96 lines
2.7 KiB
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
|
|
|