Various fixes and stack frame changes
This commit is contained in:
parent
b0515d3573
commit
9dacda4009
|
@ -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
|
||||
if self.frames.len() > 1:
|
||||
let frame = self.frames.pop()
|
||||
if self.frames.len() > 1:
|
||||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
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)
|
||||
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)
|
||||
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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
operator `+`(a: int): int {
|
||||
operator `-`(a: int): int {
|
||||
return a;
|
||||
}
|
||||
|
||||
operator `+`(a: int32): int32 {
|
||||
return a;
|
||||
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!
|
||||
|
|
Loading…
Reference in New Issue