nondescript/src/ndspkg/compiler/utils.nim

96 lines
2.7 KiB
Nim

import strformat
import ../chunk
import ../scanner
import ../config
import ../types/value
import types
proc errorAt*(comp: Compiler, line: int, msg: string, at: string = "") =
if comp.panicMode:
return
write stderr, &"[line {line}] Error "
if at.len > 0:
write stderr, &"at {at} "
write stderr, msg
write stderr, "\n"
comp.hadError = true
comp.panicMode = true
proc error*(comp: Compiler, msg: string) =
## create a simple error message
comp.errorAt(comp.previous.line, msg)
proc errorAtCurrent*(comp: Compiler, msg: string) =
comp.errorAt(comp.current.line, msg)
proc advance*(comp: Compiler) =
comp.previous = comp.current
while true:
comp.current = comp.scanner.scanToken()
if (comp.current.tokenType != tkError):
break
comp.errorAtCurrent(comp.current.text)
proc match*(comp: Compiler, tokenType: TokenType): bool =
if comp.current.tokenType == tokenType:
comp.advance()
true
else:
false
proc consume*(comp: Compiler, tokenType: TokenType, msg: string) =
if comp.current.tokenType == tokenType:
comp.advance()
else:
comp.errorAtCurrent(msg)
proc synchronize*(comp: Compiler) =
comp.panicMode = false
while comp.current.tokenType != tkEof:
if comp.previous.tokenType in {tkSemicolon, tkRightBrace}:
return
if comp.current.tokenType in {tkProc, tkVar, tkFor, tkIf, tkWhile}:
return
comp.advance()
proc writeChunk*(comp: Compiler, dStackIndex: int, ch: OpCode | DoubleUint8 | uint8) =
comp.stackIndex += dStackIndex
comp.chunk.writeChunk(ch, comp.previous.line)
proc writePops*(comp: Compiler, count: int) =
if count > argMax:
comp.error("Too many local variables in block.")
if count == 0:
return
if count == 1:
comp.writeChunk(-1, opPop)
elif count < shortArgMax:
comp.writeChunk(-count, opPopSA)
comp.writeChunk(0, count.uint8)
else:
comp.writeChunk(-count, opPopA)
comp.writeChunk(0, count.toDU8())
proc writeConstant*(comp: Compiler, constant: NdValue) =
comp.stackIndex.inc
let index = comp.chunk.writeConstant(constant, comp.previous.line)
if index >= argMax:
comp.error("Too many constants in one chunk.")
proc addLocal*(comp: Compiler, name: string, delta: int) =
if comp.locals.len >= argMax:
comp.error("Too many local variables in function.")
# if delta is 0 or negative, it means that it is already on the stack when addLocal is called
# if delta is positive, the first ever value of the local is to the right
comp.locals.add(Local(name: name, depth: if delta > 0: -1 else: comp.scopes.high, index: comp.stackIndex + delta, scope: comp.scopes[comp.scopes.high()], captured: false))
proc markInitialized*(comp: Compiler) =
comp.locals[comp.locals.high].depth = comp.scopes.high