88 lines
2.2 KiB
Nim
88 lines
2.2 KiB
Nim
{.used.}
|
|
|
|
import ../scanner
|
|
import ../chunk
|
|
|
|
# the following order of imports here is important
|
|
# it defines the allowed dependency precedence between the compiler files
|
|
import types
|
|
import utils
|
|
import precedence
|
|
import jumps
|
|
|
|
proc ifExpr(comp: Compiler) =
|
|
# if expressions return the body if condition is truthy,
|
|
# the else expression otherwise, unless there is no else:
|
|
# if there is no else, it returns the condition if it is falsey
|
|
comp.consume(tkLeftParen, "Expect '(' after 'if'.")
|
|
comp.expression()
|
|
comp.consume(tkRightParen, "Expect ')' after condition.")
|
|
|
|
let thenJump = comp.emitJump(0, opJumpIfFalse)
|
|
|
|
# conditional code that can be jumped over must leave the stack in tact!
|
|
|
|
comp.writeChunk(-1, opPop)
|
|
comp.expression()
|
|
# net change to stack: -1 + 1 = 0
|
|
|
|
let elseJump = comp.emitJump(0, opJump)
|
|
comp.patchJump(thenJump)
|
|
|
|
if comp.match(tkElse):
|
|
comp.writeChunk(-1, opPop)
|
|
comp.expression()
|
|
|
|
comp.patchJump(elseJump)
|
|
|
|
|
|
tkIf.genRule(ifExpr, nop, pcNone)
|
|
|
|
proc andExpr(comp: Compiler) =
|
|
let endJump = comp.emitJump(0, opJumpIfFalse)
|
|
|
|
comp.writeChunk(-1, opPop)
|
|
comp.parsePrecedence(pcAnd)
|
|
# net effect on stack: -1 + 1 = 0
|
|
|
|
comp.patchJump(endJump)
|
|
|
|
tkAnd.genRule(nop, andExpr, pcAnd)
|
|
|
|
proc orExpr(comp: Compiler) =
|
|
let elseJump = comp.emitJump(0, opJumpIfFalse)
|
|
let endJump = comp.emitJump(0, opJump)
|
|
|
|
comp.patchJump(elseJump)
|
|
|
|
comp.writeChunk(-1, opPop)
|
|
comp.parsePrecedence(pcOr)
|
|
# net effect on stack: -1 + 1 = 0
|
|
|
|
comp.patchJump(endJump)
|
|
|
|
tkOr.genRule(nop, orExpr, pcOr)
|
|
|
|
proc parseWhile(comp: Compiler) =
|
|
|
|
comp.writeChunk(1, opNil) # return value
|
|
let loopStart = comp.chunk.len
|
|
comp.consume(tkLeftParen, "Expect '(' after 'while'.")
|
|
# condition
|
|
comp.expression()
|
|
comp.consume(tkRightParen, "Expect ')' after condition.")
|
|
|
|
let exitJump = comp.emitJump(-1, opJumpIfFalsePop)
|
|
# this cannot be handled with just opPop, since the net change in the
|
|
# stack size inside code that is conditional must be 0!
|
|
|
|
# body
|
|
comp.writeChunk(-1, opPop) # pop the old return value
|
|
comp.expression()
|
|
# net stack change: 1 + -1 = 0
|
|
|
|
comp.emitLoop(loopstart = loopStart, delta = 0, op = opLoop)
|
|
comp.patchJump(exitJump)
|
|
|
|
tkWhile.genRule(parseWhile, nop, pcNone)
|