diff --git a/reid_src/test.reid b/reid_src/test.reid index 3ed449c..5fbe3b8 100644 --- a/reid_src/test.reid +++ b/reid_src/test.reid @@ -1 +1,3 @@ -print(); \ No newline at end of file +let otus = "Hello, world!"; +let dotus = otus; +print(dotus); \ No newline at end of file diff --git a/src/compiler.rs b/src/compiler.rs index 3039581..0e3e5d1 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -2,9 +2,10 @@ use std::collections::HashMap; use super::errors::CompilerError; use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, Statement}; -use super::vm::VariableType; +use super::vm::{BuiltinFunctionDef, FunctionDef, FunctionSignature, VariableType}; type Variable = (HeapID, VariableType); +pub type FuncID = usize; pub type HeapID = usize; pub type RegID = usize; @@ -18,6 +19,7 @@ pub enum Command { AssignVariable(HeapID, RegID), // Assign variable from registery at RegID VarToReg(HeapID, RegID), // Bring Variable to registery at RegID StringLit(String), // Bring String Literal to Stack + FunctionCall(FuncID), // Call Function at FuncID } pub struct Compiler { @@ -40,11 +42,22 @@ impl Compiler { } } + pub fn with_builtin_functions>>(mut self, list: T) -> Compiler { + self.add_builtin_functions(list.into()); + self + } + pub fn compile(mut self) -> Result { self.handle_expression(self.parsed.0.clone())?; Ok(CompiledReid { list: self.list }) } + pub fn add_builtin_functions>>(&mut self, list: T) { + for func in list.into() { + self.root_scope.add_builtin_function(func); + } + } + fn handle_expression( &mut self, exp: Expression, @@ -62,7 +75,26 @@ impl Compiler { self.list.push(Command::EndScope); Ok(None) } - Expression::FunctionCall(..) => Err(CompilerError::Fatal), + Expression::FunctionCall(pos, name, args) => { + let mut arguments = Vec::new(); + + for expr in args { + if let Some(vtype) = self.handle_expression(expr)? { + arguments.push(vtype); + } else { + return Err(CompilerError::CanNotAssignVoidType); + } + } + if let Some(func) = self + .root_scope + .find_function(&FunctionSignature::new(name.clone(), arguments.clone())) + { + self.list.push(Command::FunctionCall(func.0)); + Ok(None) + } else { + Err(CompilerError::FunctionNotFound(pos, name, arguments)) + } + } Expression::ValueRef(_, val) => match val { Pattern::IdentPattern(pos, ident) => { if let Some(var) = self.root_scope.get(ident.clone()) { @@ -123,6 +155,7 @@ impl Compiler { pub struct Scope { counter: HeapID, variables: HashMap, + functions: Vec, inner_scope: Option>, } @@ -141,6 +174,25 @@ impl Scope { } } + fn find_function(&self, signature: &FunctionSignature) -> Option<(usize, &FunctionSignature)> { + let mut found = None; + for (idx, func) in self.functions.iter().enumerate() { + if func == signature { + found = Some((idx, func)); + } + } + found + } + + fn add_builtin_function(&mut self, function: FunctionSignature) -> bool { + if self.find_function(&function).is_some() { + false + } else { + self.functions.push(function); + true + } + } + fn add_var( &mut self, pos: Position, diff --git a/src/errors.rs b/src/errors.rs index 2008982..339971e 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -3,6 +3,8 @@ use std::fmt; use std::fmt::Display; use std::io; +use super::vm::VariableType; + #[derive(Debug)] pub enum GenericError { StdIOError(io::Error), @@ -64,6 +66,7 @@ pub enum CompilerError { InvalidScopeExit(Position), LetFailed(Position, Box), CanNotAssignVoidType, + FunctionNotFound(Position, String, Vec), } impl CompilerError { @@ -92,12 +95,35 @@ impl Display for CompilerError { CompilerError::LetFailed(pos, error) => { format!("Let statement failed at {}:\n {}", pos, error) } - CompilerError::CanNotAssignVoidType => format!("Can not assign void type to variable"), + CompilerError::CanNotAssignVoidType => format!("Can not assign void type here"), + CompilerError::FunctionNotFound(pos, name, params) => format!( + "Function with signature {}{} not found at {}", + name, + ParamList(params.clone()), + pos + ), }; write!(f, "{}", text) } } +struct ParamList(Vec); + +impl Display for ParamList { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut text = String::new(); + text += "("; + for (idx, vtype) in self.0.iter().enumerate() { + if idx > 0 { + text += ", "; + } + text += &vtype.to_string(); + } + text += ")"; + write!(f, "{}", text) + } +} + #[derive(Debug)] pub enum RuntimePanic { Fatal, @@ -109,4 +135,5 @@ pub enum RuntimePanic { InvalidHeapAddress, ValueNotInitialized, InvalidTypeAssign, + InvalidFuncAddress, } diff --git a/src/main.rs b/src/main.rs index 8e1e3e9..278d6d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use std::path::Path; use compiler::Compiler; use parser::Parser; -use vm::VirtualMachine; +use vm::{BuiltinFunctionDef, BuiltinFunctions, Value, VariableType, VirtualMachine}; fn main() { let path = Path::new("reid_src/test.reid"); @@ -20,15 +20,29 @@ fn main() { eprintln!("Syntax error: {}", error); std::process::exit(1); } - dbg!(&parsed); - let compiled = Compiler::from(parsed.unwrap()).compile(); + //dbg!(&parsed); + + let print = BuiltinFunctionDef::new( + "print", + vec![VariableType::TypeString], + Box::new(move |args| { + let Value::StringVal(string) = &args[0]; + println!("{}", string); + }), + ); + let builtin_functions = BuiltinFunctions(vec![print]); + + let compiled = Compiler::from(parsed.unwrap()) + .with_builtin_functions(builtin_functions.signatures()) + .compile(); if let Err(error) = compiled { eprintln!("Compilation error: {}", error); std::process::exit(1); } - dbg!(&compiled); + //dbg!(&compiled); let mut vm = VirtualMachine::from(compiled.unwrap()); + vm.add_builtin_functions(builtin_functions); if let Err(error) = vm.run() { eprintln!("Runtime panic: {:#?}", error); std::process::exit(1); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 921a328..eb09bd3 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -257,10 +257,6 @@ impl<'a> Expect<'a> { other, ) } - - fn get_expect>(&mut self, expectable: Expectable) -> Expect { - self.parser.expect(expectable) - } } pub struct Expects<'a> { diff --git a/src/parser/parsed_reid.rs b/src/parser/parsed_reid.rs index d8f8021..ebd897e 100644 --- a/src/parser/parsed_reid.rs +++ b/src/parser/parsed_reid.rs @@ -74,6 +74,7 @@ impl Expression { Err(SyntaxError::ExpectedToken(parser.pos(), '}')) } } else if let Some(texts) = parser.expect_ident().and(Expectable::Static("(")).get() { + let pos = parser.pos(); let name = texts.get(0).unwrap(); let mut arg_list = Vec::new(); while { @@ -95,7 +96,6 @@ impl Expression { } } } {} - let pos = parser.pos(); parser .expect_static(")") .get_or(SyntaxError::ExpectedToken(pos, ')'))?; diff --git a/src/vm/functions.rs b/src/vm/functions.rs new file mode 100644 index 0000000..615e319 --- /dev/null +++ b/src/vm/functions.rs @@ -0,0 +1,101 @@ +use super::{Value, VariableType}; + +#[derive(Debug, Clone)] +pub struct FunctionSignature { + pub name: String, + pub parameters: Vec, +} + +impl FunctionSignature { + pub fn new>(name: T, params: Vec) -> FunctionSignature { + FunctionSignature { + name: name.into(), + parameters: params, + } + } +} + +impl PartialEq for FunctionSignature { + fn eq(&self, other: &FunctionSignature) -> bool { + if self.name == other.name && self.parameters.len() == other.parameters.len() { + let mut found_difference = false; + for (idx, t) in self.parameters.iter().enumerate() { + if other.parameters[idx] != *t { + found_difference = true; + } + } + !found_difference + } else { + false + } + } +} + +impl From for FunctionSignature { + fn from(from: BuiltinFunctionDef) -> FunctionSignature { + from.signature + } +} + +pub enum FunctionDef { + Builtin(BuiltinFunctionDef), +} + +impl FunctionDef { + fn get_signature(&self) -> &FunctionSignature { + match self { + FunctionDef::Builtin(func) => &func.signature, + } + } +} + +impl PartialEq for FunctionDef { + fn eq(&self, other: &FunctionDef) -> bool { + self.get_signature() == other.get_signature() + } +} + +impl PartialEq for FunctionDef { + fn eq(&self, other: &FunctionSignature) -> bool { + self.get_signature() == other + } +} + +pub struct BuiltinFunctionDef { + pub signature: FunctionSignature, + pub function: Box)>, +} + +impl BuiltinFunctionDef { + pub fn new>( + name: T, + parameters: Vec, + func: Box)>, + ) -> BuiltinFunctionDef { + BuiltinFunctionDef { + signature: FunctionSignature { + name: name.into(), + parameters, + }, + function: func, + } + } +} + +pub struct BuiltinFunctions(pub Vec); + +impl BuiltinFunctions { + pub fn signatures(&self) -> Vec { + let mut signatures = Vec::new(); + for func in &self.0 { + signatures.push(func.signature.clone()); + } + signatures + } +} + +impl From for Vec { + fn from(builtin: BuiltinFunctions) -> Self { + builtin.0 + } +} diff --git a/src/vm.rs b/src/vm/mod.rs similarity index 71% rename from src/vm.rs rename to src/vm/mod.rs index 689082d..91d1fca 100644 --- a/src/vm.rs +++ b/src/vm/mod.rs @@ -1,14 +1,21 @@ +pub mod functions; + use std::collections::HashMap; +use std::fmt; +use std::fmt::Display; use super::compiler::{Command, CompiledReid, HeapID}; use super::errors::RuntimePanic; +pub use functions::*; + pub struct VirtualMachine { registry_stack: Vec<[Option; 8]>, registry: [Option; 8], stack: Vec, heap: HashMap, + functions: Vec, position: usize, compiled: CompiledReid, @@ -22,12 +29,19 @@ impl VirtualMachine { stack: Vec::new(), heap: HashMap::new(), + functions: Vec::new(), position: 0, compiled, } } + pub fn add_builtin_functions>>(&mut self, list: T) { + for func in list.into() { + self.functions.push(FunctionDef::Builtin(func)); + } + } + pub fn run(&mut self) -> Result<(), RuntimePanic> { let mut error = None; while error.is_none() { @@ -60,19 +74,19 @@ impl VirtualMachine { match command { Command::InitializeVariable(heapid, vtype) => { self.heap.insert(heapid, AllocatedVar(vtype, None)); - dbg!("Initialized new variable to heap", &self.heap); + //dbg!("Initialized new variable to heap", &self.heap); Ok(()) } Command::BeginScope => { self.registry_stack.push(self.registry.clone()); self.registry = Default::default(); - dbg!("Begun new scope"); + //dbg!("Begun new scope"); Ok(()) } Command::EndScope => { if let Some(reg) = self.registry_stack.pop() { self.registry = reg; - dbg!("Scope ended"); + //dbg!("Scope ended"); Ok(()) } else { Err(RuntimePanic::ScopeStackUnderflow) @@ -81,7 +95,7 @@ impl VirtualMachine { Command::Pop(regid) => { if let Some(val) = self.stack.pop() { self.registry[regid] = Some(val); - dbg!("Registry popped", regid, &self.stack, &self.registry); + //dbg!("Registry popped", regid, &self.stack, &self.registry); Ok(()) } else { Err(RuntimePanic::StackUnderflow) @@ -91,7 +105,7 @@ impl VirtualMachine { if let Some(reg) = &self.registry[regid] { if self.stack.len() < usize::MAX { self.stack.push(reg.clone()); - dbg!("Registry pushed", regid, &self.stack); + //dbg!("Registry pushed", regid, &self.stack); Ok(()) } else { Err(RuntimePanic::StackOverflow) @@ -104,7 +118,7 @@ impl VirtualMachine { if let Some(reg) = &self.registry[regid] { if let Some(var) = self.heap.get_mut(&heapid) { var.try_set(Some(reg.clone()))?; - dbg!("Variable assigned", heapid, regid, &self.heap); + //dbg!("Variable assigned", heapid, regid, &self.heap); Ok(()) } else { Err(RuntimePanic::InvalidHeapAddress) @@ -117,7 +131,7 @@ impl VirtualMachine { if let Some(var) = self.heap.get(&heapid) { if let Some(val) = &var.1 { self.registry[regid] = Some(val.clone()); - dbg!("Variable pushed to registry", heapid, regid, &self.registry); + //dbg!("Variable pushed to registry", heapid, regid, &self.registry); Ok(()) } else { Err(RuntimePanic::ValueNotInitialized) @@ -129,12 +143,32 @@ impl VirtualMachine { Command::StringLit(string) => { if self.stack.len() < usize::MAX { self.stack.push(Value::StringVal(string.clone())); - dbg!("String literal added to stack", string, &self.stack); + //dbg!("String literal added to stack", string, &self.stack); Ok(()) } else { Err(RuntimePanic::StackOverflow) } } + Command::FunctionCall(funcid) => { + if self.functions.len() <= funcid { + Err(RuntimePanic::InvalidFuncAddress) + } else { + match &self.functions[funcid] { + FunctionDef::Builtin(f) => { + let mut params = Vec::new(); + for _ in 0..f.signature.parameters.len() { + if let Some(val) = self.stack.pop() { + params.push(val); + } else { + return Err(RuntimePanic::StackUnderflow); + } + } + (f.function)(params); + } + } + Ok(()) + } + } } } } @@ -157,14 +191,8 @@ impl AllocatedVar { } } } - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum VariableType { - TypeString, -} - #[derive(Clone, Debug, PartialEq, Eq)] -enum Value { +pub enum Value { StringVal(String), } @@ -175,3 +203,16 @@ impl Value { } } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum VariableType { + TypeString, +} + +impl ToString for VariableType { + fn to_string(&self) -> String { + match self { + VariableType::TypeString => "String".to_string(), + } + } +}