Skip to content

Commit

Permalink
Merge pull request #13 from calcit-lang/return-call
Browse files Browse the repository at this point in the history
a toy version of return-call
  • Loading branch information
NoEgAm authored Jul 21, 2022
2 parents fb8a1fd + 6630ef9 commit 4324377
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- run: cargo run -- -S examples/assert.cirru
- run: cargo run -- -S examples/nested.cirru
- run: cargo run -- -S examples/named.cirru
- run: cargo run -- examples/recur.cirru
- run: cargo run -- --emit-binary target/a.calx examples/named.cirru && cargo run -- --eval-binary target/a.calx

# - run: cargo test
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
- run: cargo run -- -S examples/assert.cirru
- run: cargo run -- -S examples/nested.cirru
- run: cargo run -- -S examples/named.cirru
- run: cargo run -- examples/recur.cirru
- run: cargo run -- --emit-binary target/a.calx examples/named.cirru && cargo run -- --eval-binary target/a.calx

- uses: actions-rs/clippy-check@v1
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ Calx Binary Edition `0.1`:
| (BlockEnd) | internal mark for ending a block | Internal |
| `echo` | pop value from stack and print | |
| `call $f` | call function `$f` | |
| `return-call $f` | tail call function `$f` | |
| `call-import $f` | call imported function `$f` | |
| `unreachable` | throw unreachable panic | |
| `nop` | No op | |
Expand Down
24 changes: 24 additions & 0 deletions examples/recur.cirru
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

fn main ()
const 0
const 100000
call sum
echo

fn sum (($acc i64) ($x i64) -> i64)
local.get $acc
local.get $x
add
;; dup
;; echo
block (->)
block (->)
local.get $x
const 1
i.le
br-if 1
local.get $x
const -1
add
return-call sum
return
11 changes: 11 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,17 @@ pub fn parse_instr(ptr_base: usize, node: &Cirru, collector: &mut LocalsCollecto

Ok(vec![CalxInstr::Call((*name).to_owned())])
}
"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::List(_) => return Err(format!("expected a name, got {:?}", xs[1])),
};

Ok(vec![CalxInstr::ReturnCall((*name).to_owned())])
}
"call-import" => {
if xs.len() != 2 {
return Err(format!("call expected function name, {:?}", xs));
Expand Down
4 changes: 3 additions & 1 deletion src/primes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ pub enum CalxInstr {
BlockEnd(bool),
/// pop and println current value
Echo,
/// TODO use function name at first, during running, only use index,
/// TODO use function name at first, during running, index can be faster
Call(String),
/// for tail recursion
ReturnCall(String),
CallImport(String),
Unreachable,
Nop,
Expand Down
49 changes: 48 additions & 1 deletion src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ impl CalxVM {

match (&self.stack[last_idx], &v2) {
(Calx::F64(n1), Calx::F64(n2)) => self.stack[last_idx] = Calx::F64(n1 + n2),
(Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64(n1 + n2),
(_, _) => return Err(self.gen_err(format!("expected 2 numbers to +, {:?} {:?}", self.stack[last_idx], v2))),
}
}
Expand All @@ -331,6 +332,7 @@ impl CalxVM {

match (&self.stack[last_idx], &v2) {
(Calx::F64(n1), Calx::F64(n2)) => self.stack[last_idx] = Calx::F64(n1 * n2),
(Calx::I64(n1), Calx::I64(n2)) => self.stack[last_idx] = Calx::I64(n1 * n2),
(_, _) => return Err(self.gen_err(format!("expected 2 numbers to multiply, {:?} {:?}", self.stack[last_idx], v2))),
}
}
Expand Down Expand Up @@ -374,6 +376,7 @@ impl CalxVM {
// TODO
}
CalxInstr::Call(f_name) => {
// println!("frame size: {}", self.frames.len());
match find_func(&self.funcs, &f_name) {
Some(f) => {
let mut locals: Vec<Calx> = vec![];
Expand All @@ -397,6 +400,39 @@ impl CalxVM {
None => return Err(self.gen_err(format!("cannot find function named: {}", f_name))),
}
}
CalxInstr::ReturnCall(f_name) => {
// println!("frame size: {}", self.frames.len());
match find_func(&self.funcs, &f_name) {
Some(f) => {
// println!("examine stack: {:?}", self.stack);
let mut locals: Vec<Calx> = vec![];
for _ in 0..f.params_types.len() {
let v = self.stack_pop()?;
locals.insert(0, v);
}
let prev_frame = self.top_frame.to_owned();
if prev_frame.initial_stack_size != self.stack.len() {
return Err(self.gen_err(format!(
"expected constant initial stack size: {}, got: {}",
prev_frame.initial_stack_size,
self.stack.len()
)));
}
self.top_frame = CalxFrame {
blocks_track: vec![],
initial_stack_size: self.stack.len(),
locals,
pointer: 0,
instrs: f.instrs,
ret_types: f.ret_types,
};

// start in new frame
continue;
}
None => return Err(self.gen_err(format!("cannot find function named: {}", f_name))),
}
}
CalxInstr::CallImport(f_name) => match self.imports.to_owned().get(&*f_name) {
None => return Err(self.gen_err(format!("missing imported function {}", f_name))),
Some((f, size)) => {
Expand Down Expand Up @@ -451,7 +487,7 @@ impl CalxVM {
// println!("\nFUNC {} {}", self.funcs[i].name, stack_size);

for j in 0..self.funcs[i].instrs.len() {
// println!("* {:?}", self.funcs[i].instrs[j].to_owned());
// println!("{} * {:?}", stack_size, self.funcs[i].instrs[j].to_owned());
match self.funcs[i].instrs[j].to_owned() {
CalxInstr::Block {
looped,
Expand Down Expand Up @@ -530,6 +566,16 @@ impl CalxVM {
}
None => return Err(format!("cannot find function named: {}", f_name)),
},
CalxInstr::ReturnCall(f_name) => match find_func(&self.funcs, &f_name) {
Some(f) => {
if stack_size < f.params_types.len() {
return Err(format!("insufficient size to call: {} {:?}", stack_size, f.params_types));
}
stack_size = stack_size - f.params_types.len() + f.ret_types.len();
ops.push(CalxInstr::ReturnCall(f_name))
}
None => return Err(format!("cannot find function named: {}", f_name)),
},
CalxInstr::CallImport(f_name) => match &self.imports.get(&*f_name) {
Some((_f, size)) => {
if stack_size < *size {
Expand Down Expand Up @@ -711,6 +757,7 @@ pub fn instr_stack_arity(op: &CalxInstr) -> (usize, usize) {
CalxInstr::BlockEnd(_) => (0, 0),
CalxInstr::Echo => (1, 0),
CalxInstr::Call(_) => (0, 0), // TODO
CalxInstr::ReturnCall(_) => (0, 0), // TODO
CalxInstr::CallImport(_) => (0, 0), // import
CalxInstr::Unreachable => (0, 0), // TODO
CalxInstr::Nop => (0, 0),
Expand Down

0 comments on commit 4324377

Please sign in to comment.