Add functions and a print function
This commit is contained in:
		
							parent
							
								
									86c2b13d1a
								
							
						
					
					
						commit
						8b60677123
					
				| @ -1 +1,3 @@ | ||||
| print(); | ||||
| let otus = "Hello, world!"; | ||||
| let dotus = otus; | ||||
| print(dotus); | ||||
| @ -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<T: Into<Vec<FunctionSignature>>>(mut self, list: T) -> Compiler { | ||||
|         self.add_builtin_functions(list.into()); | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn compile(mut self) -> Result<CompiledReid, CompilerError> { | ||||
|         self.handle_expression(self.parsed.0.clone())?; | ||||
|         Ok(CompiledReid { list: self.list }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_builtin_functions<T: Into<Vec<FunctionSignature>>>(&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<String, Variable>, | ||||
|     functions: Vec<FunctionSignature>, | ||||
|     inner_scope: Option<Box<Scope>>, | ||||
| } | ||||
| 
 | ||||
| @ -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, | ||||
|  | ||||
| @ -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<CompilerError>), | ||||
|     CanNotAssignVoidType, | ||||
|     FunctionNotFound(Position, String, Vec<VariableType>), | ||||
| } | ||||
| 
 | ||||
| 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<VariableType>); | ||||
| 
 | ||||
| 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, | ||||
| } | ||||
|  | ||||
							
								
								
									
										22
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								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); | ||||
|  | ||||
| @ -257,10 +257,6 @@ impl<'a> Expect<'a> { | ||||
|             other, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     fn get_expect<T: Into<String>>(&mut self, expectable: Expectable<T>) -> Expect { | ||||
|         self.parser.expect(expectable) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct Expects<'a> { | ||||
|  | ||||
| @ -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, ')'))?; | ||||
|  | ||||
							
								
								
									
										101
									
								
								src/vm/functions.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/vm/functions.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| use super::{Value, VariableType}; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct FunctionSignature { | ||||
|     pub name: String, | ||||
|     pub parameters: Vec<VariableType>, | ||||
| } | ||||
| 
 | ||||
| impl FunctionSignature { | ||||
|     pub fn new<T: Into<String>>(name: T, params: Vec<VariableType>) -> 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<BuiltinFunctionDef> 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<FunctionSignature> for FunctionDef { | ||||
|     fn eq(&self, other: &FunctionSignature) -> bool { | ||||
|         self.get_signature() == other | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct BuiltinFunctionDef { | ||||
|     pub signature: FunctionSignature, | ||||
|     pub function: Box<dyn Fn(Vec<Value>)>, | ||||
| } | ||||
| 
 | ||||
| impl BuiltinFunctionDef { | ||||
|     pub fn new<T: Into<String>>( | ||||
|         name: T, | ||||
|         parameters: Vec<VariableType>, | ||||
|         func: Box<dyn Fn(Vec<Value>)>, | ||||
|     ) -> BuiltinFunctionDef { | ||||
|         BuiltinFunctionDef { | ||||
|             signature: FunctionSignature { | ||||
|                 name: name.into(), | ||||
|                 parameters, | ||||
|             }, | ||||
|             function: func, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct BuiltinFunctions(pub Vec<BuiltinFunctionDef>); | ||||
| 
 | ||||
| impl BuiltinFunctions { | ||||
|     pub fn signatures(&self) -> Vec<FunctionSignature> { | ||||
|         let mut signatures = Vec::new(); | ||||
|         for func in &self.0 { | ||||
|             signatures.push(func.signature.clone()); | ||||
|         } | ||||
|         signatures | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<BuiltinFunctions> for Vec<BuiltinFunctionDef> { | ||||
|     fn from(builtin: BuiltinFunctions) -> Self { | ||||
|         builtin.0 | ||||
|     } | ||||
| } | ||||
| @ -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<Value>; 8]>, | ||||
|     registry: [Option<Value>; 8], | ||||
| 
 | ||||
|     stack: Vec<Value>, | ||||
|     heap: HashMap<HeapID, AllocatedVar>, | ||||
|     functions: Vec<FunctionDef>, | ||||
| 
 | ||||
|     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<T: Into<Vec<BuiltinFunctionDef>>>(&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(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user