mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
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.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
discard """
|
||||
output: '''
|
||||
PEG AST traversal output
|
||||
------------------------
|
||||
pkNonTerminal: Sum @(2, 3)
|
||||
pkSequence: (Product (('+' / '-') Product)*)
|
||||
pkNonTerminal: Product @(3, 7)
|
||||
@@ -26,6 +28,25 @@ pkNonTerminal: Sum @(2, 3)
|
||||
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]
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -36,43 +57,92 @@ const
|
||||
indent = " "
|
||||
|
||||
let
|
||||
pegSrc = """
|
||||
Expr <- Sum
|
||||
Sum <- Product (('+' / '-') Product)*
|
||||
Product <- Value (('*' / '/') Value)*
|
||||
Value <- [0-9]+ / '(' Expr ')'
|
||||
"""
|
||||
pegAst: Peg = pegSrc.peg
|
||||
pegAst = """
|
||||
Expr <- Sum
|
||||
Sum <- Product (('+' / '-')Product)*
|
||||
Product <- Value (('*' / '/')Value)*
|
||||
Value <- [0-9]+ / '(' Expr ')'
|
||||
""".peg
|
||||
txt = "(5+3)/2-7*22"
|
||||
|
||||
var
|
||||
outp = newStringStream()
|
||||
processed: seq[string] = @[]
|
||||
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 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
|
||||
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 outp.data
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user