From 4c3ea6c84b94a57ee00729902cddca1114752721 Mon Sep 17 00:00:00 2001 From: tiye Date: Sat, 16 Jul 2022 15:27:44 +0800 Subject: [PATCH] initial support for generating binary and evaluating from binary; tag 0.1.3 --- Cargo.toml | 11 +++++---- README.md | 4 ++++ src/bin/calx.rs | 61 +++++++++++++++++++++++++++++++++++++++++-------- src/parser.rs | 8 +++---- src/primes.rs | 22 +++++++++--------- 5 files changed, 77 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0427021..e2cb880 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "calx_vm" -version = "0.1.2" +version = "0.1.3" authors = ["jiyinyiyong "] edition = "2018" license = "MIT" @@ -16,10 +16,11 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cirru_parser = "0.1.17" -regex = "1.5.4" +cirru_parser = "0.1.23" +regex = "1.6.0" lazy_static = "1.4.0" -clap = "3.1.5" +clap = "3.2.12" +bincode = "2.0.0-rc.1" [profile.release] -debug = true \ No newline at end of file +debug = true diff --git a/README.md b/README.md index fe3a4a6..1ffd9db 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,10 @@ calx -S hello.cirru calx -D hello.cirru ``` +`--emit-binary filename` for encode functions into a binary file. + +`--eval-binary` for reading a binary input file to run. + ### Syntax Sugar Code of: diff --git a/src/bin/calx.rs b/src/bin/calx.rs index 723310d..c7a78bb 100644 --- a/src/bin/calx.rs +++ b/src/bin/calx.rs @@ -28,26 +28,69 @@ fn main() -> Result<(), String> { .help("disabled preprocess") .takes_value(false), ) + .arg( + Arg::new("EMIT_BINARY") + .long("emit-binary") + .value_name("emit-binary") + .help("emit binary, rather than running") + .takes_value(true), + ) + .arg( + Arg::new("EVALUATE_BINARY") + .long("eval-binary") + .value_name("eval-binary") + .help("evaluate program from binary") + .takes_value(false), + ) .arg(Arg::new("SOURCE").help("A *.cirru file for loading code").required(true).index(1)) .get_matches(); let source = matches.value_of("SOURCE").unwrap(); let show_code = matches.is_present("SHOW_CODE"); let disable_pre = matches.is_present("DISABLE_PRE"); - - let contents = fs::read_to_string(source).expect("Cirru file for instructions"); - let xs = parse(&contents).expect("Some Cirru content"); + let emit_binary = matches.is_present("EMIT_BINARY"); + let eval_binary = matches.is_present("EVALUATE_BINARY"); let mut fns: Vec = vec![]; - for x in xs { - if let Cirru::List(ys) = x { - let f = parse_function(&ys)?; - fns.push(f); - } else { - panic!("expected top level expressions"); + + if eval_binary { + let code = fs::read(source).expect("read binar from source file"); + fns = bincode::decode_from_slice(&code, bincode::config::standard()) + .expect("decode functions from binary") + .0; + } else { + let contents = fs::read_to_string(source).expect("Cirru file for instructions"); + let xs = parse(&contents).expect("Some Cirru content"); + + for x in xs { + if let Cirru::List(ys) = x { + let f = parse_function(&ys)?; + fns.push(f); + } else { + panic!("expected top level expressions"); + } } } + if emit_binary { + let mut slice = [0u8; 10000]; + let length = match bincode::encode_into_slice(&fns, &mut slice, bincode::config::standard()) { + Ok(l) => { + println!("encoded binary length: {}", l); + l + } + Err(e) => panic!("failed on default length of 10000: {}", e), + }; + let slice = &slice[..length]; + let target_file = matches.value_of("EMIT_BINARY").unwrap(); + match fs::write(target_file, slice) { + Ok(_) => println!("wrote binary to {}", target_file), + Err(e) => panic!("failed to write binary to {}: {}", target_file, e), + }; + return Ok(()); + // println!("Bytes written: {:?}", slice); + } + let mut imports: CalxImportsDict = HashMap::new(); imports.insert(String::from("log"), (log_calx_value, 1)); imports.insert(String::from("log2"), (log_calx_value, 2)); diff --git a/src/parser.rs b/src/parser.rs index 8e16f5e..23ae0ec 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -55,7 +55,7 @@ pub fn parse_function(nodes: &[Cirru]) -> Result { } Ok(CalxFunc { - name, + name: name.to_string(), params_types, ret_types, instrs: body, @@ -210,7 +210,7 @@ pub fn parse_instr(ptr_base: usize, node: &Cirru) -> Result, Stri Cirru::List(_) => return Err(format!("expected a name, got {:?}", xs[1])), }; - Ok(vec![CalxInstr::Call(name)]) + Ok(vec![CalxInstr::Call((*name).to_owned())]) } "call-import" => { if xs.len() != 2 { @@ -221,7 +221,7 @@ pub fn parse_instr(ptr_base: usize, node: &Cirru) -> Result, Stri Cirru::List(_) => return Err(format!("expected a name, got {:?}", xs[1])), }; - Ok(vec![CalxInstr::CallImport(name)]) + Ok(vec![CalxInstr::CallImport((*name).to_owned())]) } "unreachable" => Ok(vec![CalxInstr::Unreachable]), "nop" => Ok(vec![CalxInstr::Nop]), @@ -252,7 +252,7 @@ pub fn parse_instr(ptr_base: usize, node: &Cirru) -> Result, Stri Cirru::List(_) => return Err(format!("assert expected a message, got {:?}", xs[1])), }; - Ok(vec![CalxInstr::Assert(message)]) + Ok(vec![CalxInstr::Assert((*message).to_owned())]) } _ => Err(format!("unknown instruction: {}", name)), }, diff --git a/src/primes.rs b/src/primes.rs index 840ac9f..3189885 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -6,10 +6,11 @@ * (I'm not equiped enough for building a bytecode VM yet...) */ +use bincode::{Decode, Encode}; use std::fmt; /// Simplied from Calcit, but trying to be basic and mutable -#[derive(Debug, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Decode, Encode)] pub enum Calx { Nil, Bool(bool), @@ -18,10 +19,10 @@ pub enum Calx { Str(String), List(Vec), // to simultate linked structures - Link(Box, Box, Box), + // Link(Box, Box, Box), } -#[derive(Debug, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Decode, Encode)] pub enum CalxType { Nil, Bool, @@ -52,15 +53,14 @@ impl fmt::Display for Calx { } f.write_str(")")?; Ok(()) - } - Calx::Link(..) => f.write_str("TODO LINK"), + } // Calx::Link(..) => f.write_str("TODO LINK"), } } } -#[derive(Debug, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Encode, Decode)] pub struct CalxFunc { - pub name: Box, + pub name: String, pub params_types: Vec, pub ret_types: Vec, pub instrs: Vec, @@ -86,7 +86,7 @@ impl fmt::Display for CalxFunc { } /// learning from WASM but for dynamic data -#[derive(Debug, Clone, PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Decode, Encode)] pub enum CalxInstr { // Param, // load variable from parameter LocalSet(usize), @@ -150,14 +150,14 @@ pub enum CalxInstr { /// pop and println current value Echo, /// TODO use function name at first, during running, only use index, - Call(Box), - CallImport(Box), + Call(String), + CallImport(String), Unreachable, Nop, Quit(usize), // quit and return value Return, /// TODO might also be a foreign function instead - Assert(Box), + Assert(String), } #[derive(Debug, Clone, PartialEq, PartialOrd)]