Added virtual machine and basic running
This commit is contained in:
		
							parent
							
								
									0f45350bec
								
							
						
					
					
						commit
						b3fa498f73
					
				| @ -4,10 +4,10 @@ use super::errors::CompilerError; | ||||
| use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, Statement}; | ||||
| 
 | ||||
| type Variable = (HeapID, VariableType); | ||||
| type HeapID = u32; | ||||
| type RegID = u32; | ||||
| pub type HeapID = usize; | ||||
| pub type RegID = usize; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Command { | ||||
|     InitializeVariable(HeapID, VariableType), // Initializes new variable to HeapID at VariableType
 | ||||
|     BeginScope,                               // Begins new Scope
 | ||||
|  | ||||
| @ -75,6 +75,7 @@ impl CompilerError { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for CompilerError { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let text = match self { | ||||
| @ -83,7 +84,7 @@ impl Display for CompilerError { | ||||
|                 format!("Variable '{}' already exists, re-assign at {}", pos, name) | ||||
|             } | ||||
|             CompilerError::VariableNotExists(pos, name) => { | ||||
|                 format!("Variable '{}' does not exist, at {}", pos, name) | ||||
|                 format!("Variable '{}' does not exist, at {}", name, pos) | ||||
|             } | ||||
|             CompilerError::InvalidScopeExit(pos) => { | ||||
|                 format!("Attempted to escape a scope invalidly at {}", pos) | ||||
| @ -96,3 +97,15 @@ impl Display for CompilerError { | ||||
|         write!(f, "{}", text) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum RuntimePanic { | ||||
|     Fatal, | ||||
|     InvalidCommandIdx(usize), | ||||
|     ScopeStackUnderflow, | ||||
|     StackUnderflow, | ||||
|     StackOverflow, | ||||
|     RegistryNotDefined, | ||||
|     InvalidHeapAddress, | ||||
|     ValueNotInitialized, | ||||
| } | ||||
|  | ||||
							
								
								
									
										37
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -2,28 +2,33 @@ mod compiler; | ||||
| mod errors; | ||||
| mod file_io; | ||||
| mod parser; | ||||
| mod vm; | ||||
| 
 | ||||
| use file_io::open_file; | ||||
| use std::path::Path; | ||||
| 
 | ||||
| use compiler::Compiler; | ||||
| use file_io::open_file; | ||||
| use parser::Parser; | ||||
| use std::path::Path; | ||||
| use vm::VirtualMachine; | ||||
| 
 | ||||
| fn main() { | ||||
|     let path = Path::new("reid_src/test.reid"); | ||||
|     let parsed = Parser::from(open_file(&path).ok().unwrap()).parse(); | ||||
|     match parsed { | ||||
|         Err(error) => { | ||||
|             eprintln!("Syntax error: {}", error); | ||||
|             std::process::exit(1); | ||||
|         } | ||||
|         Ok(parsed) => { | ||||
|             dbg!(&parsed); | ||||
|             let compiled = Compiler::from(parsed).compile(); | ||||
|             if let Err(error) = compiled { | ||||
|                 eprintln!("Compilation error: {}", error); | ||||
|                 std::process::exit(1); | ||||
|             } | ||||
|             dbg!(compiled); | ||||
|         } | ||||
|     if let Err(error) = parsed { | ||||
|         eprintln!("Syntax error: {}", error); | ||||
|         std::process::exit(1); | ||||
|     } | ||||
|     dbg!(&parsed); | ||||
|     let compiled = Compiler::from(parsed.unwrap()).compile(); | ||||
|     if let Err(error) = compiled { | ||||
|         eprintln!("Compilation error: {}", error); | ||||
|         std::process::exit(1); | ||||
|     } | ||||
|     dbg!(&compiled); | ||||
| 
 | ||||
|     let mut vm = VirtualMachine::from(compiled.unwrap()); | ||||
|     if let Err(error) = vm.run() { | ||||
|         eprintln!("Runtime panic: {:#?}", error); | ||||
|         std::process::exit(1); | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										148
									
								
								src/vm.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								src/vm.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| use super::compiler::{Command, CompiledReid, HeapID, VariableType}; | ||||
| use super::errors::RuntimePanic; | ||||
| 
 | ||||
| pub struct VirtualMachine { | ||||
|     registry_stack: Vec<[Option<Value>; 8]>, | ||||
|     registry: [Option<Value>; 8], | ||||
| 
 | ||||
|     stack: Vec<Value>, | ||||
|     heap: HashMap<HeapID, AllocatedVar>, | ||||
| 
 | ||||
|     position: usize, | ||||
|     compiled: CompiledReid, | ||||
| } | ||||
| 
 | ||||
| impl VirtualMachine { | ||||
|     pub fn from(compiled: CompiledReid) -> VirtualMachine { | ||||
|         VirtualMachine { | ||||
|             registry_stack: Vec::new(), | ||||
|             registry: Default::default(), | ||||
| 
 | ||||
|             stack: Vec::new(), | ||||
|             heap: HashMap::new(), | ||||
| 
 | ||||
|             position: 0, | ||||
|             compiled, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn run(&mut self) -> Result<(), RuntimePanic> { | ||||
|         let mut error = None; | ||||
|         while error.is_none() { | ||||
|             if let Some(command) = self.compiled.list.get(self.position).map(|v| v.clone()) { | ||||
|                 self.position += 1; | ||||
|                 if let Err(err) = self.execute(command.clone()) { | ||||
|                     error = Some(err); | ||||
|                 } | ||||
|                 if self.remaining() == 0 { | ||||
|                     break; | ||||
|                 } | ||||
|             } else { | ||||
|                 error = Some(RuntimePanic::InvalidCommandIdx(self.position)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if let Some(error) = error { | ||||
|             Err(error) | ||||
|         } else { | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn remaining(&self) -> usize { | ||||
|         let len = self.compiled.list.len(); | ||||
|         len - self.position.max(0).min(len) | ||||
|     } | ||||
| 
 | ||||
|     fn execute(&mut self, command: Command) -> Result<(), RuntimePanic> { | ||||
|         match command { | ||||
|             Command::InitializeVariable(heapid, vtype) => { | ||||
|                 self.heap.insert(heapid, AllocatedVar(vtype, None)); | ||||
|                 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"); | ||||
|                 Ok(()) | ||||
|             } | ||||
|             Command::EndScope => { | ||||
|                 if let Some(reg) = self.registry_stack.pop() { | ||||
|                     self.registry = reg; | ||||
|                     dbg!("Scope ended"); | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::ScopeStackUnderflow) | ||||
|                 } | ||||
|             } | ||||
|             Command::Pop(regid) => { | ||||
|                 if let Some(val) = self.stack.pop() { | ||||
|                     self.registry[regid] = Some(val); | ||||
|                     dbg!("Registry popped", regid, &self.stack, &self.registry); | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::StackUnderflow) | ||||
|                 } | ||||
|             } | ||||
|             Command::Push(regid) => { | ||||
|                 if let Some(reg) = &self.registry[regid] { | ||||
|                     if self.stack.len() < usize::MAX { | ||||
|                         self.stack.push(reg.clone()); | ||||
|                         dbg!("Registry pushed", regid, &self.stack); | ||||
|                         Ok(()) | ||||
|                     } else { | ||||
|                         Err(RuntimePanic::StackOverflow) | ||||
|                     } | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::RegistryNotDefined) | ||||
|                 } | ||||
|             } | ||||
|             Command::AssignVariable(heapid, regid) => { | ||||
|                 if let Some(reg) = &self.registry[regid] { | ||||
|                     if let Some(var) = self.heap.get_mut(&heapid) { | ||||
|                         var.1 = Some(reg.clone()); | ||||
|                         dbg!("Variable assigned", heapid, regid, &self.heap); | ||||
|                         Ok(()) | ||||
|                     } else { | ||||
|                         Err(RuntimePanic::InvalidHeapAddress) | ||||
|                     } | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::RegistryNotDefined) | ||||
|                 } | ||||
|             } | ||||
|             Command::VarToReg(heapid, regid) => { | ||||
|                 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); | ||||
|                         Ok(()) | ||||
|                     } else { | ||||
|                         Err(RuntimePanic::ValueNotInitialized) | ||||
|                     } | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::InvalidHeapAddress) | ||||
|                 } | ||||
|             } | ||||
|             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); | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
|                     Err(RuntimePanic::StackOverflow) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| struct AllocatedVar(VariableType, Option<Value>); | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| enum Value { | ||||
|     StringVal(String), | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user