roan_engine/interpreter/
access.rs

1use 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    /// Interpret an access expression.
10    ///
11    /// # Arguments
12    /// * `access` - [AccessExpr] expression to interpret.
13    /// * `ctx` - The context in which to interpret the access expression.
14    /// * `vm` - The virtual machine to use.
15    ///
16    /// # Returns
17    /// The result of the access expression.
18    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    /// Access a field of a value.
97    ///
98    /// # Arguments
99    /// * `value` - The [Value] to access the field of.
100    /// * `expr` - The [Expr] representing the field to access.
101    /// * `ctx` - The context in which to access the field.
102    ///
103    /// # Returns
104    /// The value of the field.
105    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}