nondescript/src/ndspkg/compiler/statement.nim

66 lines
2.0 KiB
Nim

{.used.}
import ../scanner
import ../chunk
import types
import utils
import precedence
import scope
import variables
# below are the expressions that can contain statements in some way
# the only expressions that can contain a statement are:
# the block expression
proc statement*(comp: Compiler)
proc parseBlock(comp: Compiler) =
## Despite the name, can be used for statements if the arg statement is true
## Also can be used for function bodies
comp.beginScope()
while comp.current.tokenType != tkRightBrace and comp.current.tokenType != tkEof:
comp.statement()
discard comp.endScope()
comp.consume(tkRightBrace, "Expect '}' after block.")
tkLeftBrace.genRule(parseBlock, nop, pcNone)
# statements
proc breakStatement(comp: Compiler) =
if not comp.match(tkLabel):
comp.error("Label expected after break.")
let label = comp.previous.text[1..^1]
for i in countdown(comp.scopes.high, 0):
let scope = comp.scopes[i]
if scope.labels.contains(label):
comp.jumpToEnd(scope)
break
comp.consume(tkSemicolon, "Semicolon expected after break statement.")
if comp.current.tokenType != tkRightBrace:
comp.error("Break statement must be the last element inside the innermost block it is in.")
proc statement*(comp: Compiler) =
if comp.match(tkVar):
comp.varStatement()
comp.consume(tkSemicolon, "Semicolon expected after expression statement.")
# elif comp.match(tkDef):
# comp.procStatement()
# comp.consume(tkSemicolon, "Semicolon expected after procedure declaration.")
elif comp.match(tkBreak):
comp.breakStatement()
else:
comp.expression()
if comp.current.tokenType == tkRightBrace:
# last expression in the block expression -> semicolon optional
comp.writeChunk(0, opSetLocal)
comp.writeChunk(0, comp.scopeRetIndex().toDU8())
else:
comp.consume(tkSemicolon, "Semicolon expected after expression statement.")
comp.writeChunk(-1, opPop)
if comp.panicMode:
comp.synchronize()