microcad_lang/eval/statements/
assignment_statement.rs1use crate::eval::*;
5use crate::value::*;
6
7impl Assignment {
8 pub fn type_check(&self, found: Type) -> EvalResult<()> {
10 if let Some(ty) = &self.specified_type {
11 if ty.ty() != found {
12 return Err(EvalError::TypeMismatch {
13 id: self.id.clone(),
14 expected: ty.ty(),
15 found,
16 });
17 }
18 }
19
20 Ok(())
21 }
22}
23
24impl Eval<()> for AssignmentStatement {
25 fn eval(&self, context: &mut Context) -> EvalResult<()> {
26 log::debug!("Evaluating assignment statement:\n{self}");
27 context.grant(self)?;
28
29 let assignment = &self.assignment;
30
31 let new_value: Value = assignment.expression.eval(context)?;
33 if let Err(err) = assignment.type_check(new_value.ty()) {
34 context.error(self, err)?;
35 return Ok(());
36 }
37
38 let new_value = match new_value {
40 Value::Model(model) => {
41 let attributes = self.attribute_list.eval(context)?;
42 model.borrow_mut().attributes = attributes.clone();
43 Value::Model(model)
44 }
45 value => {
46 if !self.attribute_list.is_empty() {
48 context.error(
49 &self.attribute_list,
50 AttributeError::CannotAssignAttribute(
51 self.assignment.expression.clone().into(),
52 ),
53 )?;
54 }
55 value
56 }
57 };
58
59 if let Ok(symbol) = context.lookup(&QualifiedName::from_id(assignment.id.clone())) {
61 let err = match &mut symbol.borrow_mut().def {
62 SymbolDefinition::Constant(_, identifier, value) => {
63 if value.is_invalid() {
64 *value = new_value.clone();
65 None
66 } else {
67 Some((
68 assignment.id.clone(),
69 EvalError::ValueAlreadyInitialized(
70 identifier.clone(),
71 value.clone(),
72 identifier.src_ref(),
73 ),
74 ))
75 }
76 }
77 _ => Some((
78 assignment.id.clone(),
79 EvalError::NotAnLValue(assignment.id.clone()),
80 )),
81 };
82 if let Some((id, err)) = err {
84 context.error(&id, err)?;
85 }
86 }
87
88 match assignment.qualifier {
90 Qualifier::Const => {
91 if context.get_property(&assignment.id).is_ok() {
92 todo!("property with that name exists")
93 }
94
95 let symbol = context.lookup(&assignment.id.clone().into());
96 match symbol {
97 Ok(symbol) => {
98 if let Err(err) = symbol.set_value(new_value) {
99 context.error(self, err)?
100 }
101 }
102 Err(err) => context.error(self, err)?,
103 }
104 }
105 Qualifier::Value => {
106 let result = if context.get_property(&assignment.id).is_ok() {
107 if context.is_init() {
108 context.init_property(assignment.id.clone(), new_value)
109 } else {
110 todo!("property with that name exists")
111 }
112 } else {
113 context.set_local_value(assignment.id.clone(), new_value)
114 };
115 if let Err(err) = result {
116 context.error(self, err)?;
117 }
118 }
119 Qualifier::Prop => {
120 if context.get_local_value(&assignment.id).is_ok() {
121 todo!("local value with that name exists")
122 }
123 if let Err(err) = context.init_property(assignment.id.clone(), new_value) {
124 context.error(self, err)?;
125 }
126 }
127 };
128
129 Ok(())
130 }
131}