Fixed if/else

This commit is contained in:
Mattia Giambirtone 2022-06-02 12:05:22 +02:00
parent 72ba5c7528
commit dfa42d994b
6 changed files with 35 additions and 74 deletions

View File

@ -470,40 +470,23 @@ proc dispatch*(self: PeonVM) =
discard self.popc() discard self.popc()
# Jump opcodes # Jump opcodes
of Jump: of Jump:
self.ip = self.readShort() self.ip = self.readLong()
of JumpForwards: of JumpForwards:
self.ip += self.readShort() self.ip += self.readLong()
of JumpBackwards: of JumpBackwards:
self.ip -= self.readShort() self.ip -= self.readLong()
of JumpIfFalse: of JumpIfFalse:
if not self.peek().boolean: if not self.peek().boolean:
self.ip += self.readShort() self.ip += self.readLong()
of JumpIfTrue: of JumpIfTrue:
if self.peek().boolean: if self.peek().boolean:
self.ip += self.readShort() self.ip += self.readLong()
of JumpIfFalsePop: of JumpIfFalsePop:
let ip = self.readLong()
if not self.peek().boolean: if not self.peek().boolean:
self.ip += self.readShort() self.ip = ip
discard self.pop() discard self.pop()
of JumpIfFalseOrPop: of JumpIfFalseOrPop:
if not self.peek().boolean:
self.ip += self.readShort()
else:
discard self.pop()
of LongJumpIfFalse:
if not self.peek().boolean:
self.ip += self.readLong()
of LongJumpIfFalsePop:
if not self.peek().boolean:
self.ip += self.readLong()
discard self.pop()
of LongJumpForwards:
self.ip += self.readLong()
of LongJumpBackwards:
self.ip -= self.readLong()
of LongJump:
self.ip = self.readLong()
of LongJumpIfFalseOrPop:
if not self.peek().boolean: if not self.peek().boolean:
self.ip += self.readLong() self.ip += self.readLong()
else: else:

View File

@ -27,7 +27,7 @@ when len(PEON_COMMIT_HASH) != 40:
const PEON_BRANCH* = "master" const PEON_BRANCH* = "master"
when len(PEON_BRANCH) > 255: when len(PEON_BRANCH) > 255:
{.fatal: "The git branch name's length must be less than or equal to 255 characters".} {.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_GC* = false # Traces the garbage collector (TODO)
const DEBUG_TRACE_ALLOCATION* = false # Traces memory allocation/deallocation const DEBUG_TRACE_ALLOCATION* = false # Traces memory allocation/deallocation
const DEBUG_TRACE_COMPILER* = false # Traces the compiler const DEBUG_TRACE_COMPILER* = false # Traces the compiler

View File

@ -913,7 +913,7 @@ proc declareName(self: Compiler, node: Declaration) =
if self.scopeDepth > 0: if self.scopeDepth > 0:
# Closure variables are only used in local # Closure variables are only used in local
# scopes # scopes
self.emitByte(LongJumpForwards) self.emitByte(JumpForwards)
self.emitBytes(0.toTriple()) self.emitBytes(0.toTriple())
of NodeKind.funDecl: of NodeKind.funDecl:
var node = FunDecl(node) var node = FunDecl(node)
@ -1098,6 +1098,17 @@ proc blockStmt(self: Compiler, node: BlockStmt) =
proc ifStmt(self: Compiler, node: IfStmt) = proc ifStmt(self: Compiler, node: IfStmt) =
## Compiles if/else statements for conditional ## Compiles if/else statements for conditional
## execution of code ## execution of code
var cond = self.inferType(node.condition)
if not self.compareTypes(cond, Type(kind: Bool)):
if cond == nil:
if node.condition.kind == identExpr:
self.error(&"reference to undeclared identifier '{IdentExpr(node.condition).name.lexeme}'")
elif node.condition.kind == callExpr and CallExpr(node.condition).callee.kind == identExpr:
self.error(&"reference to undeclared identifier '{IdentExpr(CallExpr(node.condition).callee).name.lexeme}'")
else:
self.error(&"expecting value of type 'bool', but expression has no type")
else:
self.error(&"expecting value of type 'bool', got '{self.typeToStr(cond)}' instead")
self.expression(node.condition) self.expression(node.condition)
var jumpCode: OpCode var jumpCode: OpCode
if self.enableOptimizations: if self.enableOptimizations:
@ -1118,21 +1129,11 @@ proc ifStmt(self: Compiler, node: IfStmt) =
proc emitLoop(self: Compiler, begin: int) = proc emitLoop(self: Compiler, begin: int) =
## Emits a JumpBackwards instruction with the correct ## Emits a JumpBackwards instruction with the correct
## jump offset ## jump offset
var offset: int var offset = self.chunk.code.len() - begin + 4
case OpCode(self.chunk.code[begin + 1]): # The jump instruction if offset > 16777215:
of LongJumpForwards, LongJumpBackwards, LongJumpIfFalse, self.error("cannot jump more than 16777215 bytecode instructions")
LongJumpIfFalsePop, LongJumpIfTrue: self.emitByte(JumpBackwards)
offset = self.chunk.code.len() - begin + 4 self.emitBytes(offset.toTriple())
else:
offset = self.chunk.code.len() - begin
if offset > uint16.high().int:
if offset > 16777215:
self.error("cannot jump more than 16777215 bytecode instructions")
self.emitByte(LongJumpBackwards)
self.emitBytes(offset.toTriple())
else:
self.emitByte(JumpBackwards)
self.emitBytes(offset.toDouble())
proc whileStmt(self: Compiler, node: WhileStmt) = proc whileStmt(self: Compiler, node: WhileStmt) =
@ -1299,14 +1300,10 @@ proc raiseStmt(self: Compiler, node: RaiseStmt) =
proc continueStmt(self: Compiler, node: ContinueStmt) = proc continueStmt(self: Compiler, node: ContinueStmt) =
## Compiles continue statements. A continue statements ## Compiles continue statements. A continue statements
## jumps to the next iteration in a loop ## jumps to the next iteration in a loop
if self.currentLoop.start <= 65535: if self.currentLoop.start > 16777215:
self.emitByte(Jump) self.error("too much code to jump over in continue statement")
self.emitBytes(self.currentLoop.start.toDouble()) self.emitByte(Jump)
else: self.emitBytes(self.currentLoop.start.toTriple())
if self.currentLoop.start > 16777215:
self.error("too much code to jump over in continue statement")
self.emitByte(LongJump)
self.emitBytes(self.currentLoop.start.toTriple())
proc breakStmt(self: Compiler, node: BreakStmt) = proc breakStmt(self: Compiler, node: BreakStmt) =
@ -1422,7 +1419,7 @@ proc funDecl(self: Compiler, node: FunDecl) =
self.frames.add(self.names.high()) self.frames.add(self.names.high())
let fn = self.names[^(node.arguments.len() + 1)] let fn = self.names[^(node.arguments.len() + 1)]
fn.codePos = self.chunk.code.len() fn.codePos = self.chunk.code.len()
let jmp = self.emitJump(LongJumpForwards) let jmp = self.emitJump(JumpForwards)
for argument in node.arguments: for argument in node.arguments:
self.emitByte(LoadArgument) self.emitByte(LoadArgument)
if node.returnType != nil and self.inferType(node.returnType) == nil: if node.returnType != nil and self.inferType(node.returnType) == nil:

View File

@ -110,14 +110,6 @@ type
JumpIfTrue, # Jumps to a relative index in the bytecode if x is true JumpIfTrue, # Jumps to a relative index in the bytecode if x is true
JumpIfFalsePop, # Like JumpIfFalse, but also pops off the stack (regardless of truthyness). Optimization for if statements JumpIfFalsePop, # Like JumpIfFalse, but also pops off the stack (regardless of truthyness). Optimization for if statements
JumpIfFalseOrPop, # Jumps to an absolute index in the bytecode if x is false and pops otherwise (used for logical and) JumpIfFalseOrPop, # Jumps to an absolute index in the bytecode if x is false and pops otherwise (used for logical and)
## Long variants of jumps (they use a 24-bit operand instead of a 16-bit one)
LongJump,
LongJumpIfFalse,
LongJumpIfTrue,
LongJumpIfFalsePop,
LongJumpIfFalseOrPop,
LongJumpForwards,
LongJumpBackwards,
## Functions ## Functions
Call, # Calls a function and initiates a new stack frame Call, # Calls a function and initiates a new stack frame
Return, # Terminates the current function Return, # Terminates the current function
@ -175,11 +167,9 @@ const argumentTripleInstructions* = {}
const callInstructions* = {Call, } const callInstructions* = {Call, }
# Jump instructions jump at relative or absolute bytecode offsets # Jump instructions jump at relative or absolute bytecode offsets
const jumpInstructions* = {Jump, LongJump, JumpIfFalse, JumpIfFalsePop, const jumpInstructions* = {Jump, JumpIfFalse, JumpIfFalsePop,
JumpForwards, JumpBackwards, JumpForwards, JumpBackwards,
LongJumpIfFalse, LongJumpIfFalsePop, JumpIfTrue}
LongJumpForwards, LongJumpBackwards,
JumpIfTrue, LongJumpIfTrue}
proc newChunk*: Chunk = proc newChunk*: Chunk =

View File

@ -30,7 +30,7 @@ proc getLineEditor: LineEditor
# Handy dandy compile-time constants # Handy dandy compile-time constants
const debugLexer = false const debugLexer = false
const debugParser = false const debugParser = false
const debugCompiler = false const debugCompiler = true
const debugSerializer = false const debugSerializer = false
const debugRuntime = false const debugRuntime = false

View File

@ -167,21 +167,12 @@ proc constantInstruction(self: Debugger, instruction: OpCode) =
proc jumpInstruction(self: Debugger, instruction: OpCode) = proc jumpInstruction(self: Debugger, instruction: OpCode) =
## Debugs jumps ## Debugs jumps
var orig = self.current var orig = self.current
var jump: int var jump = [self.chunk.code[self.current + 1], self.chunk.code[self.current + 2], self.chunk.code[self.current + 3]].fromTriple().int()
case instruction:
of Jump, JumpIfFalse, JumpIfTrue, JumpIfFalsePop, JumpForwards, JumpBackwards:
jump = [self.chunk.code[self.current + 1], self.chunk.code[self.current + 2]].fromDouble().int()
of LongJump, LongJumpIfFalse, LongJumpIfTrue, LongJumpIfFalsePop,
LongJumpForwards, LongJumpBackwards:
jump = [self.chunk.code[self.current + 1], self.chunk.code[self.current + 2], self.chunk.code[self.current + 3]].fromTriple().int()
self.current += 1
else:
discard # Unreachable
printInstruction(instruction, true) printInstruction(instruction, true)
printDebug("Jump size: ") printDebug("Jump size: ")
stdout.styledWrite(fgYellow, $jump) stdout.styledWrite(fgYellow, $jump)
nl() nl()
self.current += 3 self.current += 4
for i in countup(orig, self.current + 1): for i in countup(orig, self.current + 1):
self.checkFrameStart(i) self.checkFrameStart(i)