ocypode_lang/runtime/
interpreter.rs

1use bigdecimal::ToPrimitive;
2
3use super::{builtins::Builtins, environment::Environment};
4use crate::{
5    ast::*,
6    errors::{Error as OYError, ErrorKind, Result as OYResult, SpanError},
7    utils,
8};
9
10/// The interpreter. This will execute the AST of Ocypode and return the result. check the AST in `src/front/ast.rs`.
11#[derive(Debug, Default)]
12pub struct Interpreter {
13    /// The current environment.
14    environment: Environment,
15}
16
17impl Interpreter {
18    /// Creates a new interpreter.
19    pub fn new() -> Self {
20        Self {
21            environment: Environment::new(),
22        }
23    }
24
25    /// Interprets the given program. This will return the exit code of the program.
26    pub fn interpret(mut self, program: Program, argc: usize, argv: Vec<String>) -> OYResult<u8> {
27        let mut exit_code = 0;
28        // The program contains only functions. So we need to add them to the environment.
29        for function in program.0 {
30            match function {
31                Statement::Function(function) => {
32                    self.environment.add_global_function(function)?;
33                }
34                _ => unreachable!("The program only contains functions"),
35            }
36        }
37
38        // Then we need to find the main function.
39        if let Some(main_function) = self.environment.get_global_function("main") {
40            let args = vec![
41                Arg {
42                    expr: ExpressionStatement::Value(ValueExpression::Object(
43                        ObjectExpression::Int(argc.to_string().parse().unwrap(), Span::new(0, 0)),
44                    )),
45                    is_unpack: false,
46                    span: Span::new(0, 0),
47                },
48                Arg {
49                    expr: ExpressionStatement::Value(ValueExpression::Object(
50                        ObjectExpression::Array(
51                            argv.into_iter()
52                                .map(|v| {
53                                    ExpressionStatement::Value(ValueExpression::Object(
54                                        ObjectExpression::String(v, Span::new(0, 0)),
55                                    ))
56                                })
57                                .collect(),
58                            Span::new(0, 0),
59                        ),
60                    )),
61                    is_unpack: false,
62                    span: Span::new(0, 0),
63                },
64            ];
65            exit_code = match self.execute_function(main_function, args)? {
66                ObjectExpression::Int(int, span) => int
67                    .to_u8()
68                    .ok_or_else(|| OYError::new(ErrorKind::InvalidExitCode(int), span))?,
69                _ => exit_code,
70            };
71            Ok(exit_code)
72        } else {
73            Err(OYError::new(ErrorKind::MissingMainFunction, (0, 0)))
74        }
75    }
76
77    /// Executes the given function with the given arguments.
78    /// This will return the result of the function. If the function does not return anything, it will return `nil`.
79    ///
80    /// Note: The environment should contain a fream for the function (Will removed after the function is executed)
81    pub fn execute_function(
82        &mut self,
83        function: FunctionStatement,
84        args: Vec<Arg>,
85    ) -> OYResult<ObjectExpression> {
86        self.environment.new_for_function(function.params, args)?;
87        let mut result = ObjectExpression::Nil(function.span);
88        if let Some(block) = function.block {
89            for statement in block.statements {
90                if let Some(return_value) = self.execute_statement(statement)? {
91                    result = return_value;
92                    break;
93                }
94            }
95        } else {
96            unreachable!("The builtin function should call in the call expression")
97        }
98        self.environment.exit_frame();
99        Ok(result)
100    }
101
102    /// Executes the given statement.
103    /// This will return the result of the value of return statement. if there is no return statement, it will return `nil`.
104    pub fn execute_statement(
105        &mut self,
106        statement: Statement,
107    ) -> OYResult<Option<ObjectExpression>> {
108        match statement {
109            Statement::Function(function) => {
110                self.environment.add_local_function(function).map(|_| None)
111            }
112            Statement::Assignment(assign) => self.execute_assign(assign).map(|_| None),
113            Statement::Return(return_stmt) => {
114                let return_value = self.execute_expression(return_stmt.value)?;
115                Ok(Some(return_value))
116            }
117            Statement::Expression(expr) => {
118                self.execute_expression(expr)?;
119                Ok(None)
120            }
121        }
122    }
123
124    /// Executes the given assign statement.
125    /// This will execute the expr and save the varibal with the object
126    pub fn execute_assign(&mut self, assign: AssignmentStatement) -> OYResult<()> {
127        let object = self.execute_expression(assign.expression)?;
128        let assign = AssignmentStatement {
129            ident: assign.ident,
130            expression: ExpressionStatement::Value(ValueExpression::Object(object)),
131            span: assign.span,
132        };
133        self.environment.add_variable(assign)?;
134        Ok(())
135    }
136
137    /// Executes the given expression.
138    /// This will return the result of the expression.
139    pub fn execute_expression(&mut self, expr: ExpressionStatement) -> OYResult<ObjectExpression> {
140        match expr {
141            ExpressionStatement::FunctionCall(func_call) => self.execute_function_call(func_call),
142            ExpressionStatement::Value(value) => self.execute_value(value),
143        }
144    }
145
146    /// Executes the given function call.
147    /// This will return the result of the function call.
148    pub fn execute_function_call(
149        &mut self,
150        func_call: FunctionCallExpression,
151    ) -> OYResult<ObjectExpression> {
152        let function = match func_call.callable {
153            ValueExpression::Ident(ident) => {
154                let function = self.environment.take(&ident.ident, func_call.span)?;
155                match function {
156                    Statement::Assignment(assign) => match assign.expression {
157                        ExpressionStatement::Value(ValueExpression::Object(
158                            ObjectExpression::Function(function),
159                        )) => function,
160                        _ => {
161                            return Err(OYError::new(
162                                ErrorKind::NotCallable(func_call.span.span()),
163                                assign.span,
164                            ));
165                        }
166                    },
167                    Statement::Function(function) => function,
168                    _ => {
169                        return Err(OYError::new(
170                            ErrorKind::NotCallable(func_call.span.span()),
171                            function.span(),
172                        ));
173                    }
174                }
175            }
176            ValueExpression::Object(ObjectExpression::Function(anonymous_function)) => {
177                anonymous_function
178            }
179            _ => unreachable!(
180                "The function call can only be an anonymous function or a function identifier"
181            ),
182        };
183
184        let args = if func_call.args.iter().any(|arg| arg.is_unpack) {
185            utils::unpack_args(self, func_call.args)?
186        } else {
187            func_call.args
188        };
189        let args = if args.len() >= function.params.len()
190            && function.params.last().map(|p| p.is_pack).unwrap_or(false)
191        {
192            utils::pack_args(self, &function, args)?
193        } else {
194            args
195        };
196        if function.params.len() != args.len() {
197            return Err(OYError::new(
198                ErrorKind::UncorrectArguments(
199                    args.len(),
200                    function
201                        .ident
202                        .clone()
203                        .map_or_else(|| function.span.span(), |ident| ident.span.span()),
204                    function.params,
205                    function
206                        .ident
207                        .map_or_else(|| "Anonymous function".to_owned(), |ident| ident.ident),
208                ),
209                func_call.span,
210            ));
211        }
212        if function.block.is_none() {
213            Builtins::execute_builtin_funtion(
214                &function.ident.unwrap().ident,
215                func_call.span,
216                args.into_iter()
217                    .map(|arg| {
218                        let arg_span = arg.span;
219                        let mut expr = self.execute_expression(arg.expr)?;
220                        *expr.span_mut() = arg_span;
221                        Ok(expr)
222                    })
223                    .collect::<OYResult<Vec<ObjectExpression>>>()?,
224            )
225        } else {
226            self.execute_function(function, args)
227        }
228    }
229
230    /// Executes the given value.
231    /// This will return the result of the value.
232    pub fn execute_value(&mut self, value: ValueExpression) -> OYResult<ObjectExpression> {
233        match value {
234            ValueExpression::Object(ObjectExpression::Array(arr, _)) => {
235                let mut result = Vec::new();
236                for expr in arr {
237                    result.push(ExpressionStatement::Value(ValueExpression::Object(
238                        self.execute_expression(expr)?,
239                    )));
240                }
241                Ok(ObjectExpression::Array(result, Span::new(0, 0)))
242            }
243            ValueExpression::Object(obj) => Ok(obj),
244            ValueExpression::Ident(ident) => {
245                match self.environment.take(&ident.ident, ident.span)? {
246                    Statement::Assignment(assign) => self.execute_expression(assign.expression),
247                    Statement::Function(function) => Ok(ObjectExpression::Function(function)),
248                    _ => unreachable!(),
249                }
250            }
251        }
252    }
253}