diff --git a/src/backend/vm.nim b/src/backend/vm.nim index 63b7718..640be27 100644 --- a/src/backend/vm.nim +++ b/src/backend/vm.nim @@ -822,9 +822,13 @@ proc dispatch*(self: var PeonVM) = # not a great idea) self.pushc(self.pop()) of LoadVar: - # Pushes a variable from the call stack + # Pushes a local variable from the call stack # onto the operand stack self.push(self.getc(self.readLong().int)) + of LoadGlobal: + # Pushes a global variable from the call stack + # onto the operand stack + self.push(self.calls[self.readLong().int]) of NoOp: # Does nothing continue diff --git a/src/frontend/compiler/targets/bytecode/opcodes.nim b/src/frontend/compiler/targets/bytecode/opcodes.nim index bb61399..42855ce 100644 --- a/src/frontend/compiler/targets/bytecode/opcodes.nim +++ b/src/frontend/compiler/targets/bytecode/opcodes.nim @@ -189,7 +189,8 @@ type SysClock64, # Pushes the output of a monotonic clock on the stack LoadTOS, # Pushes the top of the call stack onto the operand stack DupTop, # Duplicates the top of the operand stack onto the operand stack - ReplExit # Exits the VM immediately, leaving its state intact. Used in the REPL + ReplExit, # Exits the VM immediately, leaving its state intact. Used in the REPL + LoadGlobal # Loads a global variable # We group instructions by their operation/operand types for easier handling when debugging @@ -282,7 +283,7 @@ const constantInstructions* = {LoadInt64, LoadUInt64, # Stack triple instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form # of 24 bit integers -const stackTripleInstructions* = {StoreVar, LoadVar, } +const stackTripleInstructions* = {StoreVar, LoadVar, LoadGlobal} # Stack double instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form # of 16 bit integers diff --git a/src/frontend/compiler/targets/bytecode/target.nim b/src/frontend/compiler/targets/bytecode/target.nim index 0033f3f..cbc39b5 100644 --- a/src/frontend/compiler/targets/bytecode/target.nim +++ b/src/frontend/compiler/targets/bytecode/target.nim @@ -95,7 +95,7 @@ proc compile*(self: BytecodeCompiler, ast: seq[Declaration], file: string, lines mode: CompileMode = Debug): Chunk proc statement(self: BytecodeCompiler, node: Statement) proc declaration(self: BytecodeCompiler, node: Declaration) -proc varDecl(self: BytecodeCompiler, node: VarDecl) +proc varDecl(self: BytecodeCompiler, node: VarDecl, hoist: bool = false) proc specialize(self: BytecodeCompiler, typ: Type, args: seq[Expression]): Type {.discardable.} proc patchReturnAddress(self: BytecodeCompiler, pos: int) proc handleMagicPragma(self: BytecodeCompiler, pragma: Pragma, name: Name) @@ -1233,10 +1233,14 @@ method identifier(self: BytecodeCompiler, node: IdentExpr, name: Name = nil, com if not s.belongsTo.isNil() and s.belongsTo.valueType.fun.kind == funDecl and FunDecl(s.belongsTo.valueType.fun).isTemplate: discard else: - # Loads a regular variable from the current frame - self.emitByte(LoadVar, s.ident.token.line) - # No need to check for -1 here: we already did a nil check above! - self.emitBytes(s.position.toTriple(), s.ident.token.line) + if s.depth > 0: + # Loads a regular variable from the current frame + self.emitByte(LoadVar, s.ident.token.line) + # No need to check for -1 here: we already did a nil check above! + self.emitBytes(s.position.toTriple(), s.ident.token.line) + else: + self.emitByte(LoadGlobal, s.ident.token.line) + self.emitBytes(s.position.toTriple(), s.ident.token.line) method assignment(self: BytecodeCompiler, node: ASTNode, compile: bool = true): Type {.discardable.} = @@ -1860,8 +1864,10 @@ proc statement(self: BytecodeCompiler, node: Statement) = self.expression(Expression(node)) -proc varDecl(self: BytecodeCompiler, node: VarDecl) = +proc varDecl(self: BytecodeCompiler, node: VarDecl, hoist: bool = false) = ## Compiles variable declarations + if node.name.depth == 0 and not hoist: + return var typ: Type # Our parser guarantees that the variable declaration # will have a type declaration or a value (or both) @@ -2071,6 +2077,11 @@ proc compile*(self: BytecodeCompiler, ast: seq[Declaration], file: string, lines if not incremental: self.jumps = @[] let pos = self.beginProgram() + let idx = self.stackIndex + for node in ast: + if node.kind == varDecl and VarDecl(node).name.depth == 0: + self.varDecl(VarDecl(node), hoist=true) + self.stackIndex = idx while not self.done(): self.declaration(Declaration(self.step())) self.terminateProgram(pos)