Files
Nim/tests/stdlib/tpegs.nim
gemath f26ed1d540 Add interpreting event parser proc to pegs module. (#8075)
* Added simple interpreting event parser to pegs module.
* Has side-effects problem.
* Macro solution works.
* First flat callback test works.
* Fixed namespace pollution.
* Added handler for pkChar.
* Replaced event parser test.
* Started extensive docs.
* 'callback' to 'handler' renaming part 1.
* Renaming 'callback' to 'handler' part2, completed comments.
* Fixed exported API pollution.
* Added more event handler hooks, fixed comments.
* Changed event parser addition entry.
* Fixed variable names and comments.
* Enhanced comment.
* Leave handlers are not called for an unsuccessful match.
* The three varieties of back-reference matches are processed in separate
of-clauses now.
* Improved hygiene and (almost) eliminated exports.
* Trying to fix CI test breakage by eliminating export.
* Trying to fix CI test breakage by eliminating exports.
* Re-activated leave handler code execution for unsuccessful matches.
* Eliminated the last export statement (with a funny smelling hack).
* Make sure leave handler code is executed for all unsuccessful matcher
cases.
* Replaced local unicode.`==` with export.
2018-08-24 20:13:37 +02:00

149 lines
3.8 KiB
Nim

discard """
output: '''
PEG AST traversal output
------------------------
pkNonTerminal: Sum @(2, 3)
pkSequence: (Product (('+' / '-') Product)*)
pkNonTerminal: Product @(3, 7)
pkSequence: (Value (('*' / '/') Value)*)
pkNonTerminal: Value @(4, 5)
pkOrderedChoice: (([0-9] [0-9]*) / ('(' Expr ')'))
pkSequence: ([0-9] [0-9]*)
pkCharChoice: [0-9]
pkGreedyRepSet: [0-9]*
pkSequence: ('(' Expr ')')
pkChar: '('
pkNonTerminal: Expr @(1, 4)
pkNonTerminal: Sum @(2, 3)
pkChar: ')'
pkGreedyRep: (('*' / '/') Value)*
pkSequence: (('*' / '/') Value)
pkOrderedChoice: ('*' / '/')
pkChar: '*'
pkChar: '/'
pkNonTerminal: Value @(4, 5)
pkGreedyRep: (('+' / '-') Product)*
pkSequence: (('+' / '-') Product)
pkOrderedChoice: ('+' / '-')
pkChar: '+'
pkChar: '-'
pkNonTerminal: Product @(3, 7)
Event parser output
-------------------
@[5.0]
+
@[5.0, 3.0]
@[8.0]
/
@[8.0, 2.0]
@[4.0]
-
@[4.0, 7.0]
-*
@[4.0, 7.0, 22.0]
@[4.0, 154.0]
-
@[-150.0]
'''
"""
import strutils, streams
import pegs
const
indent = " "
let
pegAst = """
Expr <- Sum
Sum <- Product (('+' / '-')Product)*
Product <- Value (('*' / '/')Value)*
Value <- [0-9]+ / '(' Expr ')'
""".peg
txt = "(5+3)/2-7*22"
block:
var
outp = newStringStream()
processed: seq[string] = @[]
proc prt(outp: Stream, kind: PegKind, s: string; level: int = 0) =
outp.writeLine indent.repeat(level) & "$1: $2" % [$kind, s]
proc recLoop(p: Peg, level: int = 0) =
case p.kind
of pkEmpty..pkWhitespace:
discard
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle:
outp.prt(p.kind, $p, level)
of pkChar, pkGreedyRepChar:
outp.prt(p.kind, $p, level)
of pkCharChoice, pkGreedyRepSet:
outp.prt(p.kind, $p, level)
of pkNonTerminal:
outp.prt(p.kind,
"$1 @($3, $4)" % [p.nt.name, $p.nt.rule.kind, $p.nt.line, $p.nt.col], level)
if not(p.nt.name in processed):
processed.add p.nt.name
p.nt.rule.recLoop level+1
of pkBackRef..pkBackRefIgnoreStyle:
outp.prt(p.kind, $p, level)
else:
outp.prt(p.kind, $p, level)
for s in items(p):
s.recLoop level+1
pegAst.recLoop
echo "PEG AST traversal output"
echo "------------------------"
echo outp.data
block:
var
pStack: seq[string] = @[]
valStack: seq[float] = @[]
opStack = ""
let
parseArithExpr = pegAst.eventParser:
pkNonTerminal:
enter:
pStack.add p.nt.name
leave:
pStack.setLen pStack.high
if length > 0:
let matchStr = s.substr(start, start+length-1)
case p.nt.name
of "Value":
try:
valStack.add matchStr.parseFloat
echo valStack
except ValueError:
discard
of "Sum", "Product":
try:
let val = matchStr.parseFloat
except ValueError:
if valStack.len > 1 and opStack.len > 0:
valStack[^2] = case opStack[^1]
of '+': valStack[^2] + valStack[^1]
of '-': valStack[^2] - valStack[^1]
of '*': valStack[^2] * valStack[^1]
else: valStack[^2] / valStack[^1]
valStack.setLen valStack.high
echo valStack
opStack.setLen opStack.high
echo opStack
pkChar:
leave:
if length == 1 and "Value" != pStack[^1]:
let matchChar = s[start]
opStack.add matchChar
echo opStack
echo "Event parser output"
echo "-------------------"
let pLen = parseArithExpr(txt)
assert txt.len == pLen