From 9dacda40091829327ed7ac71574396a7d32287c1 Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Sun, 29 May 2022 17:04:19 +0200 Subject: [PATCH] Various fixes and stack frame changes --- src/backend/vm.nim | 8 ++++--- src/config.nim | 2 +- src/frontend/compiler.nim | 47 ++++++++++++++++++++++++--------------- src/util/debugger.nim | 1 + tests/dispatch.pn | 15 ++++--------- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/backend/vm.nim b/src/backend/vm.nim index 4c291d0..f7c09dc 100644 --- a/src/backend/vm.nim +++ b/src/backend/vm.nim @@ -191,9 +191,9 @@ proc dispatch*(self: PeonVM) = instruction = OpCode(self.readByte()) when DEBUG_TRACE_VM: echo &"IP: {self.ip}" - echo &"SP: {self.stack.high()}" - echo &"Stack: {self.stack}" echo &"Instruction: {instruction}" + echo &"Stack: {self.stack}" + echo &"Current Frame: {self.stack[self.frames[^1]..^1]}" discard readLine stdin case instruction: # Constant loading @@ -228,12 +228,14 @@ proc dispatch*(self: PeonVM) = of OpCode.Return: # Returns from a void function or terminates the # program entirely if we're at the topmost frame + let frame = self.frames.pop() if self.frames.len() > 1: - let frame = self.frames.pop() for i in countdown(self.stack.high(), frame): discard self.pop() self.ip = int(self.pop().uInt) else: + while self.stack.len() > 0: + discard self.pop() return of ReturnValue: # Returns from a function which has a return value, diff --git a/src/config.nim b/src/config.nim index 1fda235..6014eb9 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 b1c7f8a..0d7d425 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -51,6 +51,8 @@ type of Function: name: string isLambda: bool + isGenerator: bool + isCoroutine: bool args: seq[tuple[name: string, kind: Type]] returnType: Type of Mutable, Reference, Pointer: @@ -153,6 +155,11 @@ type closedOver: seq[Name] +proc `$`(self: Name): string = + ## Stringifies a name object + result &= &"Name(name='{self.name}', depth={self.depth}, owner='{self.owner}', private={self.isPrivate}, let={self.isLet}, const={self.isConst}" + result &= &", pos={self.codePos}, closure={self.isClosedOver}, line={self.line})" + proc newCompiler*(enableOptimizations: bool = true): Compiler = ## Initializes a new Compiler object @@ -902,7 +909,7 @@ proc declareName(self: Compiler, node: Declaration) = isConst: false, name: argument.name, valueType: nil, - codePos: self.chunk.code.len(), + codePos: 0, isLet: false, isClosedOver: false) self.names.add(name) @@ -945,8 +952,6 @@ proc identifier(self: Compiler, node: IdentExpr) = if not t.closedOver: # Static name resolution, loads value at index in the stack. Very fast. Much wow. self.emitByte(LoadVar) - if self.scopeDepth > 0: - inc(index) # Skip the return address! self.emitBytes((index - self.frames[self.scopeDepth]).toTriple()) else: # Heap-allocated closure variable. Stored in a separate "closure array" in the VM that does not have stack semantics. @@ -1014,21 +1019,23 @@ proc beginScope(self: Compiler) = proc endScope(self: Compiler) = ## Ends the current local scope - if self.scopeDepth == 0: - self.error("cannot call endScope with scopeDepth == 0 (This is an internal error and most likely a bug)") + if self.scopeDepth < 0: + self.error("cannot call endScope with scopeDepth < 0 (This is an internal error and most likely a bug)") dec(self.scopeDepth) var popped: int = 0 var name: Name + var indeces: seq[int] = @[] for i, ident in reversed(self.names): - if ident.depth > self.scopeDepth: + if ident.depth > self.scopeDepth and ident.valueType.kind != TypeKind.Function: inc(popped) name = self.names[self.names.high() - i] if name.valueType.kind != Function and OpCode(self.chunk.code[name.codePos]) == NoOp: - self.chunk.code.delete(name.codePos) - self.chunk.code.delete(name.codePos + 1) - self.chunk.code.delete(name.codePos + 2) - self.chunk.code.delete(name.codePos + 3) - self.names.delete(self.names.len() - i) + for _ in countup(0, 3): + # Since by deleting it the size of the + # sequence decreases, we don't need to + # increase the index + self.chunk.code.delete(name.codePos) + indeces.add(self.names.high() - i) if not self.enableOptimizations: # All variables with a scope depth larger than the current one # are now out of scope. Begone, you're now homeless! @@ -1053,6 +1060,8 @@ proc endScope(self: Compiler) = elif popped == 1: # We only emit PopN if we're popping more than one value self.emitByte(Pop) + for index in indeces: + self.names.delete(index) proc blockStmt(self: Compiler, node: BlockStmt) = @@ -1308,13 +1317,15 @@ proc statement(self: Compiler, node: Statement) = proc varDecl(self: Compiler, node: VarDecl) = ## Compiles variable declarations - let kind = self.inferType(node.valueType) - let typ = self.inferType(node.value) - if kind == nil and typ == nil: + let expected = self.inferType(node.valueType) + let actual = self.inferType(node.value) + if expected == nil and actual == nil: self.error(&"'{node.name.token.lexeme}' has no type") - elif not self.compareTypes(typ, kind): - if kind != nil: - self.error(&"expected value of type '{self.typeToStr(kind)}', but '{node.name.token.lexeme}' is of type '{self.typeToStr(typ)}'") + elif expected.kind == Mutable: # I mean, variables *are* already mutable (some of them anyway) + self.error(&"invalid type '{self.typeToStr(expected)}' for var") + elif not self.compareTypes(expected, actual): + if expected != nil: + 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) @@ -1448,4 +1459,4 @@ proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk = result = self.chunk if self.ast.len() > 0 and self.scopeDepth != 0: self.error(&"invalid state: invalid scopeDepth value (expected 0, got {self.scopeDepth}), did you forget to call endScope/beginScope?") - + self.endScope() diff --git a/src/util/debugger.nim b/src/util/debugger.nim index 2529145..d860dca 100644 --- a/src/util/debugger.nim +++ b/src/util/debugger.nim @@ -63,6 +63,7 @@ proc printInstruction(instruction: OpCode, newline: bool = false) = proc checkFrameStart(self: Debugger, n: int) = + return for i, e in self.cfiData: if n == e.start and not (e.started or e.stopped): e.started = true diff --git a/tests/dispatch.pn b/tests/dispatch.pn index 0631a8f..2257eec 100644 --- a/tests/dispatch.pn +++ b/tests/dispatch.pn @@ -1,16 +1,9 @@ operator `+`(a: int): int { - return a; + operator `-`(a: int): int { + return a; + } + return -a; } -operator `+`(a: int32): int32 { - return a; -} - -fn `+`(a, b: int): int32 { - return 0'i32; # Just to test error messages -} - -var `+`: int = 1; # Can't call a value! +1; # Works: defined for int64 -+1'u8; # No implementation for uint8, error!