Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize #18

Merged
merged 3 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ path = "src/bin/cli.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
cirru_parser = "0.1.26"
cirru_parser = "0.1.28"
regex = "1.10.2"
lazy_static = "1.4.0"
clap = { version = "4.4.18", features = ["derive"] }
bincode = "2.0.0-rc.3"

[target.'cfg(not(target_env = "msvc"))'.dependencies]
tikv-jemallocator = "0.5"
# [target.'cfg(not(target_env = "msvc"))'.dependencies]
# tikv-jemallocator = "0.5"

[profile.release]
debug = true
10 changes: 5 additions & 5 deletions src/bin/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use clap::{arg, Parser};

use calx_vm::{log_calx_value, parse_function, Calx, CalxFunc, CalxImportsDict, CalxVM};

#[cfg(not(target_env = "msvc"))]
use tikv_jemallocator::Jemalloc;
// #[cfg(not(target_env = "msvc"))]
// use tikv_jemallocator::Jemalloc;

#[cfg(not(target_env = "msvc"))]
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;
// #[cfg(not(target_env = "msvc"))]
// #[global_allocator]
// static GLOBAL: Jemalloc = Jemalloc;

/// binary format for saving calx program
/// TODO this is not a valid file format that requires magic code
Expand Down
10 changes: 5 additions & 5 deletions src/calx.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
mod types;

use bincode::{Decode, Encode};
// use bincode::{Decode, Encode};
use core::fmt;
use lazy_static::lazy_static;
use regex::Regex;
use std::str::FromStr;
use std::{rc::Rc, str::FromStr};

pub use types::CalxType;

/// Simplied from Calcit, but trying to be basic and mutable
#[derive(Debug, Clone, PartialEq, PartialOrd, Decode, Encode)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Calx {
/// TODO
Nil,
Expand All @@ -20,7 +20,7 @@ pub enum Calx {
/// `f64`
F64(f64),
// TODO
Str(String),
Str(Rc<str>),
/// TODO
List(Vec<Calx>),
// to simultate linked structures
Expand All @@ -39,7 +39,7 @@ impl FromStr for Calx {
_ => {
let s0 = s.chars().next().unwrap();
if s0 == '|' || s0 == ':' {
Ok(Calx::Str(s[1..s.len()].to_owned()))
Ok(Calx::Str(Rc::from(&s[1..s.len()])))
} else if FLOAT_PATTERN.is_match(s) {
match s.parse::<f64>() {
Ok(u) => Ok(Calx::F64(u)),
Expand Down
24 changes: 12 additions & 12 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ pub fn parse_function(nodes: &[Cirru]) -> Result<CalxFunc, String> {
return Err(String::from("Not a function"));
}

let name: Box<str> = if let Cirru::Leaf(x) = nodes[1].to_owned() {
x
let name: Rc<str> = if let Cirru::Leaf(x) = &nodes[1] {
(**x).into()
} else {
return Err(String::from("invalid name"));
};
Expand Down Expand Up @@ -61,7 +61,7 @@ pub fn parse_function(nodes: &[Cirru]) -> Result<CalxFunc, String> {
ret_types: Rc::new(ret_types),
local_names: Rc::new(locals_collector.locals),
syntax: Rc::new(body),
instrs: None,
instrs: Rc::new(vec![]),
})
}

Expand Down Expand Up @@ -194,33 +194,33 @@ pub fn parse_instr(ptr_base: usize, node: &Cirru, collector: &mut LocalsCollecto
return Err(format!("call expected function name, {:?}", xs));
}
let name: Box<str> = match &xs[1] {
Cirru::Leaf(s) => s.to_owned(),
Cirru::Leaf(s) => (**s).into(),
Cirru::List(_) => return Err(format!("expected a name, got {:?}", xs[1])),
};

Ok(vec![CalxSyntax::Call((*name).to_owned())])
Ok(vec![CalxSyntax::Call(Rc::from(name))])
}
"return-call" => {
if xs.len() != 2 {
return Err(format!("return-call expected function name, {:?}", xs));
}
let name: Box<str> = match &xs[1] {
Cirru::Leaf(s) => s.to_owned(),
Cirru::Leaf(s) => (**s).into(),
Cirru::List(_) => return Err(format!("expected a name, got {:?}", xs[1])),
};

Ok(vec![CalxSyntax::ReturnCall((*name).to_owned())])
Ok(vec![CalxSyntax::ReturnCall(Rc::from(name))])
}
"call-import" => {
if xs.len() != 2 {
return Err(format!("call expected function name, {:?}", xs));
}
let name: Box<str> = match &xs[1] {
Cirru::Leaf(s) => s.to_owned(),
Cirru::Leaf(s) => (**s).into(),
Cirru::List(_) => return Err(format!("expected a name, got {:?}", xs[1])),
};

Ok(vec![CalxSyntax::CallImport((*name).to_owned())])
Ok(vec![CalxSyntax::CallImport(Rc::from(name))])
}
"unreachable" => Ok(vec![CalxSyntax::Unreachable]),
"nop" => Ok(vec![CalxSyntax::Nop]),
Expand All @@ -247,11 +247,11 @@ pub fn parse_instr(ptr_base: usize, node: &Cirru, collector: &mut LocalsCollecto
return Err(format!("assert expected an extra message, {:?}", xs));
}
let message: Box<str> = match &xs[1] {
Cirru::Leaf(s) => s.to_owned(),
Cirru::Leaf(s) => (**s).into(),
Cirru::List(_) => return Err(format!("assert expected a message, got {:?}", xs[1])),
};

Ok(vec![CalxSyntax::Assert((*message).to_owned())])
Ok(vec![CalxSyntax::Assert(Rc::from(message))])
}
"inspect" => Ok(vec![CalxSyntax::Inspect]),
"if" => parse_if(ptr_base, xs, collector),
Expand Down Expand Up @@ -325,7 +325,7 @@ pub fn parse_if(ptr_base: usize, xs: &[Cirru], collector: &mut LocalsCollector)
return Err(format!("if expected 2 or 3 arguments, got {:?}", xs));
}
let types = parse_block_types(&xs[1])?;
let ret_types = types.1.clone();
let ret_types = types.1;
let then_syntax = parse_do(&xs[2], collector)?;
let else_syntax = if xs.len() == 4 { parse_do(&xs[3], collector)? } else { vec![] };

Expand Down
12 changes: 5 additions & 7 deletions src/syntax.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use std::rc::Rc;

use bincode::{Decode, Encode};

use crate::{Calx, CalxType};

/// learning from WASM but for dynamic data
#[derive(Debug, Clone, PartialEq, PartialOrd, Decode, Encode)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum CalxSyntax {
/// `local.set`, pop from stack, set value at position
LocalSet(usize),
Expand Down Expand Up @@ -98,11 +96,11 @@ pub enum CalxSyntax {
Echo,
/// `call`, call function
/// TODO optimize with index
Call(String),
Call(Rc<str>),
/// `return-call`, tail recursion call function name
ReturnCall(String),
ReturnCall(Rc<str>),
/// `call-import`, call import function
CallImport(String),
CallImport(Rc<str>),
/// `unreachable`, unreachable panic
Unreachable,
/// `nop`, no operation placeholder
Expand All @@ -112,7 +110,7 @@ pub enum CalxSyntax {
/// `return`, return from function
Return,
/// `assert`, TODO might also be a foreign function instead
Assert(String),
Assert(Rc<str>),
/// `inspect`, inspecting stack
Inspect,
/// `if`, takes 1 value from stack, returns values as ret_types
Expand Down
48 changes: 21 additions & 27 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,7 @@ impl CalxVM {

pub fn setup_top_frame(&mut self) -> Result<(), String> {
self.top_frame.instrs = match self.find_func("main") {
Some(f) => match f.instrs.clone() {
Some(x) => x.to_owned(),
None => return Err("main function must have instrs".to_string()),
},
Some(f) => f.instrs.to_owned(),
None => return Err("main function is required".to_string()),
};

Expand All @@ -93,7 +90,7 @@ impl CalxVM {
&mut output,
format_args!(
"{indent}Internal frames: {:?}",
self.frames.iter().map(|x| x.name.clone()).collect::<Vec<_>>()
self.frames.iter().map(|x| &*x.name).collect::<Vec<_>>()
),
)
.expect("inspect display");
Expand Down Expand Up @@ -160,7 +157,7 @@ impl CalxVM {

use instr::CalxInstr::*;

match &instr {
match instr {
Jmp(line) => {
self.top_frame.pointer = *line;
return Ok(true); // point reset, goto next loop
Expand All @@ -172,7 +169,7 @@ impl CalxVM {
JmpIf(line) => {
let v = self.stack.pop().unwrap();
if v == Calx::Bool(true) || v == Calx::I64(1) {
self.top_frame.pointer = line.to_owned();
self.top_frame.pointer = *line;
return Ok(true); // point reset, goto next loop
}
}
Expand Down Expand Up @@ -251,7 +248,7 @@ impl CalxVM {
GlobalNew => self.globals.push(Calx::Nil),
Const(v) => self.stack_push(v.to_owned()),
Dup => {
self.stack_push(self.stack[self.stack.len() - 1].to_owned());
self.stack_push(self.stack.last().unwrap().to_owned());
}
Drop => {
let _ = self.stack_pop()?;
Expand Down Expand Up @@ -426,25 +423,23 @@ impl CalxVM {
Call(idx) => {
// println!("frame size: {}", self.frames.len());
let f = &self.funcs[*idx];
let instrs = f.instrs.clone();
let instrs = &f.instrs;
let ret_types = f.ret_types.clone();
let f_name = f.name.clone();

let n = f.params_types.len();
self.check_before_pop_n(n)?;
let locals = self.stack.split_off(self.stack.len() - n);
let next_size = self.stack.len() - n;
let locals = self.stack.split_off(next_size);

// TODO reduce copy drop

let new_frame = CalxFrame {
name: f_name,
initial_stack_size: self.stack.len(),
initial_stack_size: next_size,
locals,
pointer: 0,
instrs: match instrs {
Some(x) => x.clone(),
None => unreachable!("function must have instrs"),
},
instrs: instrs.to_owned(),
ret_types,
};
let prev_frame = mem::replace(&mut self.top_frame, new_frame);
Expand All @@ -458,16 +453,18 @@ impl CalxVM {
let f = &self.funcs[*idx];

// println!("examine stack: {:?}", self.stack);
let instrs = f.instrs.clone();
let instrs = &f.instrs;
let ret_types = f.ret_types.clone();
let f_name = f.name.clone();

let n = f.params_types.len();
self.check_before_pop_n(n)?;
let locals = self.stack.split_off(self.stack.len() - n);

let next_size = self.stack.len() - n;
let locals = self.stack.split_off(next_size);

let prev_frame = &self.top_frame;
if prev_frame.initial_stack_size != self.stack.len() {
if prev_frame.initial_stack_size != next_size {
return Err(self.gen_err(format!(
"expected constant initial stack size: {}, got: {}",
prev_frame.initial_stack_size,
Expand All @@ -476,20 +473,17 @@ impl CalxVM {
}
self.top_frame = CalxFrame {
name: f_name,
initial_stack_size: self.stack.len(),
initial_stack_size: next_size,
locals,
pointer: 0,
instrs: match instrs {
Some(x) => x.clone(),
None => panic!("function must have instrs"),
},
instrs: instrs.to_owned(),
ret_types,
};

// start in new frame
return Ok(true);
}
CallImport(f_name) => match self.imports.to_owned().get(f_name) {
CallImport(f_name) => match self.imports.get(f_name) {
None => return Err(self.gen_err(format!("missing imported function {}", f_name))),
Some((f, size)) => {
if self.stack.len() < *size {
Expand Down Expand Up @@ -663,13 +657,13 @@ impl CalxVM {
}
None => return Err(format!("cannot find function named: {}", f_name)),
},
CalxSyntax::CallImport(f_name) => match &self.imports.get(f_name.as_str()) {
CalxSyntax::CallImport(f_name) => match &self.imports.get(f_name) {
Some((_f, size)) => {
if stack_size < *size {
return Err(format!("insufficient size to call import: {} {:?}", stack_size, size));
}
stack_size = stack_size - size + 1;
ops.push(CalxInstr::CallImport(Rc::from(f_name.as_str())))
ops.push(CalxInstr::CallImport(f_name.to_owned()))
}
None => return Err(format!("missing imported function {}", f_name)),
},
Expand Down Expand Up @@ -753,7 +747,7 @@ impl CalxVM {
));
}

self.funcs[i].instrs = Some(Rc::new(ops));
self.funcs[i].instrs = Rc::new(ops);
}

Ok(())
Expand Down
13 changes: 3 additions & 10 deletions src/vm/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct CalxFunc {
pub params_types: Rc<Vec<CalxType>>,
pub ret_types: Rc<Vec<CalxType>>,
pub syntax: Rc<Vec<CalxSyntax>>,
pub instrs: Option<Rc<Vec<CalxInstr>>>,
pub instrs: Rc<Vec<CalxInstr>>,
pub local_names: Rc<Vec<String>>,
}

Expand All @@ -33,15 +33,8 @@ impl fmt::Display for CalxFunc {
}
f.write_str(" .")?;
}
match &self.instrs {
Some(instrs) => {
for (idx, instr) in instrs.iter().enumerate() {
write!(f, "\n {:02} {:?}", idx, instr)?;
}
}
None => {
write!(f, "\n <none>")?;
}
for (idx, instr) in self.instrs.iter().enumerate() {
write!(f, "\n {:02} {:?}", idx, instr)?;
}
f.write_str("\n")?;
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions src/vm/instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub enum CalxInstr {
/// return from function
Return,
/// TODO might also be a foreign function instead
Assert(String),
Assert(Rc<str>),
/// inspecting stack
Inspect,
}
Expand Down Expand Up @@ -153,7 +153,7 @@ impl TryFrom<&CalxSyntax> for CalxInstr {
CalxSyntax::Quit(a) => Ok(Self::Quit(a.to_owned())),
CalxSyntax::Return => Ok(Self::Return),
CalxSyntax::Assert(a) => Ok(Self::Assert(a.to_owned())),
CalxSyntax::CallImport(a) => Ok(Self::CallImport(Rc::from(a.as_str()))),
CalxSyntax::CallImport(a) => Ok(Self::CallImport(a.to_owned())),
// debug
CalxSyntax::Inspect => Ok(Self::Inspect),

Expand Down
10 changes: 10 additions & 0 deletions try.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

cargo run -- -s demos/hello.cirru
cargo run -- -s demos/sum.cirru
cargo run -- -s demos/assert.cirru
cargo run -- -s demos/nested.cirru
cargo run -- -s demos/named.cirru
cargo run -- -s demos/recur.cirru
cargo run -- -s demos/fibonacci.cirru
cargo run -- -s demos/if.cirru
cargo run -- -s demos/fibo-if.cirru
Loading