93 lines
2.4 KiB
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)
|