diff --git a/source/hello/web.crud b/source/hello/web.crud index 9677652..4d05061 100644 --- a/source/hello/web.crud +++ b/source/hello/web.crud @@ -2,4 +2,4 @@ fn get() -> string: add("hello", "world") fn add(a: string, b: string) -> string: - a + b + a + " " + b diff --git a/src/bytecode_compiler.rs b/src/bytecode_compiler.rs index 2618b52..104751b 100644 --- a/src/bytecode_compiler.rs +++ b/src/bytecode_compiler.rs @@ -4,18 +4,27 @@ use crate::tokens::TokenType; use crate::value::Value; use crate::vm::{ OP_ADD, OP_AND, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_CHAR, - OP_DEF_DATE, OP_DEF_F32, OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, - OP_DEF_MAP, OP_DEF_STRING, OP_DEF_STRUCT, 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_OR, - OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, + OP_DEF_DATE, OP_DEF_F32, OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, + OP_DEF_STRING, OP_DEF_STRUCT, 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_OR, OP_PRINT, + OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, }; +use anyhow::anyhow; use std::collections::HashMap; -pub fn compile(ast: &Vec) -> anyhow::Result { - compile_name(ast, "/") +pub fn compile( + namespace: &str, + ast: &Vec, + registry: &mut HashMap, +) -> anyhow::Result { + compile_name(ast, namespace, registry) } -pub(crate) fn compile_function(function: &Function) -> anyhow::Result { +pub(crate) fn compile_function( + function: &Function, + registry: &mut HashMap, + namespace: &str, +) -> anyhow::Result { let mut compiler = Compiler::new(&function.name.lexeme); for parm in &function.parameters { let name = parm.name.lexeme.clone(); @@ -24,12 +33,16 @@ pub(crate) fn compile_function(function: &Function) -> anyhow::Result { compiler.emit_bytes(OP_DEFINE, name_index as u16); } - Ok(compiler.compile(&function.body)?) + Ok(compiler.compile(&function.body, registry, namespace)?) } -pub(crate) fn compile_name(ast: &Vec, name: &str) -> anyhow::Result { - let compiler = Compiler::new(name); - Ok(compiler.compile(ast)?) +pub(crate) fn compile_name( + ast: &Vec, + namespace: &str, + registry: &mut HashMap, +) -> anyhow::Result { + let compiler = Compiler::new(namespace); + Ok(compiler.compile(ast, registry, namespace)?) } struct Compiler { @@ -37,7 +50,6 @@ struct Compiler { had_error: bool, current_line: usize, vars: HashMap, - functions: HashMap, } impl Compiler { @@ -47,20 +59,39 @@ impl Compiler { had_error: false, current_line: 0, vars: HashMap::new(), - functions: HashMap::new(), } } - fn compile(mut self, ast: &Vec) -> anyhow::Result { + fn compile( + mut self, + ast: &Vec, + registry: &mut HashMap, + namespace: &str, + ) -> anyhow::Result { for statement in ast { - self.compile_statement(statement)? + if let Statement::FunctionStmt { function } = statement { + self.emit_constant(Value::String(format!( + "{}.{}", + namespace, + function.name.lexeme.clone() + ))); + } + } + + for statement in ast { + self.compile_statement(statement, registry, namespace)?; } self.emit_byte(OP_RETURN); Ok(self.chunk) } - fn compile_statement(&mut self, statement: &Statement) -> anyhow::Result<()> { + fn compile_statement( + &mut self, + statement: &Statement, + registry: &mut HashMap, + namespace: &str, + ) -> anyhow::Result<()> { self.current_line = statement.line(); match statement { Statement::VarStmt { @@ -70,39 +101,55 @@ impl Compiler { } => { let name_index = self.chunk.add_constant(Value::String(name.lexeme.clone())); self.vars.insert(name.lexeme.clone(), name_index); - self.compile_expression(initializer)?; + self.compile_expression(namespace, initializer, registry)?; self.define_variable(var_type, name_index)?; - if let Expression::List {values, .. } = initializer { + if let Expression::List { values, .. } = initializer { self.emit_byte(values.len() as u16); } } Statement::PrintStmt { value } => { - self.compile_expression(value)?; + self.compile_expression(namespace, value, registry)?; self.emit_byte(OP_PRINT); } Statement::ExpressionStmt { expression } => { - self.compile_expression(expression)?; + self.compile_expression(namespace, expression, registry)?; } Statement::FunctionStmt { function } => { let function_name = function.name.lexeme.clone(); - let name_index = self.chunk.add_constant(Value::String(function_name.clone())); - self.functions.insert(function_name, name_index); - let compiled_function = compile_function(function)?; - self.chunk.add_function(compiled_function); + self.emit_constant(Value::String(function_name.clone())); + let compiled_function = compile_function(function, registry, namespace)?; + registry.insert( + format!("{}.{}", self.chunk.name, function_name), + compiled_function, + ); } } Ok(()) } - fn compile_expression(&mut self, expression: &Expression) -> anyhow::Result<()> { + fn compile_expression( + &mut self, + namespace: &str, + expression: &Expression, + registry: &mut HashMap, + ) -> anyhow::Result<()> { match expression { Expression::FunctionCall { name, arguments, .. } => { - println!("call {}",name); - let name_index = *self.functions.get(name).unwrap(); + let name = if let None = self.chunk.find_constant(&name) { + format!("{}.{}", namespace, name) + } else { + name.clone() + }; + println!("call {}", name); + let name_index = self + .chunk + .find_constant(&name) + .unwrap_or_else(|| self.emit_constant(name.into()) as usize); + for argument in arguments { - self.compile_expression(argument)?; + self.compile_expression(namespace, argument, registry)?; } self.emit_bytes(OP_CALL, name_index as u16); self.emit_byte(arguments.len() as u16); @@ -111,18 +158,22 @@ impl Compiler { let name_index = self.vars.get(name).unwrap(); self.emit_bytes(OP_GET, *name_index as u16); } - Expression::Literal { value, .. } => self.emit_constant(value), + Expression::Literal { value, .. } => { + self.emit_constant(value.clone()); + } Expression::List { values, .. } => { for expr in values { - self.compile_expression(expr)?; + self.compile_expression(namespace, expr, registry)?; } // self.emit_bytes(OP_NEW_LIST, values.len() as u16); } - Expression::Grouping { expression, .. } => self.compile_expression(expression)?, + Expression::Grouping { expression, .. } => { + self.compile_expression(namespace, expression, registry)? + } Expression::Unary { operator, right, .. } => { - self.compile_expression(right)?; + self.compile_expression(namespace, right, registry)?; match operator.token_type { TokenType::Minus => { self.emit_byte(OP_NEGATE); @@ -139,8 +190,8 @@ impl Compiler { right, .. } => { - self.compile_expression(left)?; - self.compile_expression(right)?; + self.compile_expression(namespace, left, registry)?; + self.compile_expression(namespace, right, registry)?; match operator.token_type { TokenType::Plus => self.emit_byte(OP_ADD), TokenType::Minus => self.emit_byte(OP_SUBTRACT), @@ -196,8 +247,9 @@ impl Compiler { self.emit_byte(b2); } - fn emit_constant(&mut self, value: &Value) { - let index = self.chunk.add_constant(value.clone()); - self.emit_bytes(OP_CONSTANT, index as u16); + fn emit_constant(&mut self, value: Value) -> u16 { + let index = self.chunk.add_constant(value) as u16; + self.emit_bytes(OP_CONSTANT, index); + index } } diff --git a/src/chunk.rs b/src/chunk.rs index 87d9fc4..fc61f7a 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -1,20 +1,30 @@ -use std::collections::HashMap; use crate::value::Value; use crate::vm::{ 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_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_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, }; #[derive(Debug, Clone)] pub struct Chunk { - name: String, + pub(crate) name: String, pub code: Vec, pub constants: Vec, lines: Vec, - pub functions: HashMap, - // pub(crate) functions_by_index: Vec, +} + +impl Chunk { + pub(crate) fn find_constant(&self, p0: &String) -> Option { + for (i, constant) in self.constants.iter().enumerate() { + if let Value::String(s) = constant { + if s == p0 { + return Some(i); + } + } + } + None + } } impl Chunk { @@ -24,8 +34,6 @@ impl Chunk { code: Vec::new(), constants: vec![], lines: vec![], - functions: HashMap::new(), - // functions_by_index: Vec::new(), } } @@ -39,15 +47,7 @@ impl Chunk { self.constants.len() - 1 } - pub fn add_function(&mut self, function: Chunk) { - // self.functions_by_index.push(function.clone()); - self.functions.insert(function.name.to_string(), function); - } - pub fn disassemble(&self) { - for f in self.functions.values() { - f.disassemble(); - } println!("== {} ==", self.name); let mut offset = 0; while offset < self.code.len() { @@ -110,7 +110,10 @@ impl Chunk { fn call_inst(&self, op: &str, offset: usize) -> usize { let constant = self.code[offset + 1]; let num_args = self.code[offset + 2]; - println!("{} {}:{}({}):", op, constant, &self.constants[constant as usize], num_args); + println!( + "{} {}:{}({}):", + op, constant, &self.constants[constant as usize], num_args + ); offset + 3 } diff --git a/src/main.rs b/src/main.rs index e85e54b..d57e27c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use crudlang::scanner::scan; use crudlang::vm::interpret; use std::collections::HashMap; use std::fs; +use std::hash::Hash; use std::sync::Arc; use walkdir::WalkDir; @@ -17,6 +18,7 @@ async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let mut paths = HashMap::new(); + let mut registry = HashMap::new(); for entry in WalkDir::new("source").into_iter().filter_map(|e| e.ok()) { let path = entry.path(); if path.is_file() && path.ends_with("web.crud") { @@ -25,10 +27,13 @@ async fn main() -> anyhow::Result<()> { let tokens = scan(&source); match ast_compiler::compile(tokens) { Ok(statements) => { - let chunk = compile(&statements)?; - let path = path.strip_prefix("source")?.to_str().unwrap(); - let path = path.replace("/web.crud", ""); - paths.insert(format!("/{}", path), chunk); + let path = path + .strip_prefix("source")? + .to_str() + .unwrap() + .replace(".crud", ""); + let chunk = compile(&path, &statements, &mut registry)?; + paths.insert(path, chunk); } Err(e) => { println!("{}", e); @@ -38,16 +43,18 @@ async fn main() -> anyhow::Result<()> { println!(); } } + + let registry = Arc::new(registry); if !paths.is_empty() { let mut app = Router::new(); for (path, code) in paths.iter() { - let code = code.functions.get("get").unwrap(); - let state = Arc::new(AppState { code: code.clone() }); + let state = Arc::new(AppState { + name: format!("{}.get", path), + registry: registry.clone(), + }); println!("adding {}", path); - app = app.route(path, get(handle_get).with_state(state.clone())); - // .with_state(state); + app = app.route(&format!("/{}",path.replace("/web", "")), get(handle_get).with_state(state.clone())); } - // run our app with hyper, listening globally on port 3000 let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?; println!("listening on {}", listener.local_addr()?); axum::serve(listener, app).await?; @@ -57,11 +64,17 @@ async fn main() -> anyhow::Result<()> { #[derive(Clone)] struct AppState { - code: Chunk, + name: String, + registry: Arc>, } async fn handle_get(State(state): State>) -> Result, StatusCode> { - Ok(Json(interpret(&state.code).await.unwrap().to_string())) + Ok(Json( + interpret(&state.registry, &state.name) + .await + .unwrap() + .to_string(), + )) } // @@ -78,18 +91,19 @@ fn hello(name: string) -> string: "Hello "+name hello("sander")"#, ); - + let mut registry = HashMap::new(); match ast_compiler::compile(tokens) { Ok(statements) => { println!("{:?}", statements); - let chunk = compile(&statements)?; + let chunk = compile("", &statements, &mut registry)?; chunk.disassemble(); - println!("{}", interpret(&chunk).await?); + // println!("{}", interpret(&chunk).await?); } Err(e) => { println!("{}", e) } } + println!("{:?}", registry); Ok(()) } } diff --git a/src/value.rs b/src/value.rs index 0f67cb7..9c35942 100644 --- a/src/value.rs +++ b/src/value.rs @@ -96,6 +96,19 @@ impl Into for &str { Value::String(self.to_string()) } } + +impl From for Value { + fn from(s: String) -> Self { + Value::String(s.clone()) + } +} + +impl From<&String> for Value { + fn from(s: &String) -> Self { + Value::String(s.clone()) + } +} + impl Into for char { fn into(self) -> Value { Value::Char(self) @@ -171,8 +184,8 @@ impl Add<&Value> for &Value { (Value::U64(a), Value::U64(b)) => Ok(Value::U64(a + b)), (Value::F32(a), Value::F32(b)) => Ok(Value::F32(a + b)), (Value::F64(a), Value::F64(b)) => Ok(Value::F64(a + b)), - (Value::String(s), Value::I32(i)) => Ok(Value::String(format!("{}{}", s, i))), - (Value::String(s), Value::I64(i)) => Ok(Value::String(format!("{}{}", s, i))), + (Value::String(s), Value::I32(i)) => Ok(format!("{}{}", s, i).into()), + (Value::String(s), Value::I64(i)) => Ok(format!("{}{}", s, i).into()), (Value::String(s), Value::U32(u)) => Ok(Value::String(format!("{}{}", s, u))), (Value::String(s), Value::U64(u)) => Ok(Value::String(format!("{}{}", s, u))), (Value::String(s), Value::F32(f)) => Ok(Value::String(format!("{}{}", s, f))), diff --git a/src/vm.rs b/src/vm.rs index a721010..da86ec2 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -20,23 +20,24 @@ macro_rules! define_var { }}; } -pub struct Vm { +pub struct Vm<'a> { ip: usize, stack: Vec, local_vars: HashMap, error_occurred: bool, - arena: Bump, + registry: &'a HashMap, } -pub async fn interpret(chunk: &Chunk) -> anyhow::Result { +pub async fn interpret(registry: &HashMap, function: &str) -> anyhow::Result { + let chunk = registry.get(function).unwrap().clone(); let mut vm = Vm { ip: 0, stack: vec![], local_vars: HashMap::new(), error_occurred: false, - arena: Bump::new(), + registry, }; - vm.run(chunk, vec![]) + vm.run(&chunk, vec![]) } pub fn interpret_function(chunk: &Chunk, args: Vec) -> anyhow::Result { @@ -45,12 +46,12 @@ pub fn interpret_function(chunk: &Chunk, args: Vec) -> anyhow::Result Vm<'a> { fn run(&mut self, chunk: &Chunk, args: Vec) -> anyhow::Result { for arg in args { self.push(arg); @@ -145,16 +146,18 @@ impl Vm { } OP_CALL => { let function_name_index = self.read(chunk); - let function_name = chunk.constants[function_name_index].to_string(); - let function = chunk.functions.get(&function_name).unwrap(); - let mut args = vec![]; 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 result = interpret_function(function, args)?; + // args.reverse(); + + let function_name = chunk.constants[function_name_index].to_string(); + let function_chunk = self.registry.get(&function_name).unwrap(); + let result = interpret_function(function_chunk, args)?; self.push(result); } _ => {}