added global function calls, starting now()
This commit is contained in:
parent
3d0aad3de1
commit
d766ec775a
8 changed files with 121 additions and 71 deletions
20
src/builtins/globals.rs
Normal file
20
src/builtins/globals.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use crate::builtins::{FunctionMap, Signature, add};
|
||||||
|
use crate::compiler::tokens::TokenType::DateTime;
|
||||||
|
use crate::errors::RuntimeError;
|
||||||
|
use crate::value::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
pub(crate) static GLOBAL_FUNCTIONS: LazyLock<FunctionMap> = LazyLock::new(|| {
|
||||||
|
let mut global_functions: FunctionMap = HashMap::new();
|
||||||
|
let functions = &mut global_functions;
|
||||||
|
add(functions, "now", Signature::new(vec![], DateTime, now));
|
||||||
|
|
||||||
|
global_functions
|
||||||
|
});
|
||||||
|
|
||||||
|
fn now(_self_val: Value, _args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
Ok(Value::DateTime(Box::new(chrono::DateTime::from(
|
||||||
|
chrono::Utc::now(),
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mod string;
|
mod string;
|
||||||
mod list;
|
mod list;
|
||||||
|
pub(crate) mod globals;
|
||||||
|
|
||||||
use crate::builtins::string::string_functions;
|
use crate::builtins::string::string_functions;
|
||||||
use crate::errors::{CompilerError, RuntimeError};
|
use crate::errors::{CompilerError, RuntimeError};
|
||||||
|
|
@ -35,10 +36,12 @@ impl Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type FunctionFn = fn(Value, Vec<Value>) -> Result<Value, RuntimeError>;
|
pub(crate) type FunctionFn = fn(Value, Vec<Value>) -> Result<Value, RuntimeError>;
|
||||||
|
/// maps function names to the signature
|
||||||
pub(crate) type FunctionMap = HashMap<String, Signature>;
|
pub(crate) type FunctionMap = HashMap<String, Signature>;
|
||||||
|
/// maps receiver type name to a function map
|
||||||
pub(crate) type FunctionTable = HashMap<String, FunctionMap>;
|
pub(crate) type FunctionTable = HashMap<String, FunctionMap>;
|
||||||
|
|
||||||
static METHODS: LazyLock<FunctionTable> = LazyLock::new(|| {
|
static FUNCTIONS: LazyLock<FunctionTable> = LazyLock::new(|| {
|
||||||
let mut table: FunctionTable = HashMap::new();
|
let mut table: FunctionTable = HashMap::new();
|
||||||
table.insert("string".to_string(), string_functions());
|
table.insert("string".to_string(), string_functions());
|
||||||
table.insert("list".to_string(), list_functions());
|
table.insert("list".to_string(), list_functions());
|
||||||
|
|
@ -51,7 +54,7 @@ pub(crate) fn add(m: &mut FunctionMap, name: &str, method: Signature) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lookup(type_name: &str, method_name: &str) -> Result<&'static Signature, CompilerError> {
|
pub(crate) fn lookup(type_name: &str, method_name: &str) -> Result<&'static Signature, CompilerError> {
|
||||||
METHODS
|
FUNCTIONS
|
||||||
.get(type_name)
|
.get(type_name)
|
||||||
.and_then(|methods| methods.get(method_name))
|
.and_then(|methods| methods.get(method_name))
|
||||||
.ok_or_else(|| CompilerError::FunctionNotFound(format!("{}.{}", type_name, method_name)))
|
.ok_or_else(|| CompilerError::FunctionNotFound(format!("{}.{}", type_name, method_name)))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
use crate::builtins::globals::GLOBAL_FUNCTIONS;
|
||||||
use crate::builtins::lookup;
|
use crate::builtins::lookup;
|
||||||
use crate::compiler::assembly_pass::Op::{Add, And, Assign, BitAnd, BitOr, BitXor, Call, CallBuiltin, Constant, DefList, DefMap, Divide, Dup, Equal, Get, Goto, GotoIf, GotoIfNot, Greater, GreaterEqual, Less, LessEqual, ListGet, Multiply, Negate, Not, NotEqual, Or, Pop, Print, Return, Shr, Subtract};
|
use crate::compiler::assembly_pass::Op::{
|
||||||
|
Add, And, Assign, BitAnd, BitOr, BitXor, Call, CallBuiltin, Constant, DefList, DefMap, Divide,
|
||||||
|
Dup, Equal, Get, Goto, GotoIf, GotoIfNot, Greater, GreaterEqual, Less, LessEqual, ListGet,
|
||||||
|
Multiply, Negate, Not, NotEqual, Or, Pop, Print, Return, Shr, Subtract,
|
||||||
|
};
|
||||||
use crate::compiler::ast_pass::Expression::NamedParameter;
|
use crate::compiler::ast_pass::Expression::NamedParameter;
|
||||||
use crate::compiler::ast_pass::{Expression, Function, Parameter, Statement};
|
use crate::compiler::ast_pass::{Expression, Function, Parameter, Statement};
|
||||||
use crate::compiler::tokens::TokenType;
|
use crate::compiler::tokens::TokenType;
|
||||||
|
|
@ -221,7 +226,7 @@ impl AsmPass {
|
||||||
self.emit(Pop);
|
self.emit(Pop);
|
||||||
self.compile_statements(then_branch, symbols, registry, namespace)?;
|
self.compile_statements(then_branch, symbols, registry, namespace)?;
|
||||||
self.emit(Goto(0));
|
self.emit(Goto(0));
|
||||||
let goto_addr2 = self.chunk.code.len() - 1;// placeholder
|
let goto_addr2 = self.chunk.code.len() - 1; // placeholder
|
||||||
self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len());
|
self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len());
|
||||||
if else_branch.is_some() {
|
if else_branch.is_some() {
|
||||||
self.compile_statements(
|
self.compile_statements(
|
||||||
|
|
@ -231,7 +236,7 @@ impl AsmPass {
|
||||||
namespace,
|
namespace,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
self.chunk.code[goto_addr2]= Op::Goto(self.chunk.code.len());
|
self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len());
|
||||||
}
|
}
|
||||||
Statement::ForStatement {
|
Statement::ForStatement {
|
||||||
loop_var,
|
loop_var,
|
||||||
|
|
@ -291,17 +296,24 @@ impl AsmPass {
|
||||||
namespace, symbols, registry, arguments, parameters,
|
namespace, symbols, registry, arguments, parameters,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.emit(Call(name_index,arguments.len()));
|
self.emit(Call(name_index, arguments.len()));
|
||||||
}
|
}
|
||||||
// constructor function
|
// constructor function
|
||||||
Some(Symbol::Object { fields, .. }) => {
|
Some(Symbol::Object { fields, .. }) => {
|
||||||
self.get_arguments_in_order(
|
self.get_arguments_in_order(
|
||||||
namespace, symbols, registry, arguments, fields,
|
namespace, symbols, registry, arguments, fields,
|
||||||
)?;
|
)?;
|
||||||
self.emit(Call(name_index,arguments.len()));
|
self.emit(Call(name_index, arguments.len()));
|
||||||
}
|
}
|
||||||
|
// maybe global function
|
||||||
_ => {
|
_ => {
|
||||||
return Err(self.raise(CompilerError::FunctionNotFound(name.to_string())));
|
if let Some(fun) = GLOBAL_FUNCTIONS.get(name) {
|
||||||
|
self.emit(Call(name_index, fun.arity()));
|
||||||
|
} else {
|
||||||
|
return Err(
|
||||||
|
self.raise(CompilerError::FunctionNotFound(name.to_string()))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -338,11 +350,7 @@ impl AsmPass {
|
||||||
arguments,
|
arguments,
|
||||||
&signature.parameters,
|
&signature.parameters,
|
||||||
)?;
|
)?;
|
||||||
self.emit(CallBuiltin(
|
self.emit(CallBuiltin(name_index, type_index, arguments.len()));
|
||||||
name_index,
|
|
||||||
type_index,
|
|
||||||
arguments.len(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Expression::Variable { name, .. } => {
|
Expression::Variable { name, .. } => {
|
||||||
let name_index = self.vars.get(name);
|
let name_index = self.vars.get(name);
|
||||||
|
|
@ -513,7 +521,7 @@ pub enum Op {
|
||||||
Negate,
|
Negate,
|
||||||
Print,
|
Print,
|
||||||
Return,
|
Return,
|
||||||
Call(usize,usize),
|
Call(usize, usize),
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
Not,
|
Not,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,6 @@
|
||||||
use crate::compiler::ast_pass::Expression::{
|
use crate::compiler::ast_pass::Expression::{
|
||||||
Assignment, FieldGet, FunctionCall, ListGet, MapGet, MethodCall, NamedParameter, Stop, Variable,
|
Assignment, FieldGet, FunctionCall, ListGet, MapGet, MethodCall, NamedParameter, Stop, Variable,
|
||||||
};
|
};
|
||||||
use crate::errors::CompilerError::{
|
|
||||||
self, Expected, ParseError, TooManyParameters, UnexpectedIndent, UninitializedVariable,
|
|
||||||
};
|
|
||||||
use crate::errors::CompilerErrorAtLine;
|
|
||||||
use crate::symbol_builder::{Symbol, calculate_type, infer_type};
|
|
||||||
use crate::compiler::tokens::TokenType::{
|
use crate::compiler::tokens::TokenType::{
|
||||||
Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For,
|
Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For,
|
||||||
Greater, GreaterEqual, GreaterGreater, Identifier, If, In, Indent, Integer, LeftBrace,
|
Greater, GreaterEqual, GreaterGreater, Identifier, If, In, Indent, Integer, LeftBrace,
|
||||||
|
|
@ -14,8 +9,13 @@ use crate::compiler::tokens::TokenType::{
|
||||||
True, U32, U64, Unknown,
|
True, U32, U64, Unknown,
|
||||||
};
|
};
|
||||||
use crate::compiler::tokens::{Token, TokenType};
|
use crate::compiler::tokens::{Token, TokenType};
|
||||||
|
use crate::errors::CompilerError::{
|
||||||
|
self, Expected, ParseError, TooManyParameters, UnexpectedIndent, UninitializedVariable,
|
||||||
|
};
|
||||||
|
use crate::errors::CompilerErrorAtLine;
|
||||||
|
use crate::symbol_builder::{Symbol, calculate_type, infer_type};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{Expr, Stmt, SymbolTable};
|
use crate::{DATE_FORMAT_TIMEZONE, Expr, Stmt, SymbolTable};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -663,12 +663,9 @@ impl AstCompiler {
|
||||||
line: self.peek().line,
|
line: self.peek().line,
|
||||||
literaltype: DateTime,
|
literaltype: DateTime,
|
||||||
value: Value::DateTime(Box::new(
|
value: Value::DateTime(Box::new(
|
||||||
chrono::DateTime::parse_from_str(
|
chrono::DateTime::parse_from_str(&self.previous().lexeme, DATE_FORMAT_TIMEZONE)
|
||||||
&self.previous().lexeme,
|
.map_err(|_| self.raise(ParseError(self.previous().lexeme.clone())))?
|
||||||
"%Y-%m-%d %H:%M:%S%.3f %z",
|
.into(),
|
||||||
)
|
|
||||||
.map_err(|_| self.raise(ParseError(self.previous().lexeme.clone())))?
|
|
||||||
.into(),
|
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
} else if self.match_token(&[LeftParen]) {
|
} else if self.match_token(&[LeftParen]) {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::compiler::{compile, run};
|
||||||
use crate::errors::CompilerError::IllegalArgumentsException;
|
use crate::errors::CompilerError::IllegalArgumentsException;
|
||||||
use crate::errors::CompilerErrorAtLine;
|
use crate::errors::CompilerErrorAtLine;
|
||||||
use crate::errors::TipiLangError::{Compiler, Runtime};
|
|
||||||
use crate::errors::RuntimeError::{IllegalArgumentException, IndexOutOfBounds};
|
use crate::errors::RuntimeError::{IllegalArgumentException, IndexOutOfBounds};
|
||||||
|
use crate::errors::TipiLangError::{Compiler, Runtime};
|
||||||
use crate::value::{Value, string};
|
use crate::value::{Value, string};
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
use crate::compiler::{compile, run};
|
use crate::DATE_FORMAT_TIMEZONE;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn literal_int() {
|
fn literal_int() {
|
||||||
|
|
@ -241,8 +242,7 @@ m["name"]"#);
|
||||||
date"#),
|
date"#),
|
||||||
Ok(Value::DateTime(Box::new(
|
Ok(Value::DateTime(Box::new(
|
||||||
DateTime::parse_from_str(
|
DateTime::parse_from_str(
|
||||||
"2025-11-09 16:44:28.000 +0100",
|
"2025-11-09 16:44:28.000 +0100", DATE_FORMAT_TIMEZONE
|
||||||
"%Y-%m-%d %H:%M:%S%.3f %z"
|
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into()
|
.into()
|
||||||
|
|
@ -391,7 +391,7 @@ else:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn inline_comment(){
|
fn inline_comment() {
|
||||||
assert_eq!(run(r#"// this is a comment"#), Ok(Value::Void));
|
assert_eq!(run(r#"// this is a comment"#), Ok(Value::Void));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,6 +408,15 @@ sum
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn global_function_call() {
|
||||||
|
let value = run(r#"now()"#);
|
||||||
|
assert!(value.is_ok());
|
||||||
|
let value = value.unwrap();
|
||||||
|
let date_time_string = value.to_string();
|
||||||
|
assert!(DateTime::parse_from_str(&date_time_string, DATE_FORMAT_TIMEZONE).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn package() {
|
// fn package() {
|
||||||
// assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48)));
|
// assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48)));
|
||||||
|
|
|
||||||
|
|
@ -20,3 +20,4 @@ pub(crate) type Stmt = Result<Statement, CompilerErrorAtLine>;
|
||||||
pub(crate) type AsmRegistry = HashMap<String, AsmChunk>;
|
pub(crate) type AsmRegistry = HashMap<String, AsmChunk>;
|
||||||
|
|
||||||
pub const TIPI_EXT: &str = ".tp";
|
pub const TIPI_EXT: &str = ".tp";
|
||||||
|
pub const DATE_FORMAT_TIMEZONE: &str = "%Y-%m-%d %H:%M:%S%.3f %z";
|
||||||
|
|
@ -5,6 +5,7 @@ use std::collections::HashMap;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
||||||
|
use crate::DATE_FORMAT_TIMEZONE;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
|
|
@ -186,7 +187,7 @@ impl Display for Value {
|
||||||
Value::F32(v) => write!(f, "{}", v),
|
Value::F32(v) => write!(f, "{}", v),
|
||||||
Value::F64(v) => write!(f, "{}", v),
|
Value::F64(v) => write!(f, "{}", v),
|
||||||
Value::Char(v) => write!(f, "{}", v),
|
Value::Char(v) => write!(f, "{}", v),
|
||||||
Value::DateTime(v) => write!(f, "{}", v),
|
Value::DateTime(v) => write!(f, "{}", v.format(DATE_FORMAT_TIMEZONE)),
|
||||||
Value::Enum => write!(f, "enum"),
|
Value::Enum => write!(f, "enum"),
|
||||||
Value::ObjectType(o) => write!(f, "{}: {:?}", o.definition, o.fields),
|
Value::ObjectType(o) => write!(f, "{}: {:?}", o.definition, o.fields),
|
||||||
Value::List(v) => write!(f, "{:?}", v),
|
Value::List(v) => write!(f, "{:?}", v),
|
||||||
|
|
|
||||||
85
src/vm.rs
85
src/vm.rs
|
|
@ -1,12 +1,13 @@
|
||||||
|
use crate::AsmRegistry;
|
||||||
|
use crate::builtins::globals::GLOBAL_FUNCTIONS;
|
||||||
use crate::compiler::assembly_pass::{AsmChunk, Op};
|
use crate::compiler::assembly_pass::{AsmChunk, Op};
|
||||||
|
use crate::compiler::tokens::TokenType;
|
||||||
use crate::errors::{RuntimeError, ValueError};
|
use crate::errors::{RuntimeError, ValueError};
|
||||||
use crate::value::{Object, Value};
|
use crate::value::{Object, Value};
|
||||||
use crate::{AsmRegistry};
|
|
||||||
use arc_swap::Guard;
|
use arc_swap::Guard;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use crate::compiler::tokens::TokenType;
|
|
||||||
|
|
||||||
pub async fn interpret_async(
|
pub async fn interpret_async(
|
||||||
registry: Guard<Arc<HashMap<String, AsmChunk>>>,
|
registry: Guard<Arc<HashMap<String, AsmChunk>>>,
|
||||||
|
|
@ -60,7 +61,11 @@ impl Vm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_function(&mut self, chunk: &AsmChunk, mut args: Vec<Value>) -> Result<Value, RuntimeError> {
|
fn run_function(
|
||||||
|
&mut self,
|
||||||
|
chunk: &AsmChunk,
|
||||||
|
mut args: Vec<Value>,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
// arguments -> locals
|
// arguments -> locals
|
||||||
for (_, name) in chunk.vars.iter() {
|
for (_, name) in chunk.vars.iter() {
|
||||||
self.local_vars.insert(name.clone(), args.remove(0));
|
self.local_vars.insert(name.clone(), args.remove(0));
|
||||||
|
|
@ -130,7 +135,7 @@ impl Vm {
|
||||||
list.reverse();
|
list.reverse();
|
||||||
self.push(Value::List(list));
|
self.push(Value::List(list));
|
||||||
}
|
}
|
||||||
Op::Assign(var_index) =>{
|
Op::Assign(var_index) => {
|
||||||
let (var_type, name) = chunk.vars.get(*var_index).unwrap();
|
let (var_type, name) = chunk.vars.get(*var_index).unwrap();
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
let value = number(var_type, value)?;
|
let value = number(var_type, value)?;
|
||||||
|
|
@ -172,7 +177,9 @@ impl Vm {
|
||||||
crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?;
|
crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?;
|
||||||
self.push(return_value);
|
self.push(return_value);
|
||||||
}
|
}
|
||||||
Op::Pop => {self.pop();}
|
Op::Pop => {
|
||||||
|
self.pop();
|
||||||
|
}
|
||||||
Op::Call(function_name_index, num_args) => {
|
Op::Call(function_name_index, num_args) => {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
for _ in 0..*num_args {
|
for _ in 0..*num_args {
|
||||||
|
|
@ -182,38 +189,42 @@ impl Vm {
|
||||||
args.reverse();
|
args.reverse();
|
||||||
|
|
||||||
let function_name = chunk.constants[*function_name_index].to_string();
|
let function_name = chunk.constants[*function_name_index].to_string();
|
||||||
let function_chunk = self
|
if let Some(fun) = GLOBAL_FUNCTIONS.get(&function_name) {
|
||||||
.registry
|
let return_value = (fun.function)(Value::Void, args)?;
|
||||||
.get(&function_name)
|
self.push(return_value);
|
||||||
.or_else(|| self.registry.get(&format!("{}/{}", context, function_name)));
|
|
||||||
|
|
||||||
if function_chunk.is_none() {
|
|
||||||
let constructor = chunk.object_defs.get(&function_name);
|
|
||||||
|
|
||||||
if let Some(params) = constructor {
|
|
||||||
if params.len() != args.len() {
|
|
||||||
return Err(RuntimeError::IllegalArgumentsException(
|
|
||||||
function_name,
|
|
||||||
params.len(),
|
|
||||||
args.len(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut fields = vec![];
|
|
||||||
params.iter().zip(args).for_each(|(param, arg)| {
|
|
||||||
fields.push((param.name.lexeme.clone(), arg))
|
|
||||||
});
|
|
||||||
let new_instance = Value::ObjectType(Box::new(Object {
|
|
||||||
definition: function_name,
|
|
||||||
fields,
|
|
||||||
}));
|
|
||||||
self.push(new_instance);
|
|
||||||
} else {
|
|
||||||
return Err(RuntimeError::FunctionNotFound(function_name));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let result = interpret_function(function_chunk.unwrap(), args)?;
|
let function_chunk = self.registry.get(&function_name).or_else(|| {
|
||||||
self.push(result);
|
self.registry.get(&format!("{}/{}", context, function_name))
|
||||||
|
});
|
||||||
|
|
||||||
|
if function_chunk.is_none() {
|
||||||
|
let constructor = chunk.object_defs.get(&function_name);
|
||||||
|
|
||||||
|
if let Some(params) = constructor {
|
||||||
|
if params.len() != args.len() {
|
||||||
|
return Err(RuntimeError::IllegalArgumentsException(
|
||||||
|
function_name,
|
||||||
|
params.len(),
|
||||||
|
args.len(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut fields = vec![];
|
||||||
|
params.iter().zip(args).for_each(|(param, arg)| {
|
||||||
|
fields.push((param.name.lexeme.clone(), arg))
|
||||||
|
});
|
||||||
|
let new_instance = Value::ObjectType(Box::new(Object {
|
||||||
|
definition: function_name,
|
||||||
|
fields,
|
||||||
|
}));
|
||||||
|
self.push(new_instance);
|
||||||
|
} else {
|
||||||
|
return Err(RuntimeError::FunctionNotFound(function_name));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let result = interpret_function(function_chunk.unwrap(), args)?;
|
||||||
|
self.push(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::GotoIfNot(goto_addr) => {
|
Op::GotoIfNot(goto_addr) => {
|
||||||
|
|
@ -231,7 +242,7 @@ impl Vm {
|
||||||
Op::Goto(goto_addr) => {
|
Op::Goto(goto_addr) => {
|
||||||
self.ip = *goto_addr;
|
self.ip = *goto_addr;
|
||||||
}
|
}
|
||||||
Op::Dup =>{
|
Op::Dup => {
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
self.push(value.clone());
|
self.push(value.clone());
|
||||||
self.push(value);
|
self.push(value);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue