Fixed a bug where regular functions were mistaken for closures

This commit is contained in:
Mattia Giambirtone 2022-10-08 15:48:26 +02:00
parent ca5a1c1bc9
commit 3e6e9da475
3 changed files with 13 additions and 8 deletions

View File

@ -31,7 +31,7 @@ when debugVM or debugMem or debugGC:
import std/terminal
{.push checks:not disableVMChecks.} # The VM is a critical point where checks are deleterious
{.push checks:enableVMChecks.} # The VM is a critical point where checks are deleterious
type
PeonVM* = ref object
@ -339,10 +339,10 @@ proc newPeonVM*: PeonVM =
result.initCache()
result.gc = newPeonGC()
result.frames = @[]
result.calls = @[]
result.operands = @[]
result.results = @[]
result.envs = @[]
result.calls = @[]
result.gc.vm = result
@ -625,7 +625,7 @@ when debugVM: # So nim shuts up
stdout.styledWrite(fgGreen, "Call Stack: ", fgMagenta, "[")
for i, e in self.calls:
stdout.styledWrite(fgYellow, $e)
if i < self.calls.high():
if i < self.calls.len():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
if self.operands.len() !> 0:
@ -709,8 +709,6 @@ proc dispatch*(self: PeonVM) =
of LoadUInt8:
self.push(uint64(self.constReadUInt8(int(self.readLong()))))
of LoadString:
# TODO: Use constReadString with own memory manager
# Strings are broken rn!!
self.push(cast[uint64](self.constReadString(int(self.readLong()), int(self.readLong()))))
# We cast instead of converting because, unlike with integers,
# we don't want nim to touch any of the bits of the underlying

View File

@ -27,7 +27,7 @@ const debugStressGC* {.booldefine.} = false # Make the GC run a collection at
const PeonBytecodeMarker* = "PEON_BYTECODE" # Magic value at the beginning of bytecode files
const HeapGrowFactor* = 2 # The growth factor used by the GC to schedule the next collection
const FirstGC* = 1024 * 1024; # How many bytes to allocate before running the first GC
const disableVMChecks* {.booldefine.} = true; # Disables all types of compiler (nim-wise) checks in the VM
const enableVMChecks* {.booldefine.} = true; # Enables all types of compiler (nim-wise) checks in the VM
when HeapGrowFactor <= 1:
{.fatal: "Heap growth factor must be > 1".}
const PeonVersion* = (major: 0, minor: 1, patch: 0)
@ -35,7 +35,7 @@ const PeonRelease* = "alpha"
const PeonCommitHash* = "9884975fbd0bd2880f0969d21ee7b6ae44ecbafa"
when len(PeonCommitHash) != 40:
{.fatal: "The git commit hash must be exactly 40 characters long".}
const PeonBranch* = "master"
const PeonBranch* = "fixed-size-stack"
when len(PeonBranch) > 255 or len(PeonBranch) == 0:
{.fatal: "The git branch name's length must be within 1 and 255 characters".}
const PeonVersionString* = &"Peon {PeonVersion.major}.{PeonVersion.minor}.{PeonVersion.patch} {PeonRelease} ({PeonBranch}, {CompileDate}, {CompileTime}, {PeonCommitHash[0..8]}) [Nim {NimVersion}] on {hostOS} ({hostCPU})"

View File

@ -146,6 +146,8 @@ type
# The current scope depth. If > 0, we're
# in a local scope, otherwise it's global
scopeDepth: int
# Scope ownership data
scopeOwners: seq[tuple[owner: Name, depth: int]]
# The current function being compiled
currentFunction: Name
# Are optimizations turned on?
@ -237,6 +239,8 @@ proc newCompiler*(enableOptimizations: bool = true, replMode: bool = false): Com
result.compilerProcs["magic"] = handleMagicPragma
result.compilerProcs["pure"] = handlePurePragma
result.source = ""
result.scopeOwners = @[]
## Public getters for nicer error formatting
proc getCurrentNode*(self: Compiler): ASTNode = (if self.current >=
@ -1031,6 +1035,7 @@ proc beginScope(self: Compiler) =
## Begins a new local scope by incrementing the current
## scope's depth
inc(self.scopeDepth)
self.scopeOwners.add((self.currentFunction, self.scopeDepth))
proc `$`(self: Type): string = $self[]
@ -1053,6 +1058,7 @@ proc endScope(self: Compiler) =
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)
discard self.scopeOwners.pop()
var names: seq[Name] = @[]
var popCount = 0
for name in self.names:
@ -1346,6 +1352,7 @@ proc beginProgram(self: Compiler, incremental: bool = false): int =
isFunDecl: true,
line: -1)
self.names.add(main)
self.scopeOwners.add((main, 0))
self.emitByte(LoadInt64, 1)
self.emitBytes(self.chunk.writeConstant(main.codePos.toLong()), 1)
self.emitByte(LoadUInt32, 1)
@ -1485,7 +1492,7 @@ proc identifier(self: Compiler, node: IdentExpr) =
# a location to jump to
self.emitByte(LoadInt64, node.token.line)
self.emitBytes(self.chunk.writeConstant(s.codePos.toLong()), node.token.line)
elif self.scopeDepth > 0 and not self.currentFunction.isNil() and s.depth != self.scopeDepth:
elif self.scopeDepth > 0 and not self.currentFunction.isNil() and s.depth != self.scopeDepth and self.scopeOwners[s.depth].owner != self.currentFunction:
# Loads a closure variable. Stored in a separate "closure array" in the VM that does not
# align its semantics with the call stack. This makes closures work as expected and is
# not much slower than indexing our stack (since they're both dynamic arrays at runtime anyway)