use crate::ast_compiler::{Expression, Function, Statement}; use crate::chunk::Chunk; 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_U32}; use std::collections::HashMap; use crate::errors::CompilerError; pub fn compile( namespace: Option<&str>, ast: &Vec, registry: &mut HashMap, ) -> Result<(),CompilerError> { compile_name(ast, namespace, registry) } pub(crate) fn compile_function( function: &Function, registry: &mut HashMap, namespace: &str, ) -> Result { let mut compiler = Compiler::new(&function.name.lexeme); for parm in &function.parameters { let name = parm.name.lexeme.clone(); let name_index = compiler.chunk.add_constant(Value::String(name.clone())); compiler.vars.insert(name, name_index); compiler.emit_bytes(OP_DEFINE, name_index as u16); } Ok(compiler.compile(&function.body, registry, namespace)?) } pub(crate) fn compile_name( ast: &Vec, namespace: Option<&str>, registry: &mut HashMap, ) -> Result<(),CompilerError> { let name=namespace.unwrap_or("main"); 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 { chunk: Chunk, _had_error: bool, current_line: usize, vars: HashMap, } impl Compiler { fn new(name: &str) -> Self { Self { chunk: Chunk::new(name), _had_error: false, current_line: 0, vars: HashMap::new(), } } fn compile( mut self, ast: &Vec, registry: &mut HashMap, namespace: &str, ) -> Result { //TODO can likely be removed for statement in ast { 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, registry: &mut HashMap, namespace: &str, ) -> Result<(), CompilerError> { self.current_line = statement.line(); match statement { Statement::VarStmt { name, var_type, initializer, } => { let name_index = self.chunk.add_constant(Value::String(name.lexeme.clone())); self.vars.insert(name.lexeme.clone(), name_index); self.compile_expression(namespace, initializer, registry)?; self.define_variable(var_type, name_index, &initializer)?; } Statement::PrintStmt { value } => { self.compile_expression(namespace, value, registry)?; self.emit_byte(OP_PRINT); } Statement::ExpressionStmt { expression } => { self.compile_expression(namespace, expression, registry)?; } Statement::FunctionStmt { function } => { let function_name = function.name.lexeme.clone(); 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, ); } Statement::ObjectStmt { name, fields } => { self.chunk.add_object_def(&name.lexeme, fields); } } Ok(()) } fn compile_expression( &mut self, namespace: &str, expression: &Expression, registry: &mut HashMap, ) -> Result<(), CompilerError> { match expression { Expression::FunctionCall { name, arguments, .. } => { let qname=format!("{}.{}", namespace, name); let name_index = self .chunk .find_constant(&qname) .unwrap_or_else(|| self.emit_constant(qname.into()) as usize); for argument in arguments { self.compile_expression(namespace, argument, registry)?; } self.emit_bytes(OP_CALL, name_index as u16); self.emit_byte(arguments.len() as u16); } Expression::Variable { name, .. } => { let name_index = self.vars.get(name).unwrap(); self.emit_bytes(OP_GET, *name_index as u16); } Expression::Literal { value, .. } => { self.emit_constant(value.clone()); } Expression::List { values, .. } => { for expr in values { self.compile_expression(namespace, expr, registry)?; } } Expression::Map { entries, .. } => { for (key, value) in entries { self.compile_expression(namespace, key, registry)?; self.compile_expression(namespace, value, registry)?; } } Expression::Grouping { expression, .. } => { self.compile_expression(namespace, expression, registry)? } Expression::Unary { operator, right, .. } => { self.compile_expression(namespace, right, registry)?; match operator.token_type { TokenType::Minus => { self.emit_byte(OP_NEGATE); } TokenType::Bang => { self.emit_byte(OP_NOT); } _ => unimplemented!("unary other than ! and -"), } } Expression::Binary { left, operator, 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), TokenType::Star => self.emit_byte(OP_MULTIPLY), TokenType::Slash => self.emit_byte(OP_DIVIDE), TokenType::BitAnd => self.emit_byte(OP_BITAND), TokenType::BitOr => self.emit_byte(OP_BITOR), TokenType::BitXor => self.emit_byte(OP_BITXOR), TokenType::GreaterGreater => self.emit_byte(OP_SHR), TokenType::LessLess => self.emit_byte(OP_SHL), TokenType::EqualEqual => self.emit_byte(OP_EQUAL), TokenType::Greater => self.emit_byte(OP_GREATER), TokenType::GreaterEqual => self.emit_byte(OP_GREATER_EQUAL), TokenType::Less => self.emit_byte(OP_LESS), TokenType::LessEqual => self.emit_byte(OP_LESS_EQUAL), TokenType::LogicalAnd => self.emit_byte(OP_AND), TokenType::LogicalOr => self.emit_byte(OP_OR), _ => unimplemented!("binary other than plus, minus, star, slash"), } } } Ok(()) } fn define_variable( &mut self, var_type: &TokenType, name_index: usize, initializer: &Expression, ) -> Result<(), CompilerError> { let def_op = match var_type { TokenType::I32 => OP_DEF_I32, TokenType::I64 => OP_DEF_I64, TokenType::U32 => OP_DEF_U32, TokenType::U64 => OP_DEF_I64, TokenType::F32 => OP_DEF_F32, TokenType::F64 => OP_DEF_F64, TokenType::Date => OP_DEF_DATE, TokenType::StringType => OP_DEF_STRING, TokenType::Char => OP_DEF_CHAR, TokenType::Bool => OP_DEF_BOOL, TokenType::ListType => OP_DEF_LIST, TokenType::MapType => OP_DEF_MAP, TokenType::Object => OP_DEF_STRUCT, _ => unimplemented!("{}", var_type), }; 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(()) } fn emit_byte(&mut self, byte: u16) { self.chunk.add(byte, self.current_line); } fn emit_bytes(&mut self, b1: u16, b2: u16) { self.emit_byte(b1); self.emit_byte(b2); } fn emit_constant(&mut self, value: Value) -> u16 { let index = self.chunk.add_constant(value) as u16; self.emit_bytes(OP_CONSTANT, index); index } }