implicit return for functions

This commit is contained in:
prod2 2022-02-09 06:47:00 +01:00
parent a16026b364
commit 431e8f9a66
8 changed files with 51 additions and 60 deletions

View File

@ -34,12 +34,6 @@ proc parseArgs(comp: Compiler): int =
proc parseCall(comp: Compiler) = proc parseCall(comp: Compiler) =
# ( consumed # ( consumed
# create the call env
# current stack before opCall:
# ... <funct obj> <arg1> <arg2> <arg3>
# opCall converts it to this
# ... <ret val> <arg1> <arg2> <arg3>
let argcount = comp.parseArgs() let argcount = comp.parseArgs()
# emit call # emit call

View File

@ -18,22 +18,17 @@ proc beginScope*(comp: Compiler, function: bool = false) =
when debugCompiler: when debugCompiler:
debugEcho &"Begin scope called for depth {comp.scopes.len} function? {function}" debugEcho &"Begin scope called for depth {comp.scopes.len} function? {function}"
if function: if not function:
scope.labels.add("result")
scope.labels.add("function")
else:
while comp.match(tkLabel): while comp.match(tkLabel):
let label = comp.previous.text[1..^1] let label = comp.previous.text[1..^1]
scope.labels.add(label) scope.labels.add(label)
if function:
# if it's a function scope, the frame will move
# access to outside locals is also limited to upvalues and closures
comp.stackIndex = 0
else:
# only put the opNil if it's not a function scope, since # only put the opNil if it's not a function scope, since
# function scopes are initialized by the caller # function scopes are initialized by the caller
comp.writeChunk(1, opNil) comp.writeChunk(1, opNil)
else:
# if it's a function scope, the frame will move
# access to outside locals is also limited to upvalues and closures
comp.stackIndex = 0
for label in scope.labels: for label in scope.labels:
comp.addLocal(&":{label}", delta = 0) comp.addLocal(&":{label}", delta = 0)
@ -48,12 +43,12 @@ proc restore*(comp: Compiler, scope: Scope) =
debugEcho &"Restored scope: delta {delta}" debugEcho &"Restored scope: delta {delta}"
proc restoreInFunct*(comp: Compiler, scope: Scope) = proc restoreInFunct*(comp: Compiler, scope: Scope) =
let pops = comp.stackIndex #let pops = comp.stackIndex
comp.writePops(pops) #comp.writePops(pops)
comp.stackIndex = scope.goalStackIndex comp.stackIndex = scope.goalStackIndex
when debugCompiler: #when debugCompiler:
debugEcho &"Restored function scope: delta {pops}; new stackindex: {comp.stackIndex}" # debugEcho &"Restored function scope: delta {pops}; new stackindex: {comp.stackIndex}"
proc jumpToEnd*(comp: Compiler, scope: Scope) = proc jumpToEnd*(comp: Compiler, scope: Scope) =
## Jumps to the end of scope, does not affect stackIndex ## Jumps to the end of scope, does not affect stackIndex
@ -93,6 +88,10 @@ proc endScope*(comp: Compiler): Scope =
comp.restore(popped) comp.restore(popped)
# patch jumps to after the scope (such jumps from breaks emit the pops before jumping) # patch jumps to after the scope (such jumps from breaks emit the pops before jumping)
for jump in popped.jumps: for jump in popped.jumps:
when assertionsCompiler:
if function:
# all jumps should only happen to named block expressions
comp.error("Assertion failed: jump attempt to end function.")
comp.patchJump(jump, popped.goalStackIndex) comp.patchJump(jump, popped.goalStackIndex)
if function: if function:
comp.writeChunk(0, opReturn) comp.writeChunk(0, opReturn)

View File

@ -226,7 +226,12 @@ proc run*(chunk: Chunk): InterpretResult =
if frames.len() == 1: if frames.len() == 1:
break break
else: else:
ip = frames.pop().returnIp # remove frame that's over let retval = stack.pop()
let oldframe = frames.pop()
ip = oldframe.returnIp # remove frame that's over
let length = stack.len() - oldframe.stackBottom
stack.deleteTopN(length)
stack.push(retval)
of opTrue: of opTrue:
stack.add(fromBool(true)) stack.add(fromBool(true))
of opFalse: of opFalse:
@ -303,15 +308,8 @@ proc run*(chunk: Chunk): InterpretResult =
runtimeError(&"Wrong number of arguments, expected {arity}, got {argcount}.") runtimeError(&"Wrong number of arguments, expected {arity}, got {argcount}.")
break break
of opCall: of opCall:
# create the call env
# current stack before opCall:
# ... <funct obj> <arg1> <arg2> <arg3>
# opCall converts it to this
# ... <ret val> <arg1> <arg2> <arg3>
let argcount = ip.readUI8() let argcount = ip.readUI8()
let funct = stack.getIndexNeg(argcount) let funct = stack.getIndexNeg(argcount)
stack.setIndexNeg(argcount, fromNil()) # replace the function with nil: this is the return value slot
funct.call(argcount): funct.call(argcount):
break break
of opCreateList: of opCreateList:

View File

@ -44,13 +44,13 @@
//expect:5.0 //expect:5.0
var f = funct() { var f = funct() { @result
var y = 1; var y = 1;
var z = 3; var z = 3;
var p = 1; var p = 1;
:result = y + (z + p); :result = y + (z + p);
{ {
break @function; break @result;
}; };
:result = 10; :result = 10;
}; };
@ -60,7 +60,7 @@ print (f());
//expect:15.0 //expect:15.0
f = funct(m, n) f = funct(m, n)
:result = m + n m + n
; ;
print (f(f(5, 5), 5)); print (f(f(5, 5), 5));
@ -69,7 +69,7 @@ print (f(f(5, 5), 5));
//expect:10.0 //expect:10.0
var g = funct() var g = funct()
:result = {@a {@a
:a = { @b :a = { @b
:b = { @c :b = { @c
:c = 10; :c = 10;
@ -83,7 +83,7 @@ print (g());
//expect:9.0 //expect:9.0
var h = funct() var h = funct()
:result = {@a {@a
:a = { @b :a = { @b
:b = { @c :b = { @c
:a = 3; :a = 3;

View File

@ -1,16 +1,16 @@
// cascade // cascade
var f1 = funct() { var f1 = funct() { @result
var x = 1; var x = 1;
var y = 5; var y = 5;
:result = funct() { :result = funct() { @result
var z = 8; var z = 8;
print (x); print (x);
x = x + 1; x = x + 1;
:result = funct() { :result = funct() { @result
print (x); print (x);
x = x + 1; x = x + 1;
:result = funct() { :result = funct() { @result
print (x); print (x);
print (y); print (y);
print (z); print (z);
@ -33,7 +33,7 @@ f1()()()()();
// capturing closures in lists: // capturing closures in lists:
var f = funct() { var f = funct() { @result
var y = 5; var y = 5;
var x = @[ var x = @[
funct() print (y), funct() print (y),
@ -52,7 +52,7 @@ inst[0]();
// multiple different labels // multiple different labels
var f2 = funct() { var f2 = funct() { @result
var x = { @a @b var x = { @a @b
// this captures the internal value, not whatever it returns is assigned to // this captures the internal value, not whatever it returns is assigned to
:result = @{ :result = @{
@ -73,7 +73,7 @@ inst2["get"]();
// capturing args // capturing args
var argcap = funct(n) var argcap = funct(n)
:result = funct() print (n) funct() print (n)
; ;
//expect:8.1 //expect:8.1
@ -82,12 +82,12 @@ argcap(8.1)();
// oop: constructors, getters, setters // oop: constructors, getters, setters
var newAnimal = funct(species, color) { var newAnimal = funct(species, color) { @result
var species = species; // copy it so that it's mutable, if args ever get immutable var species = species; // copy it so that it's mutable, if args ever get immutable
var animal = @{ var animal = @{
["getSpecies"] = funct() :result = species, ["getSpecies"] = funct() species,
["setSpecies"] = funct(newSpecies) species = newSpecies, ["setSpecies"] = funct(newSpecies) species = newSpecies,
["getColor"] = funct() :result = color, // this captures an argument directly ["getColor"] = funct() color, // this captures an argument directly
}; };
:result = animal; :result = animal;
}; };
@ -116,7 +116,7 @@ print (turtle["getSpecies"]());
// 1: // 1:
var makeClosure = funct(value) { var makeClosure = funct(value) { @result
var closure = funct() { var closure = funct() {
print (value); print (value);
}; };
@ -132,9 +132,9 @@ bagel();
// 2: (multi level closures) // 2: (multi level closures)
var outer = funct() { var outer = funct() { @result
var x = "value"; var x = "value";
var middle = funct() { var middle = funct() { @result
var inner = funct() { var inner = funct() {
print (x); print (x);
}; };
@ -157,7 +157,7 @@ in();
// 3: (mixed multi level closures) // 3: (mixed multi level closures)
outer = funct() { outer = funct() { @result
var a = 1; var a = 1;
var b = 2; var b = 2;
var result; var result;
@ -170,7 +170,7 @@ outer = funct() {
result = inner; result = inner;
}; };
middle(); middle();
:result = funct() :result = result; :result = funct() result;
}; };
//expect:10.0 //expect:10.0
@ -238,7 +238,7 @@ globalGet();
// bonus: the last one with a list twist // bonus: the last one with a list twist
var bonus = funct() { var bonus = funct() { @result
var a = 1; var a = 1;
var f = funct() { var f = funct() {
print (a); print (a);

View File

@ -1,8 +1,8 @@
// a test about collections, WIP // a test about collections, WIP
var returnlist = funct() { var returnlist = funct()
:result = @[1, 2, 3, 4]; @[1, 2, 3, 4]
}; ;
//expect:3.0 //expect:3.0
print (returnlist()[2]); print (returnlist()[2]);

View File

@ -15,7 +15,7 @@ print (-((3 + 2) * 2) + 1);
// calls and indexes // calls and indexes
var returnlist = funct() { var returnlist = funct() { @result
:result = @[]; :result = @[];
:result[0] = 4; :result[0] = 4;
:result[1] = 6; :result[1] = 6;
@ -27,9 +27,9 @@ var returnlist = funct() {
print (returnlist()[2]); print (returnlist()[2]);
// priority over unary // priority over unary
var truesayer = funct() { var truesayer = funct()
:result = true; true
}; ;
//expect:false //expect:false
print (!truesayer()); print (!truesayer());

View File

@ -3,11 +3,11 @@
// :: piping function call // :: piping function call
var double = funct(num) :result = num * 2; var double = funct(num) num * 2;
var four = 2 :: double(); var four = 2 :: double();
var multiply = funct(num, factor) :result = num * factor; var multiply = funct(num, factor) num * factor;
var six = 2 :: multiply(3); var six = 2 :: multiply(3);
@ -65,7 +65,7 @@ class->method;
var multiplier = @{ var multiplier = @{
multiple = 5, multiple = 5,
do = funct(self, arg) :result = self.multiple * arg, do = funct(self, arg) self.multiple * arg,
}; };
multiplier->do(7) :: print; multiplier->do(7) :: print;
@ -74,7 +74,7 @@ multiplier->do(7) :: print;
// -> method call syntax with :: - check for precedence // -> method call syntax with :: - check for precedence
var returner = @{ var returner = @{
method = funct(self) :result = funct(n) :result = n * 2 method = funct(self) funct(n) n * 2
}; };
1.7 :: returner->method :: print; 1.7 :: returner->method :: print;