diff --git a/Makefile b/Makefile index f953db0..ce4b791 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -run: - nim --hints:off --warnings:off r src/test.nim +repl: + nim --hints:off --warnings:off r src/main.nim pretty: nimpretty src/*.nim src/backend/*.nim src/frontend/*.nim src/frontend/meta/*.nim src/memory/*.nim src/util/*.nim diff --git a/src/config.nim b/src/config.nim index 12c2291..218807b 100644 --- a/src/config.nim +++ b/src/config.nim @@ -27,7 +27,7 @@ when len(PEON_COMMIT_HASH) != 40: const PEON_BRANCH* = "master" when len(PEON_BRANCH) > 255: {.fatal: "The git branch name's length must be less than or equal to 255 characters".} -const DEBUG_TRACE_VM* = false # Traces VM execution +const DEBUG_TRACE_VM* = true # Traces VM execution const DEBUG_TRACE_GC* = false # Traces the garbage collector (TODO) const DEBUG_TRACE_ALLOCATION* = false # Traces memory allocation/deallocation const DEBUG_TRACE_COMPILER* = false # Traces the compiler diff --git a/src/frontend/compiler.nim b/src/frontend/compiler.nim index a7d668b..188ea4c 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -429,7 +429,7 @@ proc resolve(self: Compiler, name: string, return nil -proc detectClosureVariable(self: Compiler, name: var Name, depth: int = self.scopeDepth, decl: bool = false) = +proc detectClosureVariable(self: Compiler, name: var Name, depth: int = self.scopeDepth) = ## Detects if the given name is used in a local scope deeper ## than the given one and modifies the code emitted for it ## to store it as a closure variable if it is. Does nothing if the name @@ -438,7 +438,7 @@ proc detectClosureVariable(self: Compiler, name: var Name, depth: int = self.sco ## each time a name is referenced in order for closed-over variables ## to be emitted properly, otherwise the runtime may behave ## unpredictably or crash - if name.isNil() or name.depth == 0: + if name.isNil() or name.depth == 0 or name.isClosedOver: return elif name.depth < depth: # Ding! The given name is closed over: we need to @@ -446,14 +446,13 @@ proc detectClosureVariable(self: Compiler, name: var Name, depth: int = self.sco # put in place for us into a StoreClosure. We also update # the name's isClosedOver field so that self.identifier() # can emit a LoadClosure instruction instead of a LoadVar - if not name.isClosedOver: - self.closedOver.add(name) + self.closedOver.add(name) if self.closedOver.len() >= 16777216: self.error("too many consecutive closed-over variables (max is 16777215)") name.isClosedOver = true - if decl: - self.emitByte(StoreClosure) - self.emitBytes(self.closedOver.high().toTriple()) + self.chunk.code[name.codePos] = StoreClosure.uint8() + for i, b in self.closedOver.high().toTriple(): + self.chunk.code[name.codePos + i + 1] = b proc compareTypes(self: Compiler, a, b: Type): bool = @@ -1129,6 +1128,8 @@ proc identifier(self: Compiler, node: IdentExpr) = # no matter the scope depth self.emitConstant(node, self.inferType(node)) else: + self.emitByte(JumpForwards) + self.emitBytes(0.toTriple()) self.detectClosureVariable(s) if s.valueType.kind == Function: # Functions have no runtime @@ -1149,7 +1150,6 @@ proc identifier(self: Compiler, node: IdentExpr) = self.emitBytes(self.getClosurePos(s.name).toTriple()) - proc assignment(self: Compiler, node: ASTNode) = ## Compiles assignment expressions case node.kind: @@ -1583,10 +1583,8 @@ proc varDecl(self: Compiler, node: VarDecl) = self.error(&"expected value of type '{self.typeToStr(expected)}', but '{node.name.token.lexeme}' is of type '{self.typeToStr(actual)}'") self.expression(node.value) self.declareName(node, mutable=node.token.kind == TokenType.Var) - var r = self.names[^1] - self.detectClosureVariable(r, decl=true) self.emitByte(StoreVar) - self.emitBytes((self.getStackPos(r.name) + 1).toTriple()) + self.emitBytes((self.getStackPos(self.names[^1].name) + 1).toTriple()) proc typeDecl(self: Compiler, node: TypeDecl) = diff --git a/tests/closures.pn b/tests/closures.pn index df8bd06..4ab2777 100644 --- a/tests/closures.pn +++ b/tests/closures.pn @@ -1,8 +1,9 @@ fn makeClosure(n: int): fn: int { - fn inner: int { - return n; - } - return inner; + var n = n; + fn inner: int { + return n; + } + return inner; }