nondescript/src/ndspkg/compiler/controlflow.nim

93 lines
2.3 KiB
Nim

import strformat
import strutils
import bitops # needed for value
import ../scanner
import ../chunk
import ../types/value
import ../config
# 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
import scope
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)