implicit return for functions
This commit is contained in:
parent
a16026b364
commit
431e8f9a66
|
@ -34,12 +34,6 @@ proc parseArgs(comp: Compiler): int =
|
|||
proc parseCall(comp: Compiler) =
|
||||
# ( 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()
|
||||
|
||||
# emit call
|
||||
|
|
|
@ -18,22 +18,17 @@ proc beginScope*(comp: Compiler, function: bool = false) =
|
|||
when debugCompiler:
|
||||
debugEcho &"Begin scope called for depth {comp.scopes.len} function? {function}"
|
||||
|
||||
if function:
|
||||
scope.labels.add("result")
|
||||
scope.labels.add("function")
|
||||
else:
|
||||
if not function:
|
||||
while comp.match(tkLabel):
|
||||
let label = comp.previous.text[1..^1]
|
||||
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
|
||||
# function scopes are initialized by the caller
|
||||
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:
|
||||
comp.addLocal(&":{label}", delta = 0)
|
||||
|
@ -48,12 +43,12 @@ proc restore*(comp: Compiler, scope: Scope) =
|
|||
debugEcho &"Restored scope: delta {delta}"
|
||||
|
||||
proc restoreInFunct*(comp: Compiler, scope: Scope) =
|
||||
let pops = comp.stackIndex
|
||||
comp.writePops(pops)
|
||||
#let pops = comp.stackIndex
|
||||
#comp.writePops(pops)
|
||||
|
||||
comp.stackIndex = scope.goalStackIndex
|
||||
when debugCompiler:
|
||||
debugEcho &"Restored function scope: delta {pops}; new stackindex: {comp.stackIndex}"
|
||||
#when debugCompiler:
|
||||
# debugEcho &"Restored function scope: delta {pops}; new stackindex: {comp.stackIndex}"
|
||||
|
||||
proc jumpToEnd*(comp: Compiler, scope: Scope) =
|
||||
## Jumps to the end of scope, does not affect stackIndex
|
||||
|
@ -93,6 +88,10 @@ proc endScope*(comp: Compiler): Scope =
|
|||
comp.restore(popped)
|
||||
# patch jumps to after the scope (such jumps from breaks emit the pops before jumping)
|
||||
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)
|
||||
if function:
|
||||
comp.writeChunk(0, opReturn)
|
||||
|
|
|
@ -226,7 +226,12 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
if frames.len() == 1:
|
||||
break
|
||||
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:
|
||||
stack.add(fromBool(true))
|
||||
of opFalse:
|
||||
|
@ -303,15 +308,8 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
runtimeError(&"Wrong number of arguments, expected {arity}, got {argcount}.")
|
||||
break
|
||||
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 funct = stack.getIndexNeg(argcount)
|
||||
|
||||
stack.setIndexNeg(argcount, fromNil()) # replace the function with nil: this is the return value slot
|
||||
funct.call(argcount):
|
||||
break
|
||||
of opCreateList:
|
||||
|
|
|
@ -44,13 +44,13 @@
|
|||
|
||||
//expect:5.0
|
||||
|
||||
var f = funct() {
|
||||
var f = funct() { @result
|
||||
var y = 1;
|
||||
var z = 3;
|
||||
var p = 1;
|
||||
:result = y + (z + p);
|
||||
{
|
||||
break @function;
|
||||
break @result;
|
||||
};
|
||||
:result = 10;
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ print (f());
|
|||
//expect:15.0
|
||||
|
||||
f = funct(m, n)
|
||||
:result = m + n
|
||||
m + n
|
||||
;
|
||||
|
||||
print (f(f(5, 5), 5));
|
||||
|
@ -69,7 +69,7 @@ print (f(f(5, 5), 5));
|
|||
//expect:10.0
|
||||
|
||||
var g = funct()
|
||||
:result = {@a
|
||||
{@a
|
||||
:a = { @b
|
||||
:b = { @c
|
||||
:c = 10;
|
||||
|
@ -83,7 +83,7 @@ print (g());
|
|||
//expect:9.0
|
||||
|
||||
var h = funct()
|
||||
:result = {@a
|
||||
{@a
|
||||
:a = { @b
|
||||
:b = { @c
|
||||
:a = 3;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
// cascade
|
||||
|
||||
var f1 = funct() {
|
||||
var f1 = funct() { @result
|
||||
var x = 1;
|
||||
var y = 5;
|
||||
:result = funct() {
|
||||
:result = funct() { @result
|
||||
var z = 8;
|
||||
print (x);
|
||||
x = x + 1;
|
||||
:result = funct() {
|
||||
:result = funct() { @result
|
||||
print (x);
|
||||
x = x + 1;
|
||||
:result = funct() {
|
||||
:result = funct() { @result
|
||||
print (x);
|
||||
print (y);
|
||||
print (z);
|
||||
|
@ -33,7 +33,7 @@ f1()()()()();
|
|||
|
||||
// capturing closures in lists:
|
||||
|
||||
var f = funct() {
|
||||
var f = funct() { @result
|
||||
var y = 5;
|
||||
var x = @[
|
||||
funct() print (y),
|
||||
|
@ -52,7 +52,7 @@ inst[0]();
|
|||
|
||||
// multiple different labels
|
||||
|
||||
var f2 = funct() {
|
||||
var f2 = funct() { @result
|
||||
var x = { @a @b
|
||||
// this captures the internal value, not whatever it returns is assigned to
|
||||
:result = @{
|
||||
|
@ -73,7 +73,7 @@ inst2["get"]();
|
|||
// capturing args
|
||||
|
||||
var argcap = funct(n)
|
||||
:result = funct() print (n)
|
||||
funct() print (n)
|
||||
;
|
||||
|
||||
//expect:8.1
|
||||
|
@ -82,12 +82,12 @@ argcap(8.1)();
|
|||
|
||||
// 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 animal = @{
|
||||
["getSpecies"] = funct() :result = species,
|
||||
["getSpecies"] = funct() species,
|
||||
["setSpecies"] = funct(newSpecies) species = newSpecies,
|
||||
["getColor"] = funct() :result = color, // this captures an argument directly
|
||||
["getColor"] = funct() color, // this captures an argument directly
|
||||
};
|
||||
:result = animal;
|
||||
};
|
||||
|
@ -116,7 +116,7 @@ print (turtle["getSpecies"]());
|
|||
|
||||
// 1:
|
||||
|
||||
var makeClosure = funct(value) {
|
||||
var makeClosure = funct(value) { @result
|
||||
var closure = funct() {
|
||||
print (value);
|
||||
};
|
||||
|
@ -132,9 +132,9 @@ bagel();
|
|||
|
||||
// 2: (multi level closures)
|
||||
|
||||
var outer = funct() {
|
||||
var outer = funct() { @result
|
||||
var x = "value";
|
||||
var middle = funct() {
|
||||
var middle = funct() { @result
|
||||
var inner = funct() {
|
||||
print (x);
|
||||
};
|
||||
|
@ -157,7 +157,7 @@ in();
|
|||
|
||||
// 3: (mixed multi level closures)
|
||||
|
||||
outer = funct() {
|
||||
outer = funct() { @result
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
var result;
|
||||
|
@ -170,7 +170,7 @@ outer = funct() {
|
|||
result = inner;
|
||||
};
|
||||
middle();
|
||||
:result = funct() :result = result;
|
||||
:result = funct() result;
|
||||
};
|
||||
|
||||
//expect:10.0
|
||||
|
@ -238,7 +238,7 @@ globalGet();
|
|||
|
||||
// bonus: the last one with a list twist
|
||||
|
||||
var bonus = funct() {
|
||||
var bonus = funct() { @result
|
||||
var a = 1;
|
||||
var f = funct() {
|
||||
print (a);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// a test about collections, WIP
|
||||
|
||||
var returnlist = funct() {
|
||||
:result = @[1, 2, 3, 4];
|
||||
};
|
||||
var returnlist = funct()
|
||||
@[1, 2, 3, 4]
|
||||
;
|
||||
|
||||
//expect:3.0
|
||||
print (returnlist()[2]);
|
||||
|
|
|
@ -15,7 +15,7 @@ print (-((3 + 2) * 2) + 1);
|
|||
|
||||
// calls and indexes
|
||||
|
||||
var returnlist = funct() {
|
||||
var returnlist = funct() { @result
|
||||
:result = @[];
|
||||
:result[0] = 4;
|
||||
:result[1] = 6;
|
||||
|
@ -27,9 +27,9 @@ var returnlist = funct() {
|
|||
print (returnlist()[2]);
|
||||
|
||||
// priority over unary
|
||||
var truesayer = funct() {
|
||||
:result = true;
|
||||
};
|
||||
var truesayer = funct()
|
||||
true
|
||||
;
|
||||
|
||||
//expect:false
|
||||
print (!truesayer());
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
// :: piping function call
|
||||
|
||||
var double = funct(num) :result = num * 2;
|
||||
var double = funct(num) num * 2;
|
||||
|
||||
var four = 2 :: double();
|
||||
|
||||
var multiply = funct(num, factor) :result = num * factor;
|
||||
var multiply = funct(num, factor) num * factor;
|
||||
|
||||
var six = 2 :: multiply(3);
|
||||
|
||||
|
@ -65,7 +65,7 @@ class->method;
|
|||
|
||||
var multiplier = @{
|
||||
multiple = 5,
|
||||
do = funct(self, arg) :result = self.multiple * arg,
|
||||
do = funct(self, arg) self.multiple * arg,
|
||||
};
|
||||
|
||||
multiplier->do(7) :: print;
|
||||
|
@ -74,7 +74,7 @@ multiplier->do(7) :: print;
|
|||
// -> method call syntax with :: - check for precedence
|
||||
|
||||
var returner = @{
|
||||
method = funct(self) :result = funct(n) :result = n * 2
|
||||
method = funct(self) funct(n) n * 2
|
||||
};
|
||||
|
||||
1.7 :: returner->method :: print;
|
||||
|
|
Loading…
Reference in New Issue