107 lines
2.3 KiB
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())
|
|
|