Functions without explicit return statements
This commit is contained in:
@@ -69,6 +69,7 @@ mod test {
|
|||||||
"peekr", // Push the addr of x
|
"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",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
@@ -109,6 +110,7 @@ mod test {
|
|||||||
"popr", // Blow away old frame ptr
|
"popr", // Blow away old frame ptr
|
||||||
"pop",
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ impl Compilable for Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now we increment the frame ptr to right after the current frame:
|
// 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");
|
sig.emit("peekr");
|
||||||
let frame_size = sig.frame_size();
|
let frame_size = sig.frame_size();
|
||||||
if frame_size > 0 {
|
if frame_size > 0 {
|
||||||
@@ -31,29 +34,13 @@ impl Compilable for Call {
|
|||||||
//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
|
|
||||||
// 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:
|
// 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). What's left on our rstack now is our frame ptr,
|
||||||
// our frame pointer:
|
// which is what we want.
|
||||||
//sig.emit("popr");
|
|
||||||
//sig.emit("storew frame");
|
|
||||||
|
|
||||||
// And we're finished!
|
// And we're finished!
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -82,6 +69,7 @@ mod test {
|
|||||||
"push _forge_gensym_1", // evaluating target (this fn)
|
"push _forge_gensym_1", // evaluating target (this fn)
|
||||||
"call", // Actually make the call
|
"call", // Actually make the call
|
||||||
"pop", // expr-as-statement drops the evaluated value
|
"pop", // expr-as-statement drops the evaluated value
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ mod test {
|
|||||||
"push 1",
|
"push 1",
|
||||||
"peekr",
|
"peekr",
|
||||||
"storew", // The branch, x = 1
|
"storew", // The branch, x = 1
|
||||||
"#end"]
|
"#end",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -69,7 +71,9 @@ mod test {
|
|||||||
"push 7",
|
"push 7",
|
||||||
"peekr",
|
"peekr",
|
||||||
"storew", // x = 7
|
"storew", // x = 7
|
||||||
"#end"]
|
"#end",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ mod test {
|
|||||||
"peekr",
|
"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",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
@@ -184,6 +185,7 @@ mod test {
|
|||||||
"peekr",
|
"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",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
@@ -203,6 +205,7 @@ mod test {
|
|||||||
"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
|
||||||
"storew", // Store whatever's at 3 to 1000
|
"storew", // Store whatever's at 3 to 1000
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
@@ -219,6 +222,7 @@ mod test {
|
|||||||
"add", // Add 3 to that address
|
"add", // Add 3 to that address
|
||||||
"peekr", // Store it in the first var
|
"peekr", // Store it in the first var
|
||||||
"storew",
|
"storew",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.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::compilable::Compilable;
|
||||||
use crate::compiler::compiled_fn::CompiledFn;
|
use crate::compiler::compiled_fn::CompiledFn;
|
||||||
use crate::compiler::CompileError;
|
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
|
// Compile the body, storing all of it in the CompiledFn we just created / added
|
||||||
self.body.process(state, Some(&mut sig), loc)?;
|
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
|
// This can't fail because if it were a dupe name, adding the global would have failed
|
||||||
state.functions.insert(self.name.clone(), sig);
|
state.functions.insert(self.name.clone(), sig);
|
||||||
|
|
||||||
@@ -58,6 +62,7 @@ mod test {
|
|||||||
"peekr", // 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
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ mod test {
|
|||||||
"popr", // toss old frame ptr
|
"popr", // toss old frame ptr
|
||||||
"pop",
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
@@ -173,6 +174,7 @@ mod test {
|
|||||||
"popr", // Toss old frame ptr
|
"popr", // Toss old frame ptr
|
||||||
"pop",
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
].join("\n")
|
].join("\n")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ mod test {
|
|||||||
"popr", // Toss frame ptr
|
"popr", // Toss frame ptr
|
||||||
"pop",
|
"pop",
|
||||||
"ret", // Return that
|
"ret", // Return that
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
@@ -74,6 +75,7 @@ mod test {
|
|||||||
"pop",
|
"pop",
|
||||||
"ret 0", // Default return value, for an expr-less return
|
"ret 0", // Default return value, for an expr-less return
|
||||||
"#end",
|
"#end",
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ mod test {
|
|||||||
"mul", // b * 2 evaluated
|
"mul", // b * 2 evaluated
|
||||||
"peekr", // Loading "a" as an lvalue
|
"peekr", // Loading "a" as an lvalue
|
||||||
"storew", // doing the assignment
|
"storew", // doing the assignment
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ mod test {
|
|||||||
"peekr",
|
"peekr",
|
||||||
"add 3",
|
"add 3",
|
||||||
"storew", // c = c + 1
|
"storew", // c = c + 1
|
||||||
"#end" // End the loop body
|
"#end", // End the loop body
|
||||||
|
"popr", "pop", "ret 0" // Implicit void return
|
||||||
]
|
]
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ mod test {
|
|||||||
"popr",
|
"popr",
|
||||||
"pop",
|
"pop",
|
||||||
"ret",
|
"ret",
|
||||||
|
"popr", "pop", "ret 0", // Implicit void return
|
||||||
"stack: .db 0",
|
"stack: .db 0",
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
|
|
||||||
@@ -96,6 +97,38 @@ mod test {
|
|||||||
"popr",
|
"popr",
|
||||||
"pop",
|
"pop",
|
||||||
"ret",
|
"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",
|
"stack: .db 0",
|
||||||
].join("\n"))
|
].join("\n"))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user