nondescript/src/ndspkg/compv2/parser.nim

107 lines
2.3 KiB
Nim

# a new recursive descent parser for nds
# parser: converts a stream of tokens into an AST
import ../scanner
import ../chunk
import node
import ../config
import strformat
import sequtils
import sugar
# TYPEDEF
type
Parser = ref object
# scanning
scanner: Scanner
source: string
current: Token
previous: Token
# errors
hadError*: bool
panicMode: bool
proc newParser*(name: string, source: string): Parser =
result = new(Parser)
result.source = source
result.hadError = false
result.panicMode = false
# UTILS
# error handling
proc errorAt(parser: Parser, line: int, msg: string, at: string = "") =
if parser.panicMode:
return # don't display errors if already in panic mode
write stderr, &"[line {line}] Error "
if at.len > 0:
write stderr, &"at {at} "
write stderr, msg
write stderr, "\n"
parser.hadError = true
parser.panicMode = true
proc error(parser: Parser, msg: string) =
parser.errorAt(parser.previous.line, msg)
proc errorAtCurrent(parser: Parser, msg: string) =
parser.errorAt(parser.current.line, msg)
# scanning for tokens
proc advance(parser: Parser) =
parser.previous = parser.current
while true:
parser.current = parser.scanner.scanToken()
when debugScanner:
parser.current.debugPrint()
if (parser.current.tokenType != tkError):
break
parser.errorAtCurrent(parser.current.text)
proc match(parser: Parser, tokenType: TokenType): bool =
if parser.current.tokenType == tokenType:
parser.advance()
true
else:
false
proc consume(parser: Parser, tokenType: TokenType, msg: string) =
if not parser.match(tokenType):
parser.errorAtCurrent(msg)
proc synchronize(parser: Parser) =
parser.panicMode = false
while parser.current.tokenType != tkEof:
if parser.previous.tokenType in {tkSemicolon, tkRightBrace}:
return
if parser.current.tokenType in {tkFunct, tkVar, tkFor, tkIf, tkWhile}:
return
parser.advance()
# EXPRESSIONS
# STATEMENTS
proc statement(parser: Parser): Node
proc statement(parser: Parser): Node =
if parser.panicMode:
parser.synchronize()
proc parse*(parser: Parser): Node =
parser.scanner = newScanner(parser.source)
var result: Node = Node(kind: nkBlockExpr, children: @[])
parser.advance()
while parser.current.tokenType != tkEof:
result.children.add(parser.statement())