Storing the frame pointer in the rstack
This commit is contained in:
@@ -65,7 +65,8 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { var x; asm(&x) { swap 12\nstorew } }")),
|
test_body(state_for("fn test() { var x; asm(&x) { swap 12\nstorew } }")),
|
||||||
vec![
|
vec![
|
||||||
"loadw frame", // Push the addr of x
|
"pushr", // capture frame ptr
|
||||||
|
"peekr", // Push the addr of x
|
||||||
"swap 12", // The asm body, which swaps 12 behind it and stores it there
|
"swap 12", // The asm body, which swaps 12 behind it and stores it there
|
||||||
"storew",
|
"storew",
|
||||||
]
|
]
|
||||||
@@ -78,20 +79,21 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { repeat(5) c { 2; } var k = 5; return k; }")),
|
test_body(state_for("fn test() { repeat(5) c { 2; } var k = 5; return k; }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr", // capture frame ptr
|
||||||
"push 0", // Create the 'c' var and store 0 in it
|
"push 0", // Create the 'c' var and store 0 in it
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew",
|
"storew",
|
||||||
"push 5",
|
"push 5",
|
||||||
"#while", // Starting the loop:
|
"#while", // Starting the loop:
|
||||||
"dup", // Copy the limit
|
"dup", // Copy the limit
|
||||||
"loadw frame", // Load c
|
"peekr", // Load c
|
||||||
"loadw",
|
"loadw",
|
||||||
"sub", // Subtract c from a
|
"sub", // Subtract c from a
|
||||||
"agt 0", // Are we still positive?
|
"agt 0", // Are we still positive?
|
||||||
"#do",
|
"#do",
|
||||||
"push 2", // Pointless loop body
|
"push 2", // Pointless loop body
|
||||||
"pop",
|
"pop",
|
||||||
"loadw frame", // Load c as an lvalue
|
"peekr", // Load c as an lvalue
|
||||||
"dup", // Dup it, load it, add 1
|
"dup", // Dup it, load it, add 1
|
||||||
"loadw",
|
"loadw",
|
||||||
"add 1",
|
"add 1",
|
||||||
@@ -100,10 +102,12 @@ mod test {
|
|||||||
"#end", // End of the loop body!
|
"#end", // End of the loop body!
|
||||||
"pop", // Drop the limit off the top
|
"pop", // Drop the limit off the top
|
||||||
"push 5", // Push the rvalue we'll put in 'k'
|
"push 5", // Push the rvalue we'll put in 'k'
|
||||||
"loadw frame", // THIS IS THE TEST: 'k' should go at frame + 0, because it's
|
"peekr", // THIS IS THE TEST: 'k' should go at frame + 0, because it's
|
||||||
"storew", // taking the same (now freed) frame slot that c took, because c is
|
"storew", // taking the same (now freed) frame slot that c took, because c is
|
||||||
"loadw frame", // now out of scope
|
"peekr", // now out of scope
|
||||||
"loadw",
|
"loadw",
|
||||||
|
"popr", // Blow away old frame ptr
|
||||||
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
|||||||
@@ -9,19 +9,27 @@ impl Compilable for Call {
|
|||||||
// Require a function
|
// Require a function
|
||||||
let sig = sig.expect("lvalue outside a function");
|
let sig = sig.expect("lvalue outside a function");
|
||||||
|
|
||||||
// We need a stack consisting of the arguments (last on top), followed by the address to call
|
// We need a stack consisting of the arguments (last on top), followed by the new fn's frame
|
||||||
|
// pointer, followed by the address to call.
|
||||||
// So, first eval the args:
|
// So, first eval the args:
|
||||||
for arg in self.args {
|
for arg in self.args {
|
||||||
arg.process(state, Some(sig), loc)?;
|
arg.process(state, Some(sig), loc)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now we increment the frame ptr to right after the current frame:
|
||||||
|
sig.emit("peekr");
|
||||||
|
let frame_size = sig.frame_size();
|
||||||
|
if frame_size > 0 {
|
||||||
|
sig.emit_arg("add", frame_size);
|
||||||
|
}
|
||||||
|
|
||||||
// Eval the target
|
// Eval the target
|
||||||
self.target.0.process(state, Some(sig), loc)?;
|
self.target.0.process(state, Some(sig), loc)?;
|
||||||
|
|
||||||
// Before we actually do the call though, we need to deal with some paperwork around the
|
// Before we actually do the call though, we need to deal with some paperwork around the
|
||||||
// frame pointer. We will store the current frame pointer in the rstack:
|
// frame pointer. We will store the current frame pointer in the rstack:
|
||||||
sig.emit("loadw frame");
|
//sig.emit("loadw frame");
|
||||||
sig.emit("pushr");
|
//sig.emit("pushr");
|
||||||
|
|
||||||
// todo this makes arrays not work. we can no longer statically compute the frame size, we
|
// todo this makes arrays not work. we can no longer statically compute the frame size, we
|
||||||
// need to have the frame size stored at runtime somehow, probably rstack. This will mean
|
// need to have the frame size stored at runtime somehow, probably rstack. This will mean
|
||||||
@@ -37,23 +45,15 @@ impl Compilable for Call {
|
|||||||
// todo in fact, a larger refactor would just store the frame size as the first thing in the
|
// todo in fact, a larger refactor would just store the frame size as the first thing in the
|
||||||
// frame, to make vardecls faster
|
// frame, to make vardecls faster
|
||||||
|
|
||||||
// Now we increment the frame ptr to right after the current frame:
|
// Do the call:
|
||||||
let frame_size = sig.frame_size();
|
|
||||||
if frame_size > 0 {
|
|
||||||
sig.emit("loadw frame");
|
|
||||||
sig.emit_arg("add", frame_size);
|
|
||||||
sig.emit("storew frame");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Frame is now pointing at a safe place, the top of stack is the target, do the call:
|
|
||||||
sig.emit("call");
|
sig.emit("call");
|
||||||
|
|
||||||
// And this is where we'll return to. The function has popped its args and left a word on
|
// And this is where we'll return to. The function has popped its args and left a word on
|
||||||
// the stack as a return value, which someone else will deal with (this is the word that
|
// the stack as a return value, which someone else will deal with (this is the word that
|
||||||
// this expr::call will end up evaluating to). But before we're done, we need to restore
|
// this expr::call will end up evaluating to). But before we're done, we need to restore
|
||||||
// our frame pointerS
|
// our frame pointer:
|
||||||
sig.emit("popr");
|
//sig.emit("popr");
|
||||||
sig.emit("storew frame");
|
//sig.emit("storew frame");
|
||||||
|
|
||||||
// And we're finished!
|
// And we're finished!
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -69,22 +69,18 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test(a, b) { test(2, 3); }")),
|
test_body(state_for("fn test(a, b) { test(2, 3); }")),
|
||||||
vec![
|
vec![
|
||||||
"loadw frame", // capture arg b
|
"pushr",
|
||||||
|
"peekr", // capture arg b
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew",
|
"storew",
|
||||||
"loadw frame", // capture arg a
|
"peekr", // capture arg a
|
||||||
"storew",
|
"storew",
|
||||||
"push 2", // evaluating args, in order
|
"push 2", // evaluating args, in order
|
||||||
"push 3",
|
"push 3",
|
||||||
"push _forge_gensym_1", // evaluating target (this fn)
|
"peekr", // The new fn's frame ptr:
|
||||||
"loadw frame", // Store the frame ptr
|
|
||||||
"pushr",
|
|
||||||
"loadw frame", // Increment the frame ptr
|
|
||||||
"add 6",
|
"add 6",
|
||||||
"storew frame",
|
"push _forge_gensym_1", // evaluating target (this fn)
|
||||||
"call", // Actually make the call
|
"call", // Actually make the call
|
||||||
"popr", // Restore the frame ptr
|
|
||||||
"storew frame",
|
|
||||||
"pop", // expr-as-statement drops the evaluated value
|
"pop", // expr-as-statement drops the evaluated value
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
|||||||
@@ -31,16 +31,17 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } }")),
|
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push 3",
|
"push 3",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // x = 3
|
"storew", // x = 3
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"loadw",
|
"loadw",
|
||||||
"push 2",
|
"push 2",
|
||||||
"agt", // The condition, x > 2
|
"agt", // The condition, x > 2
|
||||||
"#if", // The if itself
|
"#if", // The if itself
|
||||||
"push 1",
|
"push 1",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // The branch, x = 1
|
"storew", // The branch, x = 1
|
||||||
"#end"]
|
"#end"]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
@@ -52,20 +53,21 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } else { x = 7; } }")),
|
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } else { x = 7; } }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push 3",
|
"push 3",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // x = 3
|
"storew", // x = 3
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"loadw",
|
"loadw",
|
||||||
"push 2",
|
"push 2",
|
||||||
"agt", // The condition, x > 2
|
"agt", // The condition, x > 2
|
||||||
"#if", // The if itself
|
"#if", // The if itself
|
||||||
"push 1",
|
"push 1",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // The affirmative branch, x = 1
|
"storew", // The affirmative branch, x = 1
|
||||||
"#else", // The alternative
|
"#else", // The alternative
|
||||||
"push 7",
|
"push 7",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // x = 7
|
"storew", // x = 7
|
||||||
"#end"]
|
"#end"]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ impl Compilable for Expr {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Expr::Name(name) => {
|
Expr::Name(name) => {
|
||||||
// todo split into new file
|
|
||||||
match lookup(&name, global_scope, &sig.local_scope) {
|
match lookup(&name, global_scope, &sig.local_scope) {
|
||||||
// Names are treated differently depending on what they are
|
// Names are treated differently depending on what they are
|
||||||
Some(Variable::Literal(val)) => {
|
Some(Variable::Literal(val)) => {
|
||||||
@@ -51,7 +50,8 @@ impl Compilable for Expr {
|
|||||||
Some(Variable::Local(offset)) => {
|
Some(Variable::Local(offset)) => {
|
||||||
// Names of locals are added from the frame pointer
|
// Names of locals are added from the frame pointer
|
||||||
let offset = *offset;
|
let offset = *offset;
|
||||||
sig.emit("loadw frame");
|
|
||||||
|
sig.emit("peekr"); // Frame ptr is top of rstack
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
sig.emit_arg("add", offset);
|
sig.emit_arg("add", offset);
|
||||||
}
|
}
|
||||||
@@ -158,11 +158,12 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state),
|
test_body(state),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push _forge_gensym_3",
|
"push _forge_gensym_3",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // the assignment for x
|
"storew", // the assignment for x
|
||||||
"push _forge_gensym_4",
|
"push _forge_gensym_4",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3", // the address of y (frame + 3) and put gensym_4 in it
|
"add 3", // the address of y (frame + 3) and put gensym_4 in it
|
||||||
"storew",
|
"storew",
|
||||||
]
|
]
|
||||||
@@ -175,11 +176,12 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { var x = 3; var y = &x; }")),
|
test_body(state_for("fn test() { var x = 3; var y = &x; }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push 3",
|
"push 3",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // the assignment for x
|
"storew", // the assignment for x
|
||||||
"loadw frame", // The addr of x
|
"peekr", // The addr of x
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3", // the address of y (frame + 3) and put the addr of x (frame) in it
|
"add 3", // the address of y (frame + 3) and put the addr of x (frame) in it
|
||||||
"storew",
|
"storew",
|
||||||
]
|
]
|
||||||
@@ -192,10 +194,11 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { var x = 3; *1000 = *x; }")),
|
test_body(state_for("fn test() { var x = 3; *1000 = *x; }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push 3",
|
"push 3",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // the assignment for x
|
"storew", // the assignment for x
|
||||||
"loadw frame", // Now we're compiling *x, so load x's value, which is 3
|
"peekr", // Now we're compiling *x, so load x's value, which is 3
|
||||||
"loadw",
|
"loadw",
|
||||||
"loadw", // Then load the value at 3
|
"loadw", // Then load the value at 3
|
||||||
"push 1000", // Push the addr 1000, for the lvalue
|
"push 1000", // Push the addr 1000, for the lvalue
|
||||||
@@ -210,10 +213,11 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("const foo = \"foo\"; fn test() { var x = \"bar\" + 3; }")),
|
test_body(state_for("const foo = \"foo\"; fn test() { var x = \"bar\" + 3; }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push _forge_gensym_3", // 1 is the label in the string table for "foo", 2 for "blah,"
|
"push _forge_gensym_3", // 1 is the label in the string table for "foo", 2 for "blah,"
|
||||||
"push 3", // so 3 is the string "bar"
|
"push 3", // so 3 is the string "bar"
|
||||||
"add", // Add 3 to that address
|
"add", // Add 3 to that address
|
||||||
"loadw frame", // Store it in the first var
|
"peekr", // Store it in the first var
|
||||||
"storew",
|
"storew",
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
|||||||
@@ -45,16 +45,17 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test(a, b) { b = 17 + a; }")),
|
test_body(state_for("fn test(a, b) { b = 17 + a; }")),
|
||||||
vec![
|
vec![
|
||||||
"loadw frame", // Capture var b
|
"pushr", // Store frame ptr
|
||||||
|
"peekr", // Capture var b
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew",
|
"storew",
|
||||||
"loadw frame", // Capture var a
|
"peekr", // Capture var a
|
||||||
"storew",
|
"storew",
|
||||||
"push 17", // Start calculating the rvalue, push the literal
|
"push 17", // Start calculating the rvalue, push the literal
|
||||||
"loadw frame", // This is looking up the "a" arg, at frame + 0
|
"peekr", // This is looking up the "a" arg, at frame + 0
|
||||||
"loadw",
|
"loadw",
|
||||||
"add", // 17 + a
|
"add", // 17 + a
|
||||||
"loadw frame", // Calculate the lvalue
|
"peekr", // Calculate the lvalue
|
||||||
"add 3", // "b" arg is frame + 3
|
"add 3", // "b" arg is frame + 3
|
||||||
"storew", // Finally store
|
"storew", // Finally store
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ impl Compilable for Lvalue {
|
|||||||
}
|
}
|
||||||
Variable::Local(offset) => {
|
Variable::Local(offset) => {
|
||||||
let offset = *offset;
|
let offset = *offset;
|
||||||
sig.emit_arg("loadw", "frame");
|
sig.emit("peekr");
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
sig.emit_arg("add", offset);
|
sig.emit_arg("add", offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,37 +86,38 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test(a) { var x = 0; repeat(a) c { x = x + c; } return x; }")),
|
test_body(state_for("fn test(a) { var x = 0; repeat(a) c { x = x + c; } return x; }")),
|
||||||
vec![
|
vec![
|
||||||
"loadw frame", // capture arg a
|
"pushr",
|
||||||
|
"peekr", // capture arg a
|
||||||
"storew",
|
"storew",
|
||||||
"push 0", // Create the 'x' var and store 0 in it
|
"push 0", // Create the 'x' var and store 0 in it
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew",
|
"storew",
|
||||||
"push 0", // Create the 'c' var and store 0 in it
|
"push 0", // Create the 'c' var and store 0 in it
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 6",
|
"add 6",
|
||||||
"storew",
|
"storew",
|
||||||
"loadw frame", // Load 'a' from args
|
"peekr", // Load 'a' from args
|
||||||
"loadw",
|
"loadw",
|
||||||
"#while", // Starting the loop:
|
"#while", // Starting the loop:
|
||||||
"dup", // Copy the limit
|
"dup", // Copy the limit
|
||||||
"loadw frame", // Load c
|
"peekr", // Load c
|
||||||
"add 6",
|
"add 6",
|
||||||
"loadw",
|
"loadw",
|
||||||
"sub", // Subtract c from a
|
"sub", // Subtract c from a
|
||||||
"agt 0", // Are we still positive?
|
"agt 0", // Are we still positive?
|
||||||
"#do",
|
"#do",
|
||||||
"loadw frame", // Load x
|
"peekr", // Load x
|
||||||
"add 3",
|
"add 3",
|
||||||
"loadw",
|
"loadw",
|
||||||
"loadw frame", // Load c
|
"peekr", // Load c
|
||||||
"add 6",
|
"add 6",
|
||||||
"loadw",
|
"loadw",
|
||||||
"add", // Add c to x
|
"add", // Add c to x
|
||||||
"loadw frame", // Load x as an lvalue
|
"peekr", // Load x as an lvalue
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew", // Store c + x into it
|
"storew", // Store c + x into it
|
||||||
"loadw frame", // Load c as an lvalue
|
"peekr", // Load c as an lvalue
|
||||||
"add 6",
|
"add 6",
|
||||||
"dup", // Dup it, load it, add 1
|
"dup", // Dup it, load it, add 1
|
||||||
"loadw",
|
"loadw",
|
||||||
@@ -125,9 +126,11 @@ mod test {
|
|||||||
"storew",
|
"storew",
|
||||||
"#end", // End of the loop body!
|
"#end", // End of the loop body!
|
||||||
"pop", // Drop the limit off the top
|
"pop", // Drop the limit off the top
|
||||||
"loadw frame", // Load x so we can return it
|
"peekr", // Load x so we can return it
|
||||||
"add 3",
|
"add 3",
|
||||||
"loadw",
|
"loadw",
|
||||||
|
"popr", // toss old frame ptr
|
||||||
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
@@ -140,32 +143,35 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test(a) { var x = 1; repeat(a) { x = x * 2; } return x; }")),
|
test_body(state_for("fn test(a) { var x = 1; repeat(a) { x = x * 2; } return x; }")),
|
||||||
vec![
|
vec![
|
||||||
"loadw frame", // capture arg a
|
"pushr",
|
||||||
|
"peekr", // capture arg a
|
||||||
"storew",
|
"storew",
|
||||||
"push 1", // Create the 'x' var and store 1 in it
|
"push 1", // Create the 'x' var and store 1 in it
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew",
|
"storew",
|
||||||
"loadw frame", // Load 'a' from args
|
"peekr", // Load 'a' from args
|
||||||
"loadw",
|
"loadw",
|
||||||
"#while", // Starting the loop:
|
"#while", // Starting the loop:
|
||||||
"dup", // Copy the limit
|
"dup", // Copy the limit
|
||||||
"agt 0", // Are we still positive?
|
"agt 0", // Are we still positive?
|
||||||
"#do",
|
"#do",
|
||||||
"loadw frame", // Load x
|
"peekr", // Load x
|
||||||
"add 3",
|
"add 3",
|
||||||
"loadw",
|
"loadw",
|
||||||
"push 2", // double it
|
"push 2", // double it
|
||||||
"mul",
|
"mul",
|
||||||
"loadw frame", // Load x as an lvalue
|
"peekr", // Load x as an lvalue
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew", // Store 2x into it
|
"storew", // Store 2x into it
|
||||||
"sub 1", // decrement the counter
|
"sub 1", // decrement the counter
|
||||||
"#end", // End of the loop body!
|
"#end", // End of the loop body!
|
||||||
"pop", // Drop the limit off the top
|
"pop", // Drop the limit off the top
|
||||||
"loadw frame", // Load x so we can return it
|
"peekr", // Load x so we can return it
|
||||||
"add 3",
|
"add 3",
|
||||||
"loadw",
|
"loadw",
|
||||||
|
"popr", // Toss old frame ptr
|
||||||
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
].join("\n")
|
].join("\n")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,11 +11,20 @@ impl Compilable for Return {
|
|||||||
match self {
|
match self {
|
||||||
Return(None) => {
|
Return(None) => {
|
||||||
// Returning nothing, so just default to returning a 0:
|
// Returning nothing, so just default to returning a 0:
|
||||||
|
// (but pop our frame pointer first)
|
||||||
|
sig.emit("popr");
|
||||||
|
sig.emit("pop");
|
||||||
sig.emit_arg("ret", 0)
|
sig.emit_arg("ret", 0)
|
||||||
}
|
}
|
||||||
Return(Some(expr)) => {
|
Return(Some(expr)) => {
|
||||||
// Eval the expr and emit a ret for it
|
// Eval the expr and emit a ret for it
|
||||||
expr.process(state, Some(sig), loc)?;
|
expr.process(state, Some(sig), loc)?;
|
||||||
|
|
||||||
|
// Now that we're done with it, blow away the frame ptr:
|
||||||
|
sig.emit("popr");
|
||||||
|
sig.emit("pop");
|
||||||
|
|
||||||
|
// Finally ret
|
||||||
sig.emit("ret")
|
sig.emit("ret")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,12 +42,15 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test(a) { return a + 3; }")),
|
test_body(state_for("fn test(a) { return a + 3; }")),
|
||||||
vec![
|
vec![
|
||||||
"loadw frame", // capture arg a
|
"pushr",
|
||||||
|
"peekr", // capture arg a
|
||||||
"storew",
|
"storew",
|
||||||
"loadw frame", // Load a
|
"peekr", // Load a
|
||||||
"loadw",
|
"loadw",
|
||||||
"push 3", // Add 3
|
"push 3", // Add 3
|
||||||
"add",
|
"add",
|
||||||
|
"popr", // Toss frame ptr
|
||||||
|
"pop",
|
||||||
"ret", // Return that
|
"ret", // Return that
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
@@ -50,13 +62,16 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test(a) { if (a > 0) { return; } }")),
|
test_body(state_for("fn test(a) { if (a > 0) { return; } }")),
|
||||||
vec![
|
vec![
|
||||||
"loadw frame", // capture arg a
|
"pushr",
|
||||||
|
"peekr", // capture arg a
|
||||||
"storew",
|
"storew",
|
||||||
"loadw frame", // Load a
|
"peekr", // Load a
|
||||||
"loadw",
|
"loadw",
|
||||||
"push 0", // Compare to 0
|
"push 0", // Compare to 0
|
||||||
"agt",
|
"agt",
|
||||||
"#if", // If statement
|
"#if", // If statement
|
||||||
|
"popr", // Toss frame ptr
|
||||||
|
"pop",
|
||||||
"ret 0", // Default return value, for an expr-less return
|
"ret 0", // Default return value, for an expr-less return
|
||||||
"#end",
|
"#end",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -36,16 +36,17 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { var a; var b = 7; a = b * 2; }")),
|
test_body(state_for("fn test() { var a; var b = 7; a = b * 2; }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push 7", // Start calculating the rvalue, push the literal
|
"push 7", // Start calculating the rvalue, push the literal
|
||||||
"loadw frame", // "b" is the second local var at frame + 3
|
"peekr", // "b" is the second local var at frame + 3
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew", // Do the initialization
|
"storew", // Do the initialization
|
||||||
"loadw frame", // Now we're evaluating b * 2
|
"peekr", // Now we're evaluating b * 2
|
||||||
"add 3", // b is at frame + 3...
|
"add 3", // b is at frame + 3...
|
||||||
"loadw", // load it to the stack
|
"loadw", // load it to the stack
|
||||||
"push 2",
|
"push 2",
|
||||||
"mul", // b * 2 evaluated
|
"mul", // b * 2 evaluated
|
||||||
"loadw frame", // Loading "a" as an lvalue
|
"peekr", // Loading "a" as an lvalue
|
||||||
"storew", // doing the assignment
|
"storew", // doing the assignment
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
|||||||
@@ -27,37 +27,38 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_body(state_for("fn test() { var x = 0; var c = 0; while (c < 10) { x = x + c; c = c + 1; } }")),
|
test_body(state_for("fn test() { var x = 0; var c = 0; while (c < 10) { x = x + c; c = c + 1; } }")),
|
||||||
vec![
|
vec![
|
||||||
|
"pushr",
|
||||||
"push 0",
|
"push 0",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // var x = 0
|
"storew", // var x = 0
|
||||||
"push 0",
|
"push 0",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew", // var c = 0
|
"storew", // var c = 0
|
||||||
"#while", // Start the loop
|
"#while", // Start the loop
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"loadw",
|
"loadw",
|
||||||
"push 10",
|
"push 10",
|
||||||
"alt", // c > 10
|
"alt", // c > 10
|
||||||
"#do", // Start loop body
|
"#do", // Start loop body
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"loadw",
|
"loadw",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"loadw",
|
"loadw",
|
||||||
"add",
|
"add",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"storew", // x = x + c
|
"storew", // x = x + c
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"loadw",
|
"loadw",
|
||||||
"push 1",
|
"push 1",
|
||||||
"add",
|
"add",
|
||||||
"loadw frame",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew", // c = c + 1
|
"storew", // c = c + 1
|
||||||
"#end", // End the loop body
|
"#end" // End the loop body
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -84,12 +84,15 @@ impl CompiledFn {
|
|||||||
self.local_scope.len() * 3
|
self.local_scope.len() * 3
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit the code to add the arguments' names to the local scopr, and move the arguments off
|
/// Emit the code to add the arguments' names to the local scope, and move the arguments off
|
||||||
/// the stack into the frame. Should be run before the body is compiled, because this code
|
/// the stack into the frame. Should be run before the body is compiled, because this code
|
||||||
/// has to be the first thing in the body
|
/// has to be the first thing in the body
|
||||||
pub(crate) fn handle_args(&mut self, function: &Function) -> Result<(), CompileError> {
|
pub(crate) fn handle_args(&mut self, function: &Function) -> Result<(), CompileError> {
|
||||||
let mut arg_names: Vec<&str> = Vec::new();
|
let mut arg_names: Vec<&str> = Vec::new();
|
||||||
|
|
||||||
|
// Top argument is the frame ptr; copy it to the rstack:
|
||||||
|
self.emit("pushr");
|
||||||
|
|
||||||
// Add each argument as a local
|
// Add each argument as a local
|
||||||
for name in function.args.iter() {
|
for name in function.args.iter() {
|
||||||
self.add_local(name.as_str())?;
|
self.add_local(name.as_str())?;
|
||||||
@@ -103,7 +106,7 @@ impl CompiledFn {
|
|||||||
|
|
||||||
for name in arg_names {
|
for name in arg_names {
|
||||||
if let Variable::Local(offset) = self.local_scope[name] {
|
if let Variable::Local(offset) = self.local_scope[name] {
|
||||||
self.emit("loadw frame");
|
self.emit("peekr");
|
||||||
if offset != 0 {
|
if offset != 0 {
|
||||||
self.emit_arg("add", offset);
|
self.emit_arg("add", offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ pub fn build_boot(src: &str) -> Result<Vec<String>, CompileError> {
|
|||||||
// Now we start piling stuff into the vec, starting with an org:
|
// Now we start piling stuff into the vec, starting with an org:
|
||||||
asm.push(".org 0x400".into());
|
asm.push(".org 0x400".into());
|
||||||
|
|
||||||
|
// Main takes no args, but it does take a frame ptr:
|
||||||
|
asm.push("push stack".into());
|
||||||
|
|
||||||
// jmp into main:
|
// jmp into main:
|
||||||
asm.push(format!("call {}", label));
|
asm.push(format!("call {}", label));
|
||||||
|
|
||||||
@@ -48,8 +51,7 @@ pub fn build_boot(src: &str) -> Result<Vec<String>, CompileError> {
|
|||||||
|
|
||||||
// Final thing is to place a label for the stack:
|
// Final thing is to place a label for the stack:
|
||||||
// (this is just a cell with the address of the following word)
|
// (this is just a cell with the address of the following word)
|
||||||
asm.push("frame: .db $+1".into());
|
asm.push("stack: .db 0".into());
|
||||||
asm.push(".db 0".into());
|
|
||||||
Ok(asm)
|
Ok(asm)
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError(0, 0, "Function main not defined (or not a function)".into()))
|
Err(CompileError(0, 0, "Function main not defined (or not a function)".into()))
|
||||||
@@ -68,27 +70,33 @@ mod test {
|
|||||||
let asm = build_boot("fn main() { return 5; }".into()).unwrap();
|
let asm = build_boot("fn main() { return 5; }".into()).unwrap();
|
||||||
assert_eq!(asm.join("\n"), vec![
|
assert_eq!(asm.join("\n"), vec![
|
||||||
".org 0x400",
|
".org 0x400",
|
||||||
|
"push stack",
|
||||||
"call _forge_gensym_1",
|
"call _forge_gensym_1",
|
||||||
"hlt",
|
"hlt",
|
||||||
"_forge_gensym_1:",
|
"_forge_gensym_1:",
|
||||||
|
"pushr",
|
||||||
"push 5",
|
"push 5",
|
||||||
|
"popr",
|
||||||
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
"frame: .db $+1",
|
"stack: .db 0",
|
||||||
".db 0",
|
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
|
|
||||||
// Slightly more complicated, with a global str
|
// Slightly more complicated, with a global str
|
||||||
let asm = build_boot("const str = \"blah\"; fn main() { return str; }".into()).unwrap();
|
let asm = build_boot("const str = \"blah\"; fn main() { return str; }".into()).unwrap();
|
||||||
assert_eq!(asm.join("\n"), vec![
|
assert_eq!(asm.join("\n"), vec![
|
||||||
".org 0x400",
|
".org 0x400",
|
||||||
|
"push stack",
|
||||||
"call _forge_gensym_2",
|
"call _forge_gensym_2",
|
||||||
"hlt",
|
"hlt",
|
||||||
"_forge_gensym_1: .db \"blah\\0\"",
|
"_forge_gensym_1: .db \"blah\\0\"",
|
||||||
"_forge_gensym_2:",
|
"_forge_gensym_2:",
|
||||||
|
"pushr",
|
||||||
"push _forge_gensym_1",
|
"push _forge_gensym_1",
|
||||||
|
"popr",
|
||||||
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
"frame: .db $+1",
|
"stack: .db 0",
|
||||||
".db 0",
|
|
||||||
].join("\n"))
|
].join("\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user