roan_engine/interpreter/
access.rs1use crate::{context::Context, module::Module, value::Value, vm::VM};
2use anyhow::Result;
3use roan_ast::{AccessExpr, AccessKind, Expr, GetSpan};
4use roan_error::error::RoanError::{
5 PropertyNotFoundError, StaticContext, StaticMemberAccess, UndefinedFunctionError,
6};
7
8impl Module {
9 pub fn interpret_access(
19 &mut self,
20 access: AccessExpr,
21 ctx: &mut Context,
22 vm: &mut VM,
23 ) -> Result<Value> {
24 match access.access.clone() {
25 AccessKind::Field(field_expr) => {
26 let base = access.base.clone();
27
28 self.interpret_expr(&base, ctx, vm)?;
29 let base = vm.pop().unwrap();
30
31 Ok(self.access_field(base, &field_expr, ctx, vm)?)
32 }
33 AccessKind::Index(index_expr) => {
34 self.interpret_expr(&index_expr, ctx, vm)?;
35 let index = vm.pop().unwrap();
36
37 self.interpret_expr(&access.base, ctx, vm)?;
38 let base = vm.pop().unwrap();
39
40 Ok(base.access_index(index))
41 }
42 AccessKind::StaticMethod(expr) => {
43 let base = access.base.as_ref().clone();
44
45 let (struct_name, span) = match base {
46 Expr::Variable(v) => (v.ident.clone(), v.token.span.clone()),
47 _ => return Err(StaticMemberAccess(access.span()).into()),
48 };
49
50 let struct_def = self.get_struct(&struct_name, span)?;
51
52 let expr = expr.as_ref().clone();
53 match expr {
54 Expr::Call(call) => {
55 let method_name = call.callee.clone();
56 let method = struct_def.find_static_method(&method_name);
57
58 if method.is_none() {
59 return Err(UndefinedFunctionError(
60 method_name,
61 call.token.span.clone(),
62 )
63 .into());
64 }
65
66 let method = method.unwrap();
67
68 let args = call
69 .args
70 .iter()
71 .map(|arg| {
72 self.interpret_expr(arg, ctx, vm)?;
73 Ok(vm.pop().unwrap())
74 })
75 .collect::<Result<Vec<_>>>()?;
76
77 let mut def_module = ctx.query_module(&struct_def.defining_module).unwrap();
78
79 self.execute_user_defined_function(
80 method.clone(),
81 &mut def_module,
82 args,
83 ctx,
84 vm,
85 &call,
86 )?;
87
88 Ok(vm.pop().unwrap())
89 }
90 _ => return Err(StaticContext(expr.span()).into()),
91 }
92 }
93 }
94 }
95
96 pub fn access_field(
106 &mut self,
107 value: Value,
108 expr: &Expr,
109 ctx: &mut Context,
110 vm: &mut VM,
111 ) -> Result<Value> {
112 match expr {
113 Expr::Call(call) => {
114 let value_clone = value.clone();
115 if let Value::Struct(struct_def, _) = value_clone {
116 let field = struct_def.find_method(&call.callee);
117
118 if field.is_none() {
119 return Err(PropertyNotFoundError(call.callee.clone(), expr.span()).into());
120 }
121
122 let field = field.unwrap();
123 let mut args = vec![value.clone()];
124 for arg in call.args.iter() {
125 self.interpret_expr(arg, ctx, vm)?;
126 args.push(vm.pop().expect("Expected value on stack"));
127 }
128
129 let mut def_module = ctx.query_module(&struct_def.defining_module).unwrap();
130
131 self.execute_user_defined_function(
132 field.clone(),
133 &mut def_module,
134 args,
135 ctx,
136 vm,
137 call,
138 )?;
139
140 return Ok(vm.pop().expect("Expected value on stack"));
141 }
142
143 let methods = value.builtin_methods();
144 if let Some(method) = methods.get(&call.callee) {
145 let mut args = vec![value.clone()];
146 for arg in call.args.iter() {
147 self.interpret_expr(arg, ctx, vm)?;
148 args.push(vm.pop().expect("Expected value on stack"));
149 }
150
151 self.execute_native_function(method.clone(), args, vm)?;
152
153 Ok(vm.pop().expect("Expected value on stack"))
154 } else {
155 Err(PropertyNotFoundError(call.callee.clone(), expr.span()).into())
156 }
157 }
158 Expr::Variable(lit) => {
159 let name = lit.ident.clone();
160 match value {
161 Value::Struct(_, fields) => {
162 let field = fields.get(&name).ok_or_else(|| {
163 PropertyNotFoundError(name.clone(), lit.token.span.clone())
164 })?;
165
166 Ok(field.clone())
167 }
168 Value::Object(fields) => {
169 let field = fields.get(&name).ok_or_else(|| {
170 PropertyNotFoundError(name.clone(), lit.token.span.clone())
171 })?;
172
173 Ok(field.clone())
174 }
175 _ => Err(PropertyNotFoundError(name.clone(), lit.token.span.clone()).into()),
176 }
177 }
178 _ => {
179 self.interpret_expr(expr, ctx, vm)?;
180
181 let field = vm.pop().expect("Expected value on stack");
182
183 Ok(field)
184 }
185 }
186 }
187}