Functions without explicit return statements
This commit is contained in:
@@ -69,6 +69,7 @@ mod test {
|
||||
"peekr", // Push the addr of x
|
||||
"swap 12", // The asm body, which swaps 12 behind it and stores it there
|
||||
"storew",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
@@ -109,6 +110,7 @@ mod test {
|
||||
"popr", // Blow away old frame ptr
|
||||
"pop",
|
||||
"ret",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
@@ -17,6 +17,9 @@ impl Compilable for Call {
|
||||
}
|
||||
|
||||
// Now we increment the frame ptr to right after the current frame:
|
||||
// todo this messes with recursive calls: we're hard-coding the frame size _right now,_
|
||||
// which may increase later with later vardecls in the fn, which could be _executed_ before
|
||||
// this call is. We need to store the top of the frame at runtime somehow.
|
||||
sig.emit("peekr");
|
||||
let frame_size = sig.frame_size();
|
||||
if frame_size > 0 {
|
||||
@@ -31,29 +34,13 @@ impl Compilable for Call {
|
||||
//sig.emit("loadw frame");
|
||||
//sig.emit("pushr");
|
||||
|
||||
// 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
|
||||
// every fn will stick the frame ptr it's given in the rstack in its preamble, and that any
|
||||
// vardecl will increment that ptr (that the top of the rstack is the end of the current
|
||||
// frame, essentially). Returns also need to popr/pop before doing the actual ret.
|
||||
// todo also for that matter, that means that the frame ptr no longer needs to be a global
|
||||
// symbol: have it be stored in the rstack and passed as the first param in a call. So the
|
||||
// calling convention is, push the args, push the new fn's frame ptr (current top-of-frame+1),
|
||||
// call. The receiving fn puts its frame ptr into the rstack, dups it there, puts the args
|
||||
// (it knows its own arity) into its frame, and then every vardecl grabs the 2nd thing from r,
|
||||
// increments it by whatever, and puts it back.
|
||||
// todo in fact, a larger refactor would just store the frame size as the first thing in the
|
||||
// frame, to make vardecls faster
|
||||
|
||||
// Do the call:
|
||||
sig.emit("call");
|
||||
|
||||
// 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
|
||||
// this expr::call will end up evaluating to). But before we're done, we need to restore
|
||||
// our frame pointer:
|
||||
//sig.emit("popr");
|
||||
//sig.emit("storew frame");
|
||||
// this expr::call will end up evaluating to). What's left on our rstack now is our frame ptr,
|
||||
// which is what we want.
|
||||
|
||||
// And we're finished!
|
||||
Ok(())
|
||||
@@ -82,6 +69,7 @@ mod test {
|
||||
"push _forge_gensym_1", // evaluating target (this fn)
|
||||
"call", // Actually make the call
|
||||
"pop", // expr-as-statement drops the evaluated value
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
@@ -43,7 +43,9 @@ mod test {
|
||||
"push 1",
|
||||
"peekr",
|
||||
"storew", // The branch, x = 1
|
||||
"#end"]
|
||||
"#end",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
}
|
||||
@@ -69,7 +71,9 @@ mod test {
|
||||
"push 7",
|
||||
"peekr",
|
||||
"storew", // x = 7
|
||||
"#end"]
|
||||
"#end",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -166,6 +166,7 @@ mod test {
|
||||
"peekr",
|
||||
"add 3", // the address of y (frame + 3) and put gensym_4 in it
|
||||
"storew",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
@@ -184,6 +185,7 @@ mod test {
|
||||
"peekr",
|
||||
"add 3", // the address of y (frame + 3) and put the addr of x (frame) in it
|
||||
"storew",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
@@ -203,6 +205,7 @@ mod test {
|
||||
"loadw", // Then load the value at 3
|
||||
"push 1000", // Push the addr 1000, for the lvalue
|
||||
"storew", // Store whatever's at 3 to 1000
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
@@ -219,6 +222,7 @@ mod test {
|
||||
"add", // Add 3 to that address
|
||||
"peekr", // Store it in the first var
|
||||
"storew",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::ast::{Function, Location};
|
||||
use crate::ast::{Function, Location, Return};
|
||||
use crate::compiler::compilable::Compilable;
|
||||
use crate::compiler::compiled_fn::CompiledFn;
|
||||
use crate::compiler::CompileError;
|
||||
@@ -26,6 +26,10 @@ impl Compilable for Function {
|
||||
// Compile the body, storing all of it in the CompiledFn we just created / added
|
||||
self.body.process(state, Some(&mut sig), loc)?;
|
||||
|
||||
// This fn probably has a return statement... but it's not required. As a final catch just
|
||||
// in case we fall through to this point, we'll generate a void return and compile it:
|
||||
Return(None).process(state, Some(&mut sig), loc)?;
|
||||
|
||||
// This can't fail because if it were a dupe name, adding the global would have failed
|
||||
state.functions.insert(self.name.clone(), sig);
|
||||
|
||||
@@ -58,6 +62,7 @@ mod test {
|
||||
"peekr", // Calculate the lvalue
|
||||
"add 3", // "b" arg is frame + 3
|
||||
"storew", // Finally store
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
|
||||
@@ -132,6 +132,7 @@ mod test {
|
||||
"popr", // toss old frame ptr
|
||||
"pop",
|
||||
"ret",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
@@ -173,6 +174,7 @@ mod test {
|
||||
"popr", // Toss old frame ptr
|
||||
"pop",
|
||||
"ret",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
].join("\n")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ mod test {
|
||||
"popr", // Toss frame ptr
|
||||
"pop",
|
||||
"ret", // Return that
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
@@ -74,6 +75,7 @@ mod test {
|
||||
"pop",
|
||||
"ret 0", // Default return value, for an expr-less return
|
||||
"#end",
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
@@ -48,6 +48,7 @@ mod test {
|
||||
"mul", // b * 2 evaluated
|
||||
"peekr", // Loading "a" as an lvalue
|
||||
"storew", // doing the assignment
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
)
|
||||
|
||||
@@ -58,7 +58,8 @@ mod test {
|
||||
"peekr",
|
||||
"add 3",
|
||||
"storew", // c = c + 1
|
||||
"#end" // End the loop body
|
||||
"#end", // End the loop body
|
||||
"popr", "pop", "ret 0" // Implicit void return
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
@@ -79,6 +79,7 @@ mod test {
|
||||
"popr",
|
||||
"pop",
|
||||
"ret",
|
||||
"popr", "pop", "ret 0", // Implicit void return
|
||||
"stack: .db 0",
|
||||
].join("\n"));
|
||||
|
||||
@@ -96,6 +97,38 @@ mod test {
|
||||
"popr",
|
||||
"pop",
|
||||
"ret",
|
||||
"popr", "pop", "ret 0", // Implicit void return
|
||||
"stack: .db 0",
|
||||
].join("\n"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_global_vars() {
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_return() {
|
||||
let asm = build_boot("fn foo() { } fn main() { foo(); }".into()).unwrap();
|
||||
assert_eq!(asm.join("\n"), vec![
|
||||
".org 0x400",
|
||||
"push stack",
|
||||
"call _forge_gensym_2",
|
||||
"hlt",
|
||||
"_forge_gensym_1:", // fn foo()
|
||||
"pushr", // capture frame ptr
|
||||
"popr", // drop it and ret
|
||||
"pop",
|
||||
"ret 0",
|
||||
"_forge_gensym_2:", // fn main()
|
||||
"pushr", // capture frame ptr
|
||||
"peekr", // prep frame ptr to send to foo
|
||||
"push _forge_gensym_1", // load foo
|
||||
"call", // call it
|
||||
"pop", // Throw away its return value
|
||||
"popr", // drop frame ptr and ret
|
||||
"pop",
|
||||
"ret 0",
|
||||
"stack: .db 0",
|
||||
].join("\n"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user