Add reading and writing compiled binary
This commit is contained in:
		
							parent
							
								
									70211cecc1
								
							
						
					
					
						commit
						7c5bacbf66
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,5 +1,6 @@ | ||||
| /target | ||||
| 
 | ||||
| *.log | ||||
| *.reidc | ||||
| 
 | ||||
| #Added by cargo | ||||
| # | ||||
|  | ||||
| @ -1 +1,2 @@ | ||||
| let gotus = 3; | ||||
| let gotus = "Hello, world!"; | ||||
| print(gotus); | ||||
							
								
								
									
										20
									
								
								src/args.rs
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/args.rs
									
									
									
									
									
								
							| @ -5,8 +5,10 @@ use argh::FromArgs; | ||||
| #[derive(FromArgs, PartialEq, Debug)] | ||||
| #[argh(description = "reid compiler and Virtual Machine")] | ||||
| pub struct MainOpt { | ||||
|     #[argh(positional, description = "run compiled .reidc from <path>")] | ||||
|     pub run_path: Option<PathBuf>, | ||||
|     #[argh(subcommand)] | ||||
|     pub subcommand: Subcommand, | ||||
|     pub subcommand: Option<Subcommand>, | ||||
| } | ||||
| 
 | ||||
| #[derive(FromArgs, PartialEq, Debug)] | ||||
| @ -14,7 +16,6 @@ pub struct MainOpt { | ||||
| pub enum Subcommand { | ||||
|     Compile(Compile), | ||||
|     Run(Run), | ||||
|     CompileAndRun(CompileAndRun), | ||||
| } | ||||
| 
 | ||||
| #[derive(FromArgs, PartialEq, Debug)] | ||||
| @ -27,27 +28,16 @@ pub struct Compile { | ||||
|     #[argh(positional, description = "source .reid path")] | ||||
|     pub source: String, | ||||
|     #[argh(positional, description = "output .reidc path")] | ||||
|     pub output: String, | ||||
|     pub output: Option<String>, | ||||
| } | ||||
| 
 | ||||
| #[derive(FromArgs, PartialEq, Debug)] | ||||
| #[argh(
 | ||||
|     subcommand, | ||||
|     name = "run", | ||||
|     description = "run compiled .reidc from <path>" | ||||
| )] | ||||
| pub struct Run { | ||||
|     #[argh(positional, description = "otus 2")] | ||||
|     pub path: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(FromArgs, PartialEq, Debug)] | ||||
| #[argh(
 | ||||
|     subcommand, | ||||
|     name = "c_run", | ||||
|     description = "compile and run given .reid file" | ||||
| )] | ||||
| pub struct CompileAndRun { | ||||
| pub struct Run { | ||||
|     #[argh(positional, description = "source .reid path")] | ||||
|     pub source: PathBuf, | ||||
| } | ||||
|  | ||||
| @ -7,9 +7,9 @@ use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, S | ||||
| use super::vm::{FunctionSignature, VariableType}; | ||||
| 
 | ||||
| type Variable = (HeapID, VariableType); | ||||
| pub type FuncID = usize; | ||||
| pub type HeapID = usize; | ||||
| pub type RegID = usize; | ||||
| pub type FuncID = u16; | ||||
| pub type HeapID = u16; | ||||
| pub type RegID = u8; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Command { | ||||
| @ -192,11 +192,11 @@ impl Scope { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn find_function(&self, signature: &FunctionSignature) -> Option<(usize, &FunctionSignature)> { | ||||
|     fn find_function(&self, signature: &FunctionSignature) -> Option<(FuncID, &FunctionSignature)> { | ||||
|         let mut found = None; | ||||
|         for (idx, func) in self.functions.iter().enumerate() { | ||||
|             if func == signature { | ||||
|                 found = Some((idx, func)); | ||||
|                 found = Some((idx as u16, func)); | ||||
|             } | ||||
|         } | ||||
|         found | ||||
|  | ||||
| @ -9,6 +9,9 @@ use super::vm::VariableType; | ||||
| #[derive(Debug)] | ||||
| pub enum GenericError { | ||||
|     StdIOError(io::Error), | ||||
|     CorruptedBytecode, | ||||
|     SyntaxError(SyntaxError), | ||||
|     CompilerError(CompilerError), | ||||
| } | ||||
| 
 | ||||
| impl From<io::Error> for GenericError { | ||||
| @ -17,6 +20,32 @@ impl From<io::Error> for GenericError { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<SyntaxError> for GenericError { | ||||
|     fn from(error: SyntaxError) -> Self { | ||||
|         Self::SyntaxError(error) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<CompilerError> for GenericError { | ||||
|     fn from(error: CompilerError) -> Self { | ||||
|         Self::CompilerError(error) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for GenericError { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let text = match self { | ||||
|             GenericError::StdIOError(err) => format!("IO Error: {}", err), | ||||
|             GenericError::CorruptedBytecode => { | ||||
|                 "Failed to read bytecode. Bytecode might be corrupted.".to_string() | ||||
|             } | ||||
|             GenericError::SyntaxError(err) => format!("Syntax Error: {}", err), | ||||
|             GenericError::CompilerError(err) => format!("Compiler Error: {}", err), | ||||
|         }; | ||||
|         write!(f, "{}", text) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum SyntaxError { | ||||
|     #[allow(dead_code)] | ||||
|  | ||||
							
								
								
									
										155
									
								
								src/file_io.rs
									
									
									
									
									
								
							
							
						
						
									
										155
									
								
								src/file_io.rs
									
									
									
									
									
								
							| @ -3,12 +3,165 @@ use std::io::prelude::*; | ||||
| use std::io::BufReader; | ||||
| use std::path::Path; | ||||
| 
 | ||||
| use super::compiler::{Command, CompiledReid}; | ||||
| use super::errors::GenericError; | ||||
| use super::vm::VariableType; | ||||
| 
 | ||||
| pub fn open_file(path: &Path) -> Result<String, GenericError> { | ||||
| pub fn open_source(path: &Path) -> Result<String, GenericError> { | ||||
|     let file = File::open(path)?; | ||||
|     let mut reader = BufReader::new(file); | ||||
|     let mut text = String::new(); | ||||
|     reader.read_to_string(&mut text)?; | ||||
|     Ok(text) | ||||
| } | ||||
| 
 | ||||
| pub fn into_bytecode(compiled: &CompiledReid) -> Vec<u8> { | ||||
|     let mut list = Vec::new(); | ||||
|     let iter = compiled.list.iter(); | ||||
|     for item in iter { | ||||
|         list.append(&mut item.into_u8()); | ||||
|     } | ||||
|     list | ||||
| } | ||||
| 
 | ||||
| pub fn write_bytecode(bytecode: Vec<u8>, path: &Path) -> Result<(), GenericError> { | ||||
|     let mut file = File::create(path)?; | ||||
|     file.write_all(&bytecode)?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn open_bytecode(path: &Path) -> Result<CompiledReid, GenericError> { | ||||
|     let file = File::open(path)?; | ||||
|     let mut reader = BufReader::new(file); | ||||
|     let mut commands = Vec::new(); | ||||
|     let mut iter = reader.fill_buf()?.iter().peekable(); | ||||
|     while iter.peek().is_some() { | ||||
|         if let Some(command) = Command::from_u8(&mut iter) { | ||||
|             commands.push(command); | ||||
|         } else { | ||||
|             return Err(GenericError::CorruptedBytecode); | ||||
|         } | ||||
|     } | ||||
|     Ok(CompiledReid { list: commands }) | ||||
| } | ||||
| 
 | ||||
| impl VariableType { | ||||
|     fn into_u8(&self) -> u8 { | ||||
|         match self { | ||||
|             VariableType::TypeString => 0, | ||||
|             VariableType::TypeI32 => 1, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn from_u8(num: u8) -> Option<VariableType> { | ||||
|         match num { | ||||
|             0 => Some(VariableType::TypeString), | ||||
|             1 => Some(VariableType::TypeI32), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Command { | ||||
|     fn id(&self) -> u8 { | ||||
|         match *self { | ||||
|             Command::InitializeVariable(..) => 0, | ||||
|             Command::BeginScope => 1, | ||||
|             Command::EndScope => 2, | ||||
|             Command::Pop(..) => 3, | ||||
|             Command::Push(..) => 4, | ||||
|             Command::AssignVariable(..) => 5, | ||||
|             Command::VarToReg(..) => 6, | ||||
|             Command::StringLit(..) => 7, | ||||
|             Command::I32Lit(..) => 8, | ||||
|             Command::FunctionCall(..) => 9, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn from_u8<'a, T: Iterator<Item = &'a u8>>(iter: &mut T) -> Option<Command> { | ||||
|         let id = iter.next()?; | ||||
|         match id { | ||||
|             0 => { | ||||
|                 let heapid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); | ||||
|                 Some(Command::InitializeVariable( | ||||
|                     heapid, | ||||
|                     VariableType::from_u8(*iter.next()?)?, | ||||
|                 )) | ||||
|             } | ||||
|             1 => Some(Command::BeginScope), | ||||
|             2 => Some(Command::EndScope), | ||||
|             3 => Some(Command::Pop(*iter.next()?)), | ||||
|             4 => Some(Command::Push(*iter.next()?)), | ||||
|             5 => { | ||||
|                 let heapid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); | ||||
|                 Some(Command::AssignVariable(heapid, *iter.next()?)) | ||||
|             } | ||||
|             6 => { | ||||
|                 let heapid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); | ||||
|                 Some(Command::VarToReg(heapid, *iter.next()?)) | ||||
|             } | ||||
|             7 => { | ||||
|                 let len = u32::from_be_bytes([ | ||||
|                     *iter.next()?, | ||||
|                     *iter.next()?, | ||||
|                     *iter.next()?, | ||||
|                     *iter.next()?, | ||||
|                 ]); | ||||
|                 let string = String::from_utf8(iter.take(len as usize).cloned().collect()).ok()?; | ||||
|                 Some(Command::StringLit(string)) | ||||
|             } | ||||
|             8 => { | ||||
|                 let num = i32::from_be_bytes([ | ||||
|                     *iter.next()?, | ||||
|                     *iter.next()?, | ||||
|                     *iter.next()?, | ||||
|                     *iter.next()?, | ||||
|                 ]); | ||||
|                 Some(Command::I32Lit(num)) | ||||
|             } | ||||
|             9 => { | ||||
|                 let funcid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); | ||||
|                 Some(Command::FunctionCall(funcid)) | ||||
|             } | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn into_u8(&self) -> Vec<u8> { | ||||
|         let mut list = Vec::new(); | ||||
|         list.push(self.id()); | ||||
|         match &self { | ||||
|             Command::InitializeVariable(heapid, variabletype) => { | ||||
|                 let heapid = heapid.to_be_bytes(); | ||||
|                 list.append(&mut vec![heapid[0], heapid[1], variabletype.into_u8()]) | ||||
|             } | ||||
|             Command::BeginScope => (), | ||||
|             Command::EndScope => (), | ||||
|             Command::Pop(regid) => list.push(*regid), | ||||
|             Command::Push(regid) => list.push(*regid), | ||||
|             Command::AssignVariable(heapid, regid) => { | ||||
|                 let heapid = heapid.to_be_bytes(); | ||||
|                 list.append(&mut vec![heapid[0], heapid[1], *regid]); | ||||
|             } | ||||
|             Command::VarToReg(heapid, regid) => { | ||||
|                 let heapid = heapid.to_be_bytes(); | ||||
|                 list.append(&mut vec![heapid[0], heapid[1], *regid]); | ||||
|             } | ||||
|             Command::StringLit(string) => { | ||||
|                 let string = string.as_bytes(); | ||||
|                 let len = (string.len() as u32).to_be_bytes(); | ||||
|                 list.append(&mut vec![len[0], len[1], len[2], len[3]]); | ||||
|                 list.append(&mut string.to_vec()); | ||||
|             } | ||||
|             Command::I32Lit(num) => { | ||||
|                 let num = num.to_be_bytes(); | ||||
|                 list.append(&mut vec![num[0], num[1], num[2], num[3]]); | ||||
|             } | ||||
|             Command::FunctionCall(funcid) => { | ||||
|                 let funcid = funcid.to_be_bytes(); | ||||
|                 list.append(&mut vec![funcid[0], funcid[1]]); | ||||
|             } | ||||
|         } | ||||
|         list | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										84
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -8,11 +8,13 @@ mod file_io; | ||||
| mod parser; | ||||
| mod vm; | ||||
| 
 | ||||
| use file_io::open_file; | ||||
| use std::path::Path; | ||||
| use file_io::{into_bytecode, open_bytecode, open_source, write_bytecode}; | ||||
| use std::env; | ||||
| use std::path::{Path, PathBuf}; | ||||
| 
 | ||||
| use args::*; | ||||
| use compiler::{CompiledReid, Compiler}; | ||||
| use errors::GenericError; | ||||
| use parser::Parser; | ||||
| use vm::{ | ||||
|     BuiltinFunctionDef, BuiltinFunctions, FunctionSignature, Value, VariableType, VirtualMachine, | ||||
| @ -33,35 +35,69 @@ fn main() { | ||||
| 
 | ||||
|     let opt: MainOpt = argh::from_env(); | ||||
| 
 | ||||
|     match opt.subcommand { | ||||
|         Subcommand::Compile(_) => {} | ||||
|         Subcommand::Run(_) => {} | ||||
|         Subcommand::CompileAndRun(c_run) => { | ||||
|             let path = Path::new(&c_run.source); | ||||
|             let compiled = compile(path, builtin_functions.signatures()); | ||||
|             run(compiled, builtin_functions); | ||||
|     if let Some(run_path) = opt.run_path { | ||||
|         let compiled = open_bytecode(&run_path); | ||||
|         match compiled { | ||||
|             Ok(compiled) => run(compiled, builtin_functions), | ||||
|             Err(error) => { | ||||
|                 eprintln!("{}", error); | ||||
|                 std::process::exit(1); | ||||
|             } | ||||
|         } | ||||
|     } else if let Some(subcommand) = opt.subcommand { | ||||
|         match subcommand { | ||||
|             Subcommand::Compile(opt) => { | ||||
|                 let source = Path::new(&opt.source); | ||||
|                 let output = if let Some(output) = opt.output { | ||||
|                     PathBuf::from(output) | ||||
|                 } else { | ||||
|                     source.with_extension("reidc") | ||||
|                 }; | ||||
|                 let compiled = compile(source, builtin_functions.signatures()); | ||||
|                 match compiled { | ||||
|                     Ok(compiled) => { | ||||
|                         let bytecode = into_bytecode(&compiled); | ||||
|                         if let Err(err) = write_bytecode(bytecode, &output) { | ||||
|                             eprintln!("{}", err); | ||||
|                             std::process::exit(1); | ||||
|                         } | ||||
|                     } | ||||
|                     Err(error) => { | ||||
|                         eprintln!("{}", error); | ||||
|                         std::process::exit(1); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             Subcommand::Run(opt) => { | ||||
|                 let path = Path::new(&opt.source); | ||||
|                 let compiled = compile(path, builtin_functions.signatures()); | ||||
|                 match compiled { | ||||
|                     Ok(compiled) => run(compiled, builtin_functions), | ||||
|                     Err(error) => { | ||||
|                         eprintln!("{}", error); | ||||
|                         std::process::exit(1); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         let command = env::args().collect::<Vec<String>>().join(" "); | ||||
|         eprintln!("Please try running instead:"); | ||||
|         eprintln!("  {} <path>", command); | ||||
|         eprintln!("  {} help", command); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn compile(path: &Path, builtin: Vec<FunctionSignature>) -> CompiledReid { | ||||
|     let parsed = Parser::from(open_file(&path).ok().unwrap()).parse(); | ||||
|     if let Err(error) = parsed { | ||||
|         eprintln!("Syntax error: {}", error); | ||||
|         std::process::exit(1); | ||||
|     } | ||||
|     dbg!(&parsed); | ||||
| fn compile(path: &Path, builtin: Vec<FunctionSignature>) -> Result<CompiledReid, GenericError> { | ||||
|     let parsed = Parser::from(open_source(&path)?).parse()?; | ||||
|     //dbg!(&parsed);
 | ||||
| 
 | ||||
|     let compiled = Compiler::from(parsed.unwrap()) | ||||
|     let compiled = Compiler::from(parsed) | ||||
|         .with_builtin_functions(builtin) | ||||
|         .compile(); | ||||
|     if let Err(error) = compiled { | ||||
|         eprintln!("Compilation error: {}", error); | ||||
|         std::process::exit(1); | ||||
|     } | ||||
|     dbg!(&compiled); | ||||
|         .compile()?; | ||||
|     //dbg!(&compiled);
 | ||||
| 
 | ||||
|     compiled.unwrap() | ||||
|     Ok(compiled) | ||||
| } | ||||
| 
 | ||||
| fn run(reid: CompiledReid, builtin: BuiltinFunctions) { | ||||
|  | ||||
| @ -92,7 +92,7 @@ impl VirtualMachine { | ||||
|             } | ||||
|             Command::Pop(regid) => { | ||||
|                 if let Some(val) = self.stack.pop() { | ||||
|                     self.registry[regid] = Some(val); | ||||
|                     self.registry[regid as usize] = Some(val); | ||||
|                     //dbg!("Registry popped", regid, &self.stack, &self.registry);
 | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
| @ -100,7 +100,7 @@ impl VirtualMachine { | ||||
|                 } | ||||
|             } | ||||
|             Command::Push(regid) => { | ||||
|                 if let Some(reg) = &self.registry[regid] { | ||||
|                 if let Some(reg) = &self.registry[regid as usize] { | ||||
|                     if self.stack.len() < usize::MAX { | ||||
|                         self.stack.push(reg.clone()); | ||||
|                         //dbg!("Registry pushed", regid, &self.stack);
 | ||||
| @ -113,7 +113,7 @@ impl VirtualMachine { | ||||
|                 } | ||||
|             } | ||||
|             Command::AssignVariable(heapid, regid) => { | ||||
|                 if let Some(reg) = &self.registry[regid] { | ||||
|                 if let Some(reg) = &self.registry[regid as usize] { | ||||
|                     if let Some(var) = self.heap.get_mut(&heapid) { | ||||
|                         var.try_set(Some(reg.clone()))?; | ||||
|                         //dbg!("Variable assigned", heapid, regid, &self.heap);
 | ||||
| @ -128,7 +128,7 @@ impl VirtualMachine { | ||||
|             Command::VarToReg(heapid, regid) => { | ||||
|                 if let Some(var) = self.heap.get(&heapid) { | ||||
|                     if let Some(val) = &var.1 { | ||||
|                         self.registry[regid] = Some(val.clone()); | ||||
|                         self.registry[regid as usize] = Some(val.clone()); | ||||
|                         //dbg!("Variable pushed to registry", heapid, regid, &self.registry);
 | ||||
|                         Ok(()) | ||||
|                     } else { | ||||
| @ -156,10 +156,10 @@ impl VirtualMachine { | ||||
|                 } | ||||
|             } | ||||
|             Command::FunctionCall(funcid) => { | ||||
|                 if self.functions.len() <= funcid { | ||||
|                 if self.functions.len() <= funcid as usize { | ||||
|                     Err(RuntimePanic::InvalidFuncAddress) | ||||
|                 } else { | ||||
|                     match &self.functions[funcid] { | ||||
|                     match &self.functions[funcid as usize] { | ||||
|                         FunctionDef::Builtin(f) => { | ||||
|                             let mut params = Vec::new(); | ||||
|                             for _ in 0..f.signature.parameters.len() { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user