cas_compiler/expr/
assign.rs1use cas_compute::numerical::{func::{Function, User}, value::Value};
2use cas_error::Error;
3use cas_parser::parser::{
4 ast::{assign::{Assign, AssignTarget}, LitSym, Param},
5 token::op::AssignOpKind,
6};
7use crate::{
8 error::OverrideBuiltinConstant,
9 item::Symbol,
10 Compile,
11 Compiler,
12 InstructionKind,
13 NewChunk,
14};
15
16fn extract_user_symbol(lit: &LitSym, symbol: Symbol) -> Result<usize, Error> {
19 symbol.index()
20 .map_err(|name| Error::new(vec![lit.span.clone()], OverrideBuiltinConstant {
21 name: name.to_string(),
22 }))
23}
24
25impl Compile for Assign {
26 fn compile(&self, compiler: &mut Compiler) -> Result<(), Error> {
27 match &self.target {
28 AssignTarget::Symbol(symbol) => {
29 match self.op.kind {
31 AssignOpKind::Assign => {
32 compiler.with_state(|state| {
33 state.top_level_assign = false;
34 }, |compiler| {
35 self.value.compile(compiler)
36 })?;
37
38 let symbol_id = compiler.resolve_user_symbol_or_insert(symbol)?;
39 compiler.add_instr(InstructionKind::StoreVar(symbol_id));
40 },
41 compound => {
42 let resolved = compiler.resolve_symbol(symbol)?;
43 compiler.add_instr_with_spans(
44 InstructionKind::LoadVar(resolved),
45 vec![symbol.span.clone()],
46 );
47
48 compiler.with_state(|state| {
49 state.top_level_assign = false;
50 }, |compiler| {
51 self.value.compile(compiler)
52 })?;
53
54 compiler.add_instr(InstructionKind::Binary(compound.into()));
55 let symbol_id = extract_user_symbol(symbol, compiler.resolve_symbol(symbol)?)?;
56 compiler.add_instr(InstructionKind::StoreVar(symbol_id));
57 }
58 }
59 },
60 AssignTarget::Index(index) => {
61 match self.op.kind {
63 AssignOpKind::Assign => {
64 self.value.compile(compiler)?;
66 },
67 compound => {
68 index.target.compile(compiler)?;
70
71 index.index.compile(compiler)?;
73
74 compiler.add_instr_with_spans(
76 InstructionKind::LoadIndexed,
77 vec![index.target.span(), index.index.span()],
78 );
79 self.value.compile(compiler)?;
80 compiler.add_instr(InstructionKind::Binary(compound.into()));
81 }
82 }
83
84 index.target.compile(compiler)?;
86
87 index.index.compile(compiler)?;
89
90 compiler.add_instr_with_spans(
91 InstructionKind::StoreIndexed,
92 vec![index.target.span(), index.index.span()],
93 );
94 },
95 AssignTarget::Func(header) => {
96 let NewChunk { id, chunk, captures } = compiler.new_chunk(header, |compiler| {
98 compiler.add_instr(InstructionKind::InitFunc(
99 header.name.to_string(),
100 header.to_string(),
101 header.params.len(),
102 header.params.iter().filter(|p| p.has_default()).count(),
103 ));
104
105 let mut iter = header.params.iter().rev().peekable();
108 while let Some(Param::Default(sym, default_expr)) =
109 iter.next_if(|p| p.has_default()) {
110 let assign_param = compiler.new_unassociated_label();
111
112 compiler.add_instr(InstructionKind::CheckExecReady);
115 compiler.add_instr(InstructionKind::JumpIfTrue(assign_param));
116
117 default_expr.compile(compiler)?;
120 compiler.add_instr(InstructionKind::NextArg);
121
122 compiler.set_end_label(assign_param);
123
124 let symbol_id = compiler.add_symbol(sym)?;
126 compiler.add_instr(InstructionKind::AssignVar(symbol_id));
127 }
128
129 compiler.add_instr(InstructionKind::ErrorIfMissingArgs);
132
133 for param in iter {
136 let symbol_id = compiler.add_symbol(param.symbol())?;
137 compiler.add_instr(InstructionKind::AssignVar(symbol_id));
138 }
139
140 self.value.compile(compiler)?;
141 compiler.add_instr(InstructionKind::Return);
142
143 Ok(())
144 })?;
145
146 let user_func = User::new(chunk, captures);
147 compiler.add_instr(InstructionKind::LoadConst(Value::Function(Function::User(user_func))));
148 compiler.add_instr(InstructionKind::StoreVar(id));
149 },
150 };
151
152 Ok(())
153 }
154}