Storing the frame pointer in the rstack

This commit is contained in:
2023-11-11 18:08:54 -06:00
parent 89560573ec
commit 45fe27b823
12 changed files with 133 additions and 92 deletions
+10 -6
View File
@@ -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")
+20 -24
View File
@@ -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")
+14 -10
View File
@@ -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
] ]
+1 -1
View File
@@ -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")
); );
+19 -4
View File
@@ -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")
); );
+5 -2
View File
@@ -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);
} }
+14 -6
View File
@@ -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"))
} }
} }