{.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()