nondescript/src/ndspkg/compiler/controlflow.nim

93 lines
2.4 KiB
Nim

{.used.}
import ../scanner
import ../chunk
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.")
var thenStacklen = 0
let thenJump = comp.emitJump(0, opJumpIfFalse, thenStacklen)
# 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
var elseStacklen = 0
let elseJump = comp.emitJump(0, opJump, elseStacklen)
comp.patchJump(thenJump, thenStacklen)
if comp.match(tkElse):
comp.writeChunk(-1, opPop)
comp.expression()
comp.patchJump(elseJump, elseStacklen)
tkIf.genRule(ifExpr, nop, pcNone)
proc andExpr(comp: Compiler) =
var stacklen = 0
let endJump = comp.emitJump(0, opJumpIfFalse, stacklen)
comp.writeChunk(-1, opPop)
comp.parsePrecedence(pcAnd)
# net effect on stack: -1 + 1 = 0
comp.patchJump(endJump, stacklen)
tkAnd.genRule(nop, andExpr, pcAnd)
proc orExpr(comp: Compiler) =
var elseStacklen = 0
var endStacklen = 0
let elseJump = comp.emitJump(0, opJumpIfFalse, elseStacklen)
let endJump = comp.emitJump(0, opJump, endStacklen)
comp.patchJump(elseJump, elseStacklen)
comp.writeChunk(-1, opPop)
comp.parsePrecedence(pcOr)
# net effect on stack: -1 + 1 = 0
comp.patchJump(endJump, endStacklen)
tkOr.genRule(nop, orExpr, pcOr)
proc parseWhile(comp: Compiler) =
comp.writeChunk(1, opNil) # return value
let loopStart = comp.chunk.len
let loopStacklen = comp.stackIndex
comp.consume(tkLeftParen, "Expect '(' after 'while'.")
# condition
comp.expression()
comp.consume(tkRightParen, "Expect ')' after condition.")
var exitStacklen = 0
let exitJump = comp.emitJump(-1, opJumpIfFalsePop, exitStacklen)
# 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, loopStacklen)
comp.patchJump(exitJump, exitStacklen)
tkWhile.genRule(parseWhile, nop, pcNone)