Various fixes and stack frame changes

This commit is contained in:
Mattia Giambirtone 2022-05-29 17:04:19 +02:00
parent b0515d3573
commit 9dacda4009
5 changed files with 40 additions and 33 deletions

View File

@ -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,

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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!