WIP closures, fix compiler bug
This commit is contained in:
parent
2f790067f3
commit
086c6e3c2e
|
@ -113,7 +113,7 @@ const argInstructions = {
|
|||
opPopA,
|
||||
opGetLocal, opSetLocal,
|
||||
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop,
|
||||
opFunctionDef, opClosure,
|
||||
opFunctionDef,
|
||||
opCreateList, opCreateTable,
|
||||
opGetUpvalue, opSetUpvalue,
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ proc disassembleChunk*(ch: Chunk) =
|
|||
of simpleInstructions:
|
||||
write stdout, ")\n"
|
||||
of shortArgInstructions:
|
||||
write stdout, &" {shortArg.toHex(2)}"
|
||||
write stdout, &" {shortArg.toHex(2)})\n"
|
||||
c += 1
|
||||
of argInstructions:
|
||||
write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n"
|
||||
|
@ -147,6 +147,18 @@ proc disassembleChunk*(ch: Chunk) =
|
|||
write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n"
|
||||
echo &" points to constant {ch.constants[i]} (i: {i})"
|
||||
c += 2
|
||||
of opClosure:
|
||||
let upvalCount = double.toInt
|
||||
c += 2
|
||||
write stdout, &" length: {upvalCount} [ "
|
||||
for i in countup(1, upvalCount):
|
||||
let index = double.toInt
|
||||
c += 2
|
||||
let local = shortArg.int
|
||||
c += 1
|
||||
write stdout, &"(i: {index} l: {local}) "
|
||||
write stdout, &"])\n"
|
||||
|
||||
except:
|
||||
echo &"[{cFmt}] {lineFmt} Unknown opcode {instruction}"
|
||||
c.inc
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import strformat
|
||||
import strutils
|
||||
import sequtils
|
||||
import sugar
|
||||
|
||||
import scanner
|
||||
|
@ -17,6 +18,10 @@ type
|
|||
# its depth will be set once its first ever value is determined
|
||||
scope: Scope # the innermost scope of this local
|
||||
|
||||
Upvalue = ref object
|
||||
index: int
|
||||
isLocal: bool
|
||||
|
||||
Scope = ref object
|
||||
labels: seq[string]
|
||||
goalStackIndex: int # the stack count it started with plus 1
|
||||
|
@ -24,6 +29,7 @@ type
|
|||
function: bool # if true, it is a function
|
||||
parentFunction: Scope # if not a function, which scope is the innermost function it's in (if it's a function this points to itself)
|
||||
# if parentFunction is nil, the scope is not inside a function
|
||||
upvalues: seq[Upvalue] # only needed for functions
|
||||
|
||||
Compiler = ref object
|
||||
#
|
||||
|
@ -299,12 +305,13 @@ proc jumpToEnd(comp: Compiler, scope: Scope) =
|
|||
let jmp = comp.emitJump(delta, opJump)
|
||||
scope.jumps.add(jmp)
|
||||
|
||||
proc endScope(comp: Compiler) =
|
||||
proc endScope(comp: Compiler): Scope =
|
||||
# remove locals
|
||||
let popped = comp.scopes.pop()
|
||||
if popped.parentFunction == popped:
|
||||
popped.parentFunction = nil # cleanup cycles
|
||||
let function = popped.function
|
||||
# restore the stackIndex, emit pops
|
||||
when debugCompiler:
|
||||
debugEcho &"End scope called for depth {comp.scopes.len} function? {function}"
|
||||
if function:
|
||||
|
@ -316,6 +323,9 @@ proc endScope(comp: Compiler) =
|
|||
comp.patchJump(jump)
|
||||
if function:
|
||||
comp.writeChunk(0, opReturn)
|
||||
# remove locals from the comp object that were of this scope
|
||||
comp.locals.keepIf((it) => it.depth < comp.scopes.len())
|
||||
popped
|
||||
|
||||
|
||||
# EXPRESSIONS
|
||||
|
@ -397,8 +407,25 @@ proc addUpvalue(comp: Compiler, index: int): int =
|
|||
## and creates an upvalue in every function up until the one
|
||||
## including this local so that all of the function scopes in between
|
||||
## have the right upvalue in them (compile time)
|
||||
comp.error("addupvalue not implemented yet")
|
||||
discard
|
||||
|
||||
template lenCheck(scope: Scope, blk: untyped) =
|
||||
if scope.upvalues.len() >= argMax:
|
||||
comp.error("Too many closure variables in function.")
|
||||
blk
|
||||
|
||||
let local = comp.locals[index]
|
||||
var scopeIndex = local.depth
|
||||
var isLocal = true
|
||||
var upvalIndex: int
|
||||
while scopeIndex < comp.scopes.len():
|
||||
let scope = comp.scopes[scopeIndex]
|
||||
if scope.function:
|
||||
scope.lenCheck():
|
||||
return 0
|
||||
scope.upvalues.add(Upvalue(index: if isLocal: index else: upvalIndex, isLocal: isLocal))
|
||||
isLocal = false
|
||||
upvalIndex = scope.upvalues.high()
|
||||
scopeIndex.inc
|
||||
|
||||
proc resolveLocal(comp: Compiler, name: string): tuple[index: int, upvalue: bool] =
|
||||
## the bool arg specifies whether it found an upvalue
|
||||
|
@ -684,11 +711,19 @@ proc parseFunct(comp: Compiler) =
|
|||
let shouldbeStackIndex = params.len + 1
|
||||
if shouldbeStackIndex != comp.stackIndex:
|
||||
comp.error(&"Assertion failed: wrong stackindex ({comp.stackIndex}) in function declaration (should be {shouldbeStackIndex}).")
|
||||
comp.endScope()
|
||||
let f = comp.endScope()
|
||||
dec comp.stackIndex # the previous end scope did not put anything on the stack, it is jumped over
|
||||
|
||||
# end of function declaration:
|
||||
comp.patchJump(jumpOverBody)
|
||||
# closures are implemented in a way, where the vm pops the function from the stack
|
||||
# and reads the upvalue details from the following bytes
|
||||
if f.upvalues.len() > 0:
|
||||
comp.writeChunk(0, opClosure)
|
||||
comp.writeChunk(0, f.upvalues.len().toDU8())
|
||||
for upval in f.upvalues:
|
||||
comp.writeChunk(0, upval.index.toDU8())
|
||||
comp.writeChunk(0, if upval.isLocal: 0'u8 else: 1'u8)
|
||||
|
||||
tkFunct.genRule(parseFunct, nop, pcNone)
|
||||
|
||||
|
@ -769,7 +804,7 @@ proc parseBlock(comp: Compiler) =
|
|||
comp.beginScope()
|
||||
while comp.current.tokenType != tkRightBrace and comp.current.tokenType != tkEof:
|
||||
comp.statement()
|
||||
comp.endScope()
|
||||
discard comp.endScope()
|
||||
|
||||
comp.consume(tkRightBrace, "Expect '}' after block.")
|
||||
|
||||
|
|
|
@ -222,10 +222,8 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
ip = ip.padd(offset)
|
||||
stack.push(faddr.fromFunct())
|
||||
of opClosure:
|
||||
let offset = ip.readDU8()
|
||||
let faddr: ptr uint8 = ip
|
||||
ip = ip.padd(offset)
|
||||
stack.push(newClosure[NdValue](faddr, 0).fromClosure())
|
||||
runtimeError("Closures are not implemented.")
|
||||
break
|
||||
of opCheckArity:
|
||||
let arity = ip.readUI8()
|
||||
let argcount = stack.high() - frameBottom
|
||||
|
|
|
@ -18,9 +18,9 @@ f()[0]();
|
|||
// capturing the result of a function:
|
||||
|
||||
var f2 = funct() {
|
||||
var x = { @f2
|
||||
var x = { @ftwo
|
||||
:result = funct() {
|
||||
print :f2;
|
||||
print :ftwo;
|
||||
};
|
||||
};
|
||||
x = 5;
|
||||
|
@ -31,8 +31,8 @@ f2()();
|
|||
|
||||
// oop: constructors, getters, setters
|
||||
|
||||
var newAnimal = funct(species, color) {
|
||||
var species = species; // copy it so that it's mutable, if args ever get immutable
|
||||
var newAnimal = funct(pspecies, color) {
|
||||
var species = pspecies; // copy it so that it's mutable, if args ever get immutable
|
||||
var animal = @{
|
||||
"getSpecies" = funct() :result = species,
|
||||
"setSpecies" = funct(newSpecies) species = newSpecies,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
var a = 5;
|
||||
{
|
||||
var a = 3;
|
||||
{
|
||||
var a = 2;
|
||||
print a;
|
||||
//expect:2.0
|
||||
};
|
||||
print a;
|
||||
//expect:3.0
|
||||
};
|
||||
print a;
|
||||
//expect:5.0
|
Loading…
Reference in New Issue