83 lines
2.8 KiB
Nim
83 lines
2.8 KiB
Nim
import sugar
|
|
import strformat
|
|
|
|
import ../scanner
|
|
import ../types/value
|
|
import ../config
|
|
|
|
import types
|
|
import utils
|
|
|
|
# PARSE RULE/PRECEDENCE MISC
|
|
proc nop*(comp: Compiler) = discard
|
|
|
|
var rules*: array[TokenType, ParseRule]
|
|
template genRule*(ttype: TokenType, tprefix: (Compiler) -> void, tinfix: (Compiler) -> void, tprec: Precedence) =
|
|
if tprec == pcUnary:
|
|
raise newException(Exception, "pcUnary cannot be used as a rule precedence! Use pcNone for unary-only rules!")
|
|
elif tprec == pcPrimary:
|
|
raise newException(Exception, "Invalid rule: pcPrimary cannot be used for binary operators, if this rule is for a primary value, use pcNone!")
|
|
elif tprec in {pcNonAssignTop, pcExprTop}:
|
|
raise newException(Exception, "Invalid rule: a top pc is just a placeholder")
|
|
elif tprec == pcNone and tinfix != nop:
|
|
raise newException(Exception, "Invalid rule: pcNone only allowed for unary operators and primary values, not for infix ones!")
|
|
rules[ttype] = ParseRule(name: $ttype, prefix: tprefix, infix: tinfix, prec: tprec)
|
|
|
|
for i in TokenType:
|
|
genRule(i, nop, nop, pcNone)
|
|
|
|
proc getRule*(opType: TokenType): ParseRule =
|
|
rules[opType]
|
|
|
|
proc applyRule*(rule: ParseRule): Precedence =
|
|
# returns the rule's precedence
|
|
rule.prec
|
|
|
|
proc increment*(prec: Precedence): Precedence =
|
|
# increases precedence by one
|
|
if prec == pcPrimary:
|
|
raise newException(Exception, "Invalid ruletable, pcPrimary precedence increment attempted.")
|
|
else:
|
|
Precedence(int(prec) + 1)
|
|
|
|
proc `<=`*(a, b: Precedence): bool =
|
|
int(a) <= int(b)
|
|
|
|
proc parsePrecedence*(comp: Compiler, prec: Precedence) =
|
|
comp.advance()
|
|
let rule = comp.previous.tokenType.getRule()
|
|
|
|
if rule.prefix != nop:
|
|
comp.canAssign = prec <= pcAssignment
|
|
|
|
rule.prefix(comp)
|
|
|
|
while prec <= comp.current.tokenType.getRule().prec:
|
|
comp.advance()
|
|
# checked for isSome in the loop
|
|
# since advance moves current to previous
|
|
if comp.previous.tokenType.getRule().infix == nop:
|
|
# should never happen, as having a precedence set
|
|
# means that it is a binary op
|
|
comp.error("Invalid rule table.")
|
|
return
|
|
else:
|
|
let infixRule = comp.previous.tokenType.getRule().infix
|
|
infixRule(comp)
|
|
else:
|
|
comp.error(&"Expect expression, got {($comp.previous.tokenType)[2..^1]}.")
|
|
|
|
proc expression*(comp: Compiler) =
|
|
## The lowest precedence among the pratt-parsed expressions
|
|
|
|
# DO NOT ADD ANYTHING HERE
|
|
# only use the pratt table for parsing expressions!
|
|
when assertionsVM:
|
|
let oldStackIndex = comp.stackIndex
|
|
comp.parsePrecedence(pcExprTop)
|
|
when assertionsVM:
|
|
let diff = comp.stackIndex - oldStackIndex
|
|
if diff != 1:
|
|
comp.error(&"Assertion failed: expression increased ({oldStackIndex} -> {comp.stackIndex}) the stack index by {diff} (should be 1).")
|
|
|