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) =
|
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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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());
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue