added maps, objects

better namespace resolution
This commit is contained in:
Shautvast 2025-10-31 19:37:45 +01:00
parent 3118ce97b0
commit 0bd6048083
10 changed files with 276 additions and 86 deletions

View file

@ -1,4 +1,10 @@
use crate::tokens::TokenType::{Bang, Bool, Colon, Date, Eol, Equal, F32, F64, False, FloatingPoint, Fn, Greater, GreaterEqual, GreaterGreater, I32, I64, Identifier, If, Indent, Integer, LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus, Print, RightBracket, RightParen, SignedInteger, SingleRightArrow, Slash, Star, StringType, True, U32, U64, UnsignedInteger, Char}; use crate::tokens::TokenType::{
Bang, Bool, Char, Colon, Date, Eof, Eol, Equal, F32, F64, False, FloatingPoint, Fn, Greater,
GreaterEqual, GreaterGreater, I32, I64, Identifier, Indent, Integer, LeftBrace, LeftBracket,
LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus, Print,
RightBrace, RightBracket, RightParen, SignedInteger, SingleRightArrow, Slash, Star, StringType,
True, U32, U64, UnsignedInteger,
};
use crate::tokens::{Token, TokenType}; use crate::tokens::{Token, TokenType};
use crate::value::Value; use crate::value::Value;
use anyhow::anyhow; use anyhow::anyhow;
@ -7,7 +13,7 @@ use std::collections::HashMap;
pub fn compile(tokens: Vec<Token>) -> anyhow::Result<Vec<Statement>> { pub fn compile(tokens: Vec<Token>) -> anyhow::Result<Vec<Statement>> {
let mut compiler = AstCompiler::new(tokens); let mut compiler = AstCompiler::new(tokens);
compiler.compile_tokens(0) compiler.compile_tokens()
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -34,7 +40,7 @@ impl AstCompiler {
current: 0, current: 0,
had_error: false, had_error: false,
vars: vec![], vars: vec![],
indent: vec![], indent: vec![0],
functions: HashMap::new(), functions: HashMap::new(),
} }
} }
@ -43,17 +49,17 @@ impl AstCompiler {
self.current = 0; self.current = 0;
} }
fn compile_tokens(&mut self, expected_indent: usize) -> anyhow::Result<Vec<Statement>> { fn compile_tokens(&mut self) -> anyhow::Result<Vec<Statement>> {
self.collect_functions()?; self.collect_functions()?;
self.reset(); self.reset();
self.compile(expected_indent) self.compile()
} }
fn compile(&mut self, expected_indent: usize) -> anyhow::Result<Vec<Statement>> { fn compile(&mut self) -> anyhow::Result<Vec<Statement>> {
if !self.had_error { if !self.had_error {
let mut statements = vec![]; let mut statements = vec![];
while !self.is_at_end() { while !self.is_at_end() {
let statement = self.indent(expected_indent)?; let statement = self.indent()?;
if let Some(statement) = statement { if let Some(statement) = statement {
statements.push(statement); statements.push(statement);
} else { } else {
@ -119,7 +125,8 @@ impl AstCompiler {
Ok(()) Ok(())
} }
fn indent(&mut self, expected_indent: usize) -> anyhow::Result<Option<Statement>> { fn indent(&mut self) -> anyhow::Result<Option<Statement>> {
let expected_indent = *self.indent.last().unwrap();
// skip empty lines // skip empty lines
while self.check(Eol) { while self.check(Eol) {
self.advance(); self.advance();
@ -132,14 +139,13 @@ impl AstCompiler {
} }
if indent_on_line > expected_indent { if indent_on_line > expected_indent {
panic!( panic!(
"unexpected indent level {} vs {}", "unexpected indent level {} vs expected {}",
indent_on_line, expected_indent indent_on_line, expected_indent
); );
} else if indent_on_line < expected_indent { } else if indent_on_line < expected_indent {
self.indent.pop(); self.indent.pop();
return Ok(None); return Ok(None);
} else { } else {
self.indent.push(indent_on_line);
Ok(Some(self.declaration()?)) Ok(Some(self.declaration()?))
} }
} }
@ -149,11 +155,53 @@ impl AstCompiler {
self.function_declaration() self.function_declaration()
} else if self.match_token(vec![Let]) { } else if self.match_token(vec![Let]) {
self.let_declaration() self.let_declaration()
} else if self.match_token(vec![Object]) {
self.object_declaration()
} else { } else {
self.statement() self.statement()
} }
} }
fn object_declaration(&mut self) -> anyhow::Result<Statement> {
let type_name = self.consume(Identifier, "Expect object name.")?;
self.consume(Colon, "Expect ':' after object name.")?;
self.consume(Eol, "Expect end of line.")?;
let mut fields = vec![];
let expected_indent = self.indent.last().unwrap() + 1;
// self.indent.push(expected_indent);
let mut done = false;
while !done && !self.match_token(vec![Eof]) {
for _ in 0..expected_indent {
if self.peek().token_type == Indent {
self.advance();
} else {
done = true;
}
}
if !done {
let field_name = self.consume(Identifier, "Expect an object field name.")?;
self.consume(Colon, "Expect ':' after field name.")?;
let field_type = self.peek().token_type;
if field_type.is_type() {
self.advance();
} else {
Err(anyhow::anyhow!("Expected a type"))?
}
fields.push(Parameter {
name: field_name,
var_type: field_type,
});
}
}
self.consume(Eol, "Expect end of line.")?;
Ok(Statement::ObjectStmt {
name: type_name,
fields,
})
}
fn function_declaration(&mut self) -> anyhow::Result<Statement> { fn function_declaration(&mut self) -> anyhow::Result<Statement> {
let name_token = self.consume(Identifier, "Expect function name.")?; let name_token = self.consume(Identifier, "Expect function name.")?;
self.consume(LeftParen, "Expect '(' after function name.")?; self.consume(LeftParen, "Expect '(' after function name.")?;
@ -169,7 +217,8 @@ impl AstCompiler {
self.consume(Eol, "Expect end of line.")?; self.consume(Eol, "Expect end of line.")?;
let current_indent = self.indent.last().unwrap(); let current_indent = self.indent.last().unwrap();
let body = self.compile(current_indent + 1)?; self.indent.push(current_indent + 1);
let body = self.compile()?;
self.functions.get_mut(&name_token.lexeme).unwrap().body = body; self.functions.get_mut(&name_token.lexeme).unwrap().body = body;
@ -201,9 +250,6 @@ impl AstCompiler {
return Err(anyhow!("error at line {}: {}", name_token.line, e)); return Err(anyhow!("error at line {}: {}", name_token.line, e));
} }
}; };
// match var_type{
// U32 => U32()
// }
self.vars.push(Expression::Variable { self.vars.push(Expression::Variable {
name: name_token.lexeme.to_string(), name: name_token.lexeme.to_string(),
var_type, var_type,
@ -329,6 +375,8 @@ impl AstCompiler {
debug!("primary {:?}", self.peek()); debug!("primary {:?}", self.peek());
Ok(if self.match_token(vec![LeftBracket]) { Ok(if self.match_token(vec![LeftBracket]) {
self.list()? self.list()?
} else if self.match_token(vec![LeftBrace]) {
self.map()?
} else if self.match_token(vec![False]) { } else if self.match_token(vec![False]) {
Expression::Literal { Expression::Literal {
line: self.peek().line, line: self.peek().line,
@ -401,6 +449,27 @@ impl AstCompiler {
}) })
} }
fn map(&mut self) -> anyhow::Result<Expression> {
let mut entries = vec![];
while !self.match_token(vec![RightBrace]) {
let key = self.expression()?;
self.consume(Colon, "Expect ':' after map key.")?;
let value = self.expression()?;
entries.push((key, value));
if self.peek().token_type == TokenType::Comma {
self.advance();
} else {
self.consume(RightBrace, "Expect '}' after map.")?;
break;
}
}
Ok(Expression::Map {
entries,
literaltype: MapType,
line: self.peek().line,
})
}
fn variable_lookup(&mut self, token: &Token) -> anyhow::Result<Expression> { fn variable_lookup(&mut self, token: &Token) -> anyhow::Result<Expression> {
let (var_name, var_type) = self let (var_name, var_type) = self
.vars .vars
@ -504,7 +573,7 @@ impl AstCompiler {
} }
fn is_at_end(&self) -> bool { fn is_at_end(&self) -> bool {
self.peek().token_type == TokenType::Eof self.peek().token_type == Eof
} }
} }
@ -567,6 +636,10 @@ pub enum Statement {
FunctionStmt { FunctionStmt {
function: Function, function: Function,
}, },
ObjectStmt {
name: Token,
fields: Vec<Parameter>,
},
} }
impl Statement { impl Statement {
@ -576,6 +649,7 @@ impl Statement {
Statement::VarStmt { name, .. } => name.line, Statement::VarStmt { name, .. } => name.line,
Statement::PrintStmt { value } => value.line(), Statement::PrintStmt { value } => value.line(),
Statement::FunctionStmt { function, .. } => function.name.line, Statement::FunctionStmt { function, .. } => function.name.line,
Statement::ObjectStmt { name, .. } => name.line,
} }
} }
} }
@ -613,6 +687,11 @@ pub enum Expression {
literaltype: TokenType, literaltype: TokenType,
values: Vec<Expression>, values: Vec<Expression>,
}, },
Map {
line: usize,
literaltype: TokenType,
entries: Vec<(Expression, Expression)>,
},
Variable { Variable {
line: usize, line: usize,
name: String, name: String,
@ -634,6 +713,7 @@ impl Expression {
Self::Grouping { line, .. } => *line, Self::Grouping { line, .. } => *line,
Self::Literal { line, .. } => *line, Self::Literal { line, .. } => *line,
Self::List { line, .. } => *line, Self::List { line, .. } => *line,
Self::Map { line, .. } => *line,
Self::Variable { line, .. } => *line, Self::Variable { line, .. } => *line,
Self::FunctionCall { line, .. } => *line, Self::FunctionCall { line, .. } => *line,
} }
@ -700,6 +780,7 @@ impl Expression {
Self::Grouping { expression, .. } => expression.infer_type(), Self::Grouping { expression, .. } => expression.infer_type(),
Self::Literal { literaltype, .. } => literaltype.clone(), Self::Literal { literaltype, .. } => literaltype.clone(),
Self::List { literaltype, .. } => literaltype.clone(), Self::List { literaltype, .. } => literaltype.clone(),
Self::Map { literaltype, .. } => literaltype.clone(),
Self::Unary { Self::Unary {
right, operator, .. right, operator, ..
} => { } => {

View file

@ -12,10 +12,10 @@ use crate::vm::{
use std::collections::HashMap; use std::collections::HashMap;
pub fn compile( pub fn compile(
namespace: &str, namespace: Option<&str>,
ast: &Vec<Statement>, ast: &Vec<Statement>,
registry: &mut HashMap<String, Chunk>, registry: &mut HashMap<String, Chunk>,
) -> anyhow::Result<Chunk> { ) -> anyhow::Result<()> {
compile_name(ast, namespace, registry) compile_name(ast, namespace, registry)
} }
@ -37,11 +37,19 @@ pub(crate) fn compile_function(
pub(crate) fn compile_name( pub(crate) fn compile_name(
ast: &Vec<Statement>, ast: &Vec<Statement>,
namespace: &str, namespace: Option<&str>,
registry: &mut HashMap<String, Chunk>, registry: &mut HashMap<String, Chunk>,
) -> anyhow::Result<Chunk> { ) -> anyhow::Result<()> {
let compiler = Compiler::new(namespace); let name=namespace.unwrap_or("main");
Ok(compiler.compile(ast, registry, namespace)?) let compiler = Compiler::new(name);
let chunk = compiler.compile(ast, registry, name)?;
let qname = if let Some(namespace) = namespace{
format!("{}.{}", namespace, "main")
} else {
"main".to_string()
};
registry.insert(qname, chunk);
Ok(())
} }
struct Compiler { struct Compiler {
@ -67,6 +75,7 @@ impl Compiler {
registry: &mut HashMap<String, Chunk>, registry: &mut HashMap<String, Chunk>,
namespace: &str, namespace: &str,
) -> anyhow::Result<Chunk> { ) -> anyhow::Result<Chunk> {
//TODO can likely be removed
for statement in ast { for statement in ast {
if let Statement::FunctionStmt { function } = statement { if let Statement::FunctionStmt { function } = statement {
self.emit_constant(Value::String(format!( self.emit_constant(Value::String(format!(
@ -101,10 +110,7 @@ impl Compiler {
let name_index = self.chunk.add_constant(Value::String(name.lexeme.clone())); let name_index = self.chunk.add_constant(Value::String(name.lexeme.clone()));
self.vars.insert(name.lexeme.clone(), name_index); self.vars.insert(name.lexeme.clone(), name_index);
self.compile_expression(namespace, initializer, registry)?; self.compile_expression(namespace, initializer, registry)?;
self.define_variable(var_type, name_index)?; self.define_variable(var_type, name_index, &initializer)?;
if let Expression::List { values, .. } = initializer {
self.emit_byte(values.len() as u16);
}
} }
Statement::PrintStmt { value } => { Statement::PrintStmt { value } => {
self.compile_expression(namespace, value, registry)?; self.compile_expression(namespace, value, registry)?;
@ -122,6 +128,9 @@ impl Compiler {
compiled_function, compiled_function,
); );
} }
Statement::ObjectStmt { name, fields } => {
self.chunk.add_object_def(&name.lexeme, fields);
}
} }
Ok(()) Ok(())
} }
@ -136,15 +145,11 @@ impl Compiler {
Expression::FunctionCall { Expression::FunctionCall {
name, arguments, .. name, arguments, ..
} => { } => {
let name = if let None = self.chunk.find_constant(&name) { let qname=format!("{}.{}", namespace, name);
format!("{}.{}", namespace, name)
} else {
name.clone()
};
let name_index = self let name_index = self
.chunk .chunk
.find_constant(&name) .find_constant(&qname)
.unwrap_or_else(|| self.emit_constant(name.into()) as usize); .unwrap_or_else(|| self.emit_constant(qname.into()) as usize);
for argument in arguments { for argument in arguments {
self.compile_expression(namespace, argument, registry)?; self.compile_expression(namespace, argument, registry)?;
@ -163,7 +168,12 @@ impl Compiler {
for expr in values { for expr in values {
self.compile_expression(namespace, expr, registry)?; self.compile_expression(namespace, expr, registry)?;
} }
// self.emit_bytes(OP_NEW_LIST, values.len() as u16); }
Expression::Map { entries, .. } => {
for (key, value) in entries {
self.compile_expression(namespace, key, registry)?;
self.compile_expression(namespace, value, registry)?;
}
} }
Expression::Grouping { expression, .. } => { Expression::Grouping { expression, .. } => {
self.compile_expression(namespace, expression, registry)? self.compile_expression(namespace, expression, registry)?
@ -214,7 +224,12 @@ impl Compiler {
Ok(()) Ok(())
} }
fn define_variable(&mut self, var_type: &TokenType, name_index: usize) -> anyhow::Result<()> { fn define_variable(
&mut self,
var_type: &TokenType,
name_index: usize,
initializer: &Expression,
) -> anyhow::Result<()> {
let def_op = match var_type { let def_op = match var_type {
TokenType::I32 => OP_DEF_I32, TokenType::I32 => OP_DEF_I32,
TokenType::I64 => OP_DEF_I64, TokenType::I64 => OP_DEF_I64,
@ -233,6 +248,15 @@ impl Compiler {
}; };
self.emit_bytes(def_op, name_index as u16); self.emit_bytes(def_op, name_index as u16);
match initializer {
Expression::List { values, .. } => {
self.emit_byte(values.len() as u16);
}
Expression::Map { entries, .. } => {
self.emit_byte(entries.len() as u16);
}
_ => {}
}
Ok(()) Ok(())
} }

View file

@ -1,9 +1,11 @@
use std::collections::HashMap;
use crate::ast_compiler::Parameter;
use crate::value::Value; use crate::value::Value;
use crate::vm::{ use crate::vm::{
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32, OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32,
OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_STRING, OP_DEFINE, OP_DIVIDE, OP_EQUAL, OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_STRING, OP_DEFINE, OP_DIVIDE, OP_EQUAL,
OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT,
OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_DEF_MAP,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -12,6 +14,7 @@ pub struct Chunk {
pub code: Vec<u16>, pub code: Vec<u16>,
pub constants: Vec<Value>, pub constants: Vec<Value>,
lines: Vec<usize>, lines: Vec<usize>,
object_defs: HashMap<String, Vec<Parameter>>
} }
impl Chunk { impl Chunk {
@ -28,25 +31,30 @@ impl Chunk {
} }
impl Chunk { impl Chunk {
pub fn new(name: &str) -> Chunk { pub(crate) fn new(name: &str) -> Chunk {
Chunk { Chunk {
name: name.to_string(), name: name.to_string(),
code: Vec::new(), code: Vec::new(),
constants: vec![], constants: vec![],
lines: vec![], lines: vec![],
object_defs: HashMap::new(),
} }
} }
pub fn add(&mut self, byte: u16, line: usize) { pub(crate) fn add(&mut self, byte: u16, line: usize) {
self.code.push(byte); self.code.push(byte);
self.lines.push(line); self.lines.push(line);
} }
pub fn add_constant(&mut self, value: impl Into<Value>) -> usize { pub(crate) fn add_constant(&mut self, value: impl Into<Value>) -> usize {
self.constants.push(value.into()); self.constants.push(value.into());
self.constants.len() - 1 self.constants.len() - 1
} }
pub (crate) fn add_object_def(&mut self, name: &str, fields: &[Parameter]){
self.object_defs.insert(name.to_string(), fields.to_vec());
}
pub fn disassemble(&self) { pub fn disassemble(&self) {
println!("== {} ==", self.name); println!("== {} ==", self.name);
let mut offset = 0; let mut offset = 0;
@ -95,6 +103,7 @@ impl Chunk {
OP_CALL => self.call_inst("CALL", offset), OP_CALL => self.call_inst("CALL", offset),
OP_GET => self.constant_inst("GET", offset), OP_GET => self.constant_inst("GET", offset),
OP_DEF_LIST => self.new_inst("DEFLIST", offset), OP_DEF_LIST => self.new_inst("DEFLIST", offset),
OP_DEF_MAP => self.new_inst("DEFMAP", offset),
_ => { _ => {
println!("Unknown instruction {}", instruction); println!("Unknown instruction {}", instruction);
offset + 1 offset + 1

View file

@ -2,6 +2,8 @@
mod tests { mod tests {
use crate::compile; use crate::compile;
use crate::scanner::scan; use crate::scanner::scan;
use crate::value::Value;
use crate::vm::interpret;
#[test] #[test]
fn literal_int() { fn literal_int() {
@ -81,14 +83,54 @@ mod tests {
#[test] #[test]
fn call_fn_with_args_returns_value() { fn call_fn_with_args_returns_value() {
assert!( let r = compile(
compile( r#"
r#" fn add_hello(name: string) -> string:
fn hello(name: string) -> string:
"Hello " + name "Hello " + name
hello("world")"# add_hello("world")"#,
)
.is_ok()
); );
assert!(r.is_ok());
let result = interpret(&r.unwrap(), "main").unwrap();
assert_eq!(result, Value::String("Hello world".to_string()));
}
#[test]
fn object_definition() {
let r = compile(
r#"
object Person:
name: string"#,
);
assert!(r.is_ok());
}
// #[test]
// fn object_() {
// let r = compile(r#"
// object Person:
// name: string
//
// let p = Person{name: "Sander"}
// print p
// "#, );
// println!("{:?}", r);
// assert!(r.is_ok());
// }
#[test]
fn let_map() {
let r = compile(r#"{"name": "Dent", "age": 40 }"#);
assert!(r.is_ok());
let result = interpret(&r.unwrap(), "main").unwrap();
if let Value::Map(map) = result {
assert_eq!(
map.get(&Value::String("name".to_string())).unwrap(),
&Value::String("Dent".to_string())
);
assert_eq!(
map.get(&Value::String("age".to_string())).unwrap(),
&Value::I32(40)
);
}
} }
} }

View file

@ -21,7 +21,6 @@ pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
"or" => Some(TokenType::LogicalOr), "or" => Some(TokenType::LogicalOr),
"object" => Some(TokenType::Object), "object" => Some(TokenType::Object),
"print" => Some(TokenType::Print), "print" => Some(TokenType::Print),
"struct" => Some(TokenType::Struct),
"string" => Some(TokenType::StringType), "string" => Some(TokenType::StringType),
"true" => Some(TokenType::True), "true" => Some(TokenType::True),
"u32" => Some(TokenType::U32), "u32" => Some(TokenType::U32),

View file

@ -11,10 +11,10 @@ mod tokens;
mod value; mod value;
pub mod vm; pub mod vm;
pub fn compile(src: &str) -> anyhow::Result<chunk::Chunk> { pub fn compile(src: &str) -> anyhow::Result<HashMap<String, chunk::Chunk>> {
let tokens = scan(src)?; let tokens = scan(src)?;
let mut registry = HashMap::new(); let mut registry = HashMap::new();
let ast= ast_compiler::compile(tokens)?; let ast= ast_compiler::compile(tokens)?;
let bytecode = bytecode_compiler::compile("", &ast, &mut registry)?; bytecode_compiler::compile(None, &ast, &mut registry)?;
Ok(bytecode) Ok(registry)
} }

View file

@ -6,7 +6,7 @@ use crudlang::ast_compiler;
use crudlang::bytecode_compiler::compile; use crudlang::bytecode_compiler::compile;
use crudlang::chunk::Chunk; use crudlang::chunk::Chunk;
use crudlang::scanner::scan; use crudlang::scanner::scan;
use crudlang::vm::interpret; use crudlang::vm::{interpret, interpret_async};
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use std::hash::Hash; use std::hash::Hash;
@ -32,7 +32,7 @@ async fn main() -> anyhow::Result<()> {
.to_str() .to_str()
.unwrap() .unwrap()
.replace(".crud", ""); .replace(".crud", "");
let chunk = compile(&path, &statements, &mut registry)?; let chunk = compile(Some(&path), &statements, &mut registry)?;
paths.insert(path, chunk); paths.insert(path, chunk);
} }
Err(e) => { Err(e) => {
@ -73,7 +73,7 @@ struct AppState {
async fn handle_get(State(state): State<Arc<AppState>>) -> Result<Json<String>, StatusCode> { async fn handle_get(State(state): State<Arc<AppState>>) -> Result<Json<String>, StatusCode> {
Ok(Json( Ok(Json(
interpret(&state.registry, &state.name) interpret_async(&state.registry, &state.name)
.await .await
.unwrap() .unwrap()
.to_string(), .to_string(),

View file

@ -79,7 +79,6 @@ pub enum TokenType {
Slash, Slash,
Star, Star,
StringType, StringType,
Struct,
True, True,
U32, U32,
U64, U64,
@ -150,7 +149,6 @@ impl fmt::Display for TokenType {
TokenType::SingleRightArrow => write!(f, "->"), TokenType::SingleRightArrow => write!(f, "->"),
TokenType::Slash => write!(f, "/"), TokenType::Slash => write!(f, "/"),
TokenType::Star => write!(f, "*"), TokenType::Star => write!(f, "*"),
TokenType::Struct => write!(f, "struct"),
TokenType::True => write!(f, "true"), TokenType::True => write!(f, "true"),
TokenType::Void => write!(f, "()"), TokenType::Void => write!(f, "()"),
TokenType::While => write!(f, "while"), TokenType::While => write!(f, "while"),
@ -161,3 +159,23 @@ impl fmt::Display for TokenType {
} }
impl Eq for TokenType {} impl Eq for TokenType {}
impl TokenType {
pub(crate) fn is_type(&self) -> bool {
match self {
TokenType::I32
| TokenType::I64
| TokenType::U32
| TokenType::U64
| TokenType::F32
| TokenType::F64
| TokenType::StringType
| TokenType::Date
| TokenType::Object
| TokenType::ListType
| TokenType::MapType
| TokenType::Char => true,
_ => false,
}
}
}

View file

@ -7,34 +7,11 @@ 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};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StructDefinition { pub struct Object {
fields: Vec<String>, definition: String,
}
#[derive(Debug, Clone)]
pub struct StructValue {
definition: StructDefinition,
fields: Vec<Value>, fields: Vec<Value>,
} }
impl StructValue {
pub fn new(definition: StructDefinition) -> Self {
Self {
definition,
fields: Vec::new(),
}
}
}
impl Display for StructValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for (i, field) in self.definition.fields.iter().enumerate() {
write!(f, "{}: {}", field, self.fields[i])?;
}
Ok(())
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Value { pub enum Value {
U32(u32), U32(u32),
@ -50,7 +27,7 @@ pub enum Value {
Enum, Enum,
List(Vec<Value>), List(Vec<Value>),
Map(HashMap<Value, Value>), Map(HashMap<Value, Value>),
Struct(StructValue), ObjectType(Box<Object>),
Error(String), Error(String),
Void, Void,
} }
@ -141,15 +118,30 @@ impl Display for Value {
&Value::Char(v) => write!(f, "{}", v), &Value::Char(v) => write!(f, "{}", v),
&Value::Date(v) => write!(f, "{}", v), &Value::Date(v) => write!(f, "{}", v),
&Value::Enum => write!(f, "enum"), &Value::Enum => write!(f, "enum"),
&Value::Struct(v) => write!(f, "{}", v), &Value::ObjectType(o) => write!(f, "{}: {:?}", o.definition, o.fields),
&Value::List(v) => write!(f, "{:?}", v), &Value::List(v) => write!(f, "{:?}", v),
&Value::Map(_) => write!(f, "map"), &Value::Map(map) => to_string(f, map),
&Value::Error(v) => write!(f, "{}", v), &Value::Error(v) => write!(f, "{}", v),
&Value::Void => write!(f, "()"), &Value::Void => write!(f, "()"),
} }
} }
} }
fn to_string(f: &mut Formatter, map: &HashMap<Value, Value>) -> std::fmt::Result {
f.write_str("{")?;
let mut first = true;
for (k, v) in map {
if !first {
f.write_str(", ")?;
}
f.write_str(&k.to_string())?;
f.write_str(": ")?;
f.write_str(&v.to_string())?;
first = false;
}
f.write_str("}")
}
impl Neg for &Value { impl Neg for &Value {
type Output = anyhow::Result<Value>; type Output = anyhow::Result<Value>;

View file

@ -27,7 +27,23 @@ pub struct Vm<'a> {
registry: &'a HashMap<String, Chunk>, registry: &'a HashMap<String, Chunk>,
} }
pub async fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> anyhow::Result<Value> { pub fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> anyhow::Result<Value> {
let chunk = registry.get(function).unwrap().clone();
// for (key,value) in registry.iter() {
// println!("{}", key);
// value.disassemble();
// }
let mut vm = Vm {
ip: 0,
stack: vec![],
local_vars: HashMap::new(),
error_occurred: false,
registry,
};
vm.run(&chunk, vec![])
}
pub async fn interpret_async(registry: &HashMap<String, Chunk>, function: &str) -> anyhow::Result<Value> {
let chunk = registry.get(function).unwrap().clone(); let chunk = registry.get(function).unwrap().clone();
let mut vm = Vm { let mut vm = Vm {
ip: 0, ip: 0,
@ -135,11 +151,20 @@ impl <'a> Vm<'a> {
} }
self.local_vars.insert(name, Value::List(list)); self.local_vars.insert(name, Value::List(list));
} }
OP_DEF_MAP => define_var!(self, Map, chunk), OP_DEF_MAP => {
OP_DEF_STRUCT => define_var!(self, Struct, chunk), let name = self.read_name(chunk);
let len = self.read(chunk);
let mut map = HashMap::new();
for _ in 0..len {
let value = self.pop();
let key = self.pop();
map.insert(key,value);
}
self.local_vars.insert(name, Value::Map(map));
}
OP_GET => { OP_GET => {
let name = self.read_name(chunk); let name = self.read_name(chunk);
let value = self.local_vars.get(&name).unwrap(); let value = self.local_vars.get(&name). unwrap();
self.push(value.clone()); // not happy self.push(value.clone()); // not happy
debug!("after get {:?}", self.stack); debug!("after get {:?}", self.stack);
} }