added support for builtin functions and added some for strings
This commit is contained in:
parent
b83c4bb0cc
commit
1315b2878a
10 changed files with 198 additions and 38 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
object Person:
|
object Person:
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
fn get(path: string) -> string:
|
// fn get(path: string) -> string:
|
||||||
let p = Person(name: path)
|
// let p = Person(name: path)
|
||||||
service.add("hello", p.name)
|
// service.add("hello", p.name)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ast_compiler::Expression::{
|
use crate::ast_compiler::Expression::{
|
||||||
FieldGet, FunctionCall, ListGet, MapGet, NamedParameter, Stop, Variable,
|
FieldGet, FunctionCall, ListGet, MapGet, MethodCall, NamedParameter, Stop, Variable,
|
||||||
};
|
};
|
||||||
use crate::errors::CompilerError::{
|
use crate::errors::CompilerError::{
|
||||||
self, Expected, ParseError, TooManyParameters, UnexpectedIndent, UninitializedVariable,
|
self, Expected, ParseError, TooManyParameters, UnexpectedIndent, UninitializedVariable,
|
||||||
|
|
@ -517,7 +517,7 @@ impl AstCompiler {
|
||||||
} else if self.match_token(vec![Dot]) {
|
} else if self.match_token(vec![Dot]) {
|
||||||
let name = self.peek().clone();
|
let name = self.peek().clone();
|
||||||
self.advance();
|
self.advance();
|
||||||
self.field(expr, name)
|
self.field_or_method(expr, name, symbol_table)
|
||||||
} else {
|
} else {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
@ -557,21 +557,33 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// work in progress
|
// work in progress
|
||||||
fn field(
|
fn field_or_method(
|
||||||
&mut self,
|
&mut self,
|
||||||
_operand: Expression,
|
receiver: Expression,
|
||||||
index: Token,
|
op: Token,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
) -> Result<Expression, CompilerErrorAtLine> {
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
Ok(FieldGet {
|
if self.match_token(vec![LeftParen]) {
|
||||||
field: index.lexeme.clone(),
|
let arguments = self.arguments(symbol_table)?;
|
||||||
})
|
Ok(MethodCall {
|
||||||
|
receiver: Box::new(receiver.clone()),
|
||||||
|
method_name: op.lexeme,
|
||||||
|
arguments,
|
||||||
|
line: op.line,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// no test yet
|
||||||
|
Ok(FieldGet {
|
||||||
|
receiver: Box::new(receiver.clone()),
|
||||||
|
field: op.lexeme.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primary(
|
fn primary(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut HashMap<String, Symbol>,
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
) -> Result<Expression, CompilerErrorAtLine> {
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
debug!("primary {:?}", self.peek());
|
|
||||||
Ok(if self.match_token(vec![LeftBracket]) {
|
Ok(if self.match_token(vec![LeftBracket]) {
|
||||||
self.list(symbol_table)?
|
self.list(symbol_table)?
|
||||||
} else if self.match_token(vec![LeftBrace]) {
|
} else if self.match_token(vec![LeftBrace]) {
|
||||||
|
|
@ -755,6 +767,18 @@ impl AstCompiler {
|
||||||
name: Token,
|
name: Token,
|
||||||
symbol_table: &mut HashMap<String, Symbol>,
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
) -> Result<Expression, CompilerErrorAtLine> {
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let arguments = self.arguments(symbol_table)?;
|
||||||
|
Ok(FunctionCall {
|
||||||
|
line: self.peek().line,
|
||||||
|
name: name.lexeme.to_string(),
|
||||||
|
arguments,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arguments(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Vec<Expression>, CompilerErrorAtLine> {
|
||||||
let mut arguments = vec![];
|
let mut arguments = vec![];
|
||||||
while !self.match_token(vec![RightParen]) {
|
while !self.match_token(vec![RightParen]) {
|
||||||
if arguments.len() >= 25 {
|
if arguments.len() >= 25 {
|
||||||
|
|
@ -769,11 +793,7 @@ impl AstCompiler {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(FunctionCall {
|
Ok(arguments)
|
||||||
line: self.peek().line,
|
|
||||||
name: name.lexeme.to_string(),
|
|
||||||
arguments,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(
|
fn consume(
|
||||||
|
|
@ -919,6 +939,12 @@ pub enum Expression {
|
||||||
name: String,
|
name: String,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<Expression>,
|
||||||
},
|
},
|
||||||
|
MethodCall {
|
||||||
|
line: usize,
|
||||||
|
receiver: Box<Expression>,
|
||||||
|
method_name: String,
|
||||||
|
arguments: Vec<Expression>,
|
||||||
|
},
|
||||||
Stop {
|
Stop {
|
||||||
line: usize,
|
line: usize,
|
||||||
},
|
},
|
||||||
|
|
@ -936,6 +962,7 @@ pub enum Expression {
|
||||||
index: Box<Expression>,
|
index: Box<Expression>,
|
||||||
},
|
},
|
||||||
FieldGet {
|
FieldGet {
|
||||||
|
receiver: Box<Expression>,
|
||||||
field: String,
|
field: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -951,6 +978,7 @@ impl Expression {
|
||||||
Self::Map { line, .. } => *line,
|
Self::Map { line, .. } => *line,
|
||||||
Variable { line, .. } => *line,
|
Variable { line, .. } => *line,
|
||||||
FunctionCall { line, .. } => *line,
|
FunctionCall { line, .. } => *line,
|
||||||
|
MethodCall {line,..} => *line,
|
||||||
Stop { line } => *line,
|
Stop { line } => *line,
|
||||||
NamedParameter { line, .. } => *line,
|
NamedParameter { line, .. } => *line,
|
||||||
MapGet { .. } => 0,
|
MapGet { .. } => 0,
|
||||||
|
|
|
||||||
66
src/builtin_functions.rs
Normal file
66
src/builtin_functions.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
use crate::value::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
use crate::errors::RuntimeError;
|
||||||
|
|
||||||
|
type MethodFn = fn(Value, Vec<Value>) -> Result<Value, RuntimeError>;
|
||||||
|
type MethodMap = HashMap<String, MethodFn>;
|
||||||
|
type MethodTable = HashMap<String, MethodMap>;
|
||||||
|
|
||||||
|
const METHODS: LazyLock<MethodTable> = LazyLock::new(|| {
|
||||||
|
let mut table: MethodTable = HashMap::new();
|
||||||
|
|
||||||
|
let mut string_methods: MethodMap = HashMap::new();
|
||||||
|
string_methods.insert("len".to_string(), string_len);
|
||||||
|
string_methods.insert("to_uppercase".to_string(), string_to_uppercase);
|
||||||
|
string_methods.insert("contains".to_string(), string_contains);
|
||||||
|
string_methods.insert("reverse".to_string(), string_reverse);
|
||||||
|
|
||||||
|
table.insert("string".to_string(), string_methods);
|
||||||
|
|
||||||
|
table
|
||||||
|
});
|
||||||
|
|
||||||
|
pub fn call_builtin(
|
||||||
|
type_name: &str,
|
||||||
|
method_name: &str,
|
||||||
|
self_val: Value,
|
||||||
|
args: Vec<Value>,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
|
METHODS
|
||||||
|
.get(type_name)
|
||||||
|
.and_then(|methods| methods.get(method_name))
|
||||||
|
.ok_or_else(|| RuntimeError::FunctionNotFound(format!("{}.{}",type_name, method_name)))?
|
||||||
|
(self_val, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_len(self_val: Value, _args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
match self_val {
|
||||||
|
Value::String(s) => Ok(Value::I64(s.len() as i64)),
|
||||||
|
_ => Err(RuntimeError::ExpectedType("string".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_to_uppercase(self_val: Value, _args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
match self_val {
|
||||||
|
Value::String(s) => Ok(Value::String(s.to_uppercase())),
|
||||||
|
_ => Err(RuntimeError::ExpectedType("string".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_contains(self_val: Value, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
match (self_val, args.first()) {
|
||||||
|
(Value::String(s), Some(Value::String(pat))) => {
|
||||||
|
Ok(Value::Bool(s.contains(pat.as_str())))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::ExpectedType("string".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn string_reverse(self_val: Value, _: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
match self_val {
|
||||||
|
Value::String(s) => {
|
||||||
|
Ok(s.chars().rev().collect::<String>().into())
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::ExpectedType("string".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,12 +6,7 @@ use crate::symbol_builder::{Symbol, calculate_type, infer_type};
|
||||||
use crate::tokens::TokenType;
|
use crate::tokens::TokenType;
|
||||||
use crate::tokens::TokenType::Unknown;
|
use crate::tokens::TokenType::Unknown;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::vm::{
|
use crate::vm::{OP_ADD, OP_AND, OP_ASSIGN, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CALL_BUILTIN, OP_CONSTANT, OP_DEF_LIST, OP_DEF_MAP, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_LIST_GET, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT};
|
||||||
OP_ADD, OP_AND, OP_ASSIGN, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_LIST,
|
|
||||||
OP_DEF_MAP, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL,
|
|
||||||
OP_LIST_GET, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR,
|
|
||||||
OP_SUBTRACT,
|
|
||||||
};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
|
|
@ -193,6 +188,31 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expression::MethodCall {
|
||||||
|
receiver,
|
||||||
|
method_name,
|
||||||
|
arguments,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
self.compile_expression(namespace, receiver, symbols, registry)?;
|
||||||
|
let receiver_type = infer_type(receiver,symbols).to_string();
|
||||||
|
|
||||||
|
let type_index = self
|
||||||
|
.chunk
|
||||||
|
.find_constant(&receiver_type)
|
||||||
|
.unwrap_or_else(|| self.chunk.add_constant(Value::String(receiver_type)));
|
||||||
|
|
||||||
|
let name_index = self
|
||||||
|
.chunk
|
||||||
|
.find_constant(&method_name)
|
||||||
|
.unwrap_or_else(|| self.chunk.add_constant(Value::String(method_name.to_string())));
|
||||||
|
//TODO lookup parameters for builtin
|
||||||
|
self.get_arguments_in_order( namespace, symbols, registry, arguments, &vec![])?;
|
||||||
|
self.emit_byte(OP_CALL_BUILTIN);
|
||||||
|
self.emit_byte(name_index as u16);
|
||||||
|
self.emit_byte(type_index as u16);
|
||||||
|
self.emit_byte(arguments.len() as u16);
|
||||||
|
}
|
||||||
Expression::Variable { name, line, .. } => {
|
Expression::Variable { name, line, .. } => {
|
||||||
let name_index = self.vars.get(name);
|
let name_index = self.vars.get(name);
|
||||||
if let Some(name_index) = name_index {
|
if let Some(name_index) = name_index {
|
||||||
|
|
@ -296,7 +316,13 @@ impl Compiler {
|
||||||
if name.lexeme == parameter.name.lexeme {
|
if name.lexeme == parameter.name.lexeme {
|
||||||
let value_type = infer_type(value, symbols);
|
let value_type = infer_type(value, symbols);
|
||||||
if parameter.var_type != value_type {
|
if parameter.var_type != value_type {
|
||||||
return Err(CompilerErrorAtLine::raise(CompilerError::IncompatibleTypes(parameter.var_type.clone(), value_type), argument.line()));
|
return Err(CompilerErrorAtLine::raise(
|
||||||
|
CompilerError::IncompatibleTypes(
|
||||||
|
parameter.var_type.clone(),
|
||||||
|
value_type,
|
||||||
|
),
|
||||||
|
argument.line(),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
self.compile_expression(namespace, argument, symbols, registry)?;
|
self.compile_expression(namespace, argument, symbols, registry)?;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -258,10 +258,20 @@ date"#),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn string_reverse(){
|
fn string_reverse(){
|
||||||
// assert_eq!(run(r#""abc".reverse()"#), Ok(Value::String("cba".into())));
|
assert_eq!(run(r#""abc".reverse()"#), Ok(Value::String("cba".into())));
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_to_upper(){
|
||||||
|
assert_eq!(run(r#""abc".to_uppercase()"#), Ok(Value::String("ABC".into())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_len(){
|
||||||
|
assert_eq!(run(r#""abc".len()"#), Ok(Value::I64(3)));
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn package() {
|
// fn package() {
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ pub enum RuntimeError {
|
||||||
FunctionNotFound(String),
|
FunctionNotFound(String),
|
||||||
#[error("The number of of arguments for {0} is not correct. Should be {1}, got {2}")]
|
#[error("The number of of arguments for {0} is not correct. Should be {1}, got {2}")]
|
||||||
IllegalArgumentsException(String,usize,usize),
|
IllegalArgumentsException(String,usize,usize),
|
||||||
|
#[error("Expected {0}")]
|
||||||
|
ExpectedType(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ mod symbol_builder;
|
||||||
mod tokens;
|
mod tokens;
|
||||||
mod value;
|
mod value;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
mod builtin_functions;
|
||||||
|
|
||||||
pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, Chunk>, CrudLangError> {
|
pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, Chunk>, CrudLangError> {
|
||||||
let mut registry = HashMap::new();
|
let mut registry = HashMap::new();
|
||||||
|
|
|
||||||
17
src/main.rs
17
src/main.rs
|
|
@ -34,10 +34,10 @@ async fn main() -> Result<(), CrudLangError> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let source = args.source.unwrap_or("./source".to_string());
|
let source = args.source.unwrap_or("./source".to_string());
|
||||||
let registry = compile_sourcedir(&source)?;
|
let registry = compile_sourcedir(&source)?;
|
||||||
|
let empty = registry.is_empty();
|
||||||
|
|
||||||
|
let swap = Arc::new(ArcSwap::from(Arc::new(registry)));
|
||||||
if !registry.is_empty() {
|
if !empty {
|
||||||
let swap = Arc::new(ArcSwap::from(Arc::new(registry)));
|
|
||||||
if args.watch {
|
if args.watch {
|
||||||
crudlang::file_watch::start_watch_daemon(&source, swap.clone());
|
crudlang::file_watch::start_watch_daemon(&source, swap.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -63,12 +63,13 @@ async fn main() -> Result<(), CrudLangError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
axum::serve(listener, app).await.map_err(map_underlying())?;
|
axum::serve(listener, app).await.map_err(map_underlying())?;
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
Err(Platform(
|
println!("No source files found or compilation error");
|
||||||
"No source files found or compilation error".to_string(),
|
if args.repl {
|
||||||
))
|
crudlang::repl::start(swap.clone())?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -111,7 +112,7 @@ async fn handle_any(
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(value) => Ok(Json(value.to_string())),
|
Ok(value) => Ok(Json(value.to_string())),
|
||||||
Err(e) => {
|
Err(_) => {
|
||||||
// url checks out but function for method not found
|
// url checks out but function for method not found
|
||||||
if state.registry.load().get(&format!("{}.main", component)).is_some() {
|
if state.registry.load().get(&format!("{}.main", component)).is_some() {
|
||||||
Err(StatusCode::METHOD_NOT_ALLOWED)
|
Err(StatusCode::METHOD_NOT_ALLOWED)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ use crate::errors::CompilerError;
|
||||||
use crate::errors::CompilerError::IncompatibleTypes;
|
use crate::errors::CompilerError::IncompatibleTypes;
|
||||||
use crate::tokens::TokenType::{
|
use crate::tokens::TokenType::{
|
||||||
Bool, DateTime, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less,
|
Bool, DateTime, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less,
|
||||||
LessEqual, ListType, MapType, Minus, ObjectType, Plus, SignedInteger, StringType, U32,
|
LessEqual, ListType, MapType, Minus, ObjectType, Plus, SignedInteger, StringType, U32, U64,
|
||||||
U64, Unknown, UnsignedInteger,
|
Unknown, UnsignedInteger,
|
||||||
};
|
};
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
@ -225,6 +225,10 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
|
||||||
_ => Unknown,
|
_ => Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expression::MethodCall {
|
||||||
|
receiver,
|
||||||
|
..
|
||||||
|
} => infer_type(receiver, symbols),
|
||||||
Expression::Stop { .. } => TokenType::Unknown,
|
Expression::Stop { .. } => TokenType::Unknown,
|
||||||
// Expression::PathMatch { .. } => TokenType::Unknown,
|
// Expression::PathMatch { .. } => TokenType::Unknown,
|
||||||
Expression::NamedParameter { .. } => TokenType::Unknown,
|
Expression::NamedParameter { .. } => TokenType::Unknown,
|
||||||
|
|
|
||||||
22
src/vm.rs
22
src/vm.rs
|
|
@ -7,6 +7,7 @@ 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::builtin_functions::call_builtin;
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
ip: usize,
|
ip: usize,
|
||||||
|
|
@ -198,6 +199,26 @@ impl Vm {
|
||||||
self.push(list.get(index.cast_usize()?).cloned().unwrap())
|
self.push(list.get(index.cast_usize()?).cloned().unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OP_CALL_BUILTIN => {
|
||||||
|
let function_name_index = self.read(chunk);
|
||||||
|
let function_name = chunk.constants[function_name_index].to_string();
|
||||||
|
let function_type_index = self.read(chunk);
|
||||||
|
let receiver_type_name = chunk.constants[function_type_index].to_string();
|
||||||
|
|
||||||
|
let receiver = self.pop();
|
||||||
|
|
||||||
|
let num_args = self.read(chunk);
|
||||||
|
|
||||||
|
let mut args = vec![];
|
||||||
|
for _ in 0..num_args {
|
||||||
|
let arg = self.pop();
|
||||||
|
args.push(arg);
|
||||||
|
}
|
||||||
|
args.reverse();
|
||||||
|
|
||||||
|
let return_value = call_builtin(&receiver_type_name, &function_name, receiver, args)?;
|
||||||
|
self.push(return_value);
|
||||||
|
}
|
||||||
OP_CALL => {
|
OP_CALL => {
|
||||||
let function_name_index = self.read(chunk);
|
let function_name_index = self.read(chunk);
|
||||||
let num_args = self.read(chunk);
|
let num_args = self.read(chunk);
|
||||||
|
|
@ -346,3 +367,4 @@ pub const OP_DEF_F32: u16 = 39;
|
||||||
pub const OP_DEF_F64: u16 = 40;
|
pub const OP_DEF_F64: u16 = 40;
|
||||||
pub const OP_ASSIGN: u16 = 41;
|
pub const OP_ASSIGN: u16 = 41;
|
||||||
pub const OP_LIST_GET: u16 = 42;
|
pub const OP_LIST_GET: u16 = 42;
|
||||||
|
pub const OP_CALL_BUILTIN: u16 = 43;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue