123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- discard """
- matrix: "--mm:refc; --mm:orc; --exceptions:goto"
- targets: "c cpp js"
- 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]
- '''
- """
- when defined(nimHasEffectsOf):
- {.experimental: "strictEffects".}
- import std/[strutils, streams, pegs, assertions]
- 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 {.threadvar.}: seq[string]
- valStack {.threadvar.}: seq[float]
- opStack {.threadvar.}: string
- 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 {.used.} = 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)
- doAssert txt.len == pLen
- import std/importutils
- block:
- proc pegsTest() =
- privateAccess(NonTerminal)
- privateAccess(Captures)
- if "test" =~ peg"s <- {{\ident}}": # bug #19104
- doAssert matches[0] == "test"
- doAssert matches[1] == "test", $matches[1]
- doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
- doAssert match("(a b c)", peg"'(' @ ')'")
- doAssert match("W_HI_Le", peg"\y 'while'")
- doAssert(not match("W_HI_L", peg"\y 'while'"))
- doAssert(not match("W_HI_Le", peg"\y v'while'"))
- doAssert match("W_HI_Le", peg"y'while'")
- doAssert($ +digits == $peg"\d+")
- doAssert "0158787".match(peg"\d+")
- doAssert "ABC 0232".match(peg"\w+\s+\d+")
- doAssert "ABC".match(peg"\d+ / \w+")
- var accum: seq[string] = @[]
- for word in split("00232this02939is39an22example111", peg"\d+"):
- accum.add(word)
- doAssert(accum == @["this", "is", "an", "example"])
- doAssert matchLen("key", ident) == 3
- var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
- doAssert matchLen("key1= cal9", pattern) == 11
- var ws = newNonTerminal("ws", 1, 1)
- ws.rule = *whitespace
- var expr = newNonTerminal("expr", 1, 1)
- expr.rule = sequence(capture(ident), *sequence(
- nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
- var c: Captures = default(Captures)
- var s = "a+b + c +d+e+f"
- doAssert rawMatch(s, expr.rule, 0, c) == len(s)
- var a = ""
- for i in 0..c.ml-1:
- a.add(substr(s, c.matches[i][0], c.matches[i][1]))
- doAssert a == "abcdef"
- #echo expr.rule
- #const filename = "lib/devel/peg/grammar.txt"
- #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
- #echo "a <- [abc]*?".match(grammar)
- doAssert find("_____abc_______", term("abc"), 2) == 5
- doAssert match("_______ana", peg"A <- 'ana' / . A")
- doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
- var matches: array[0..MaxSubpatterns-1, string] = default(array[0..MaxSubpatterns-1, string])
- if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
- doAssert matches[0] == "abc"
- else:
- doAssert false
- var g2 = peg"""S <- A B / C D
- A <- 'a'+
- B <- 'b'+
- C <- 'c'+
- D <- 'd'+
- """
- doAssert($g2 == "((A B) / (C D))")
- doAssert match("cccccdddddd", g2)
- doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
- "var1<-keykey; var2<-key2key2")
- doAssert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
- "$1<-$2$2; $1<-$2$2")
- doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
- if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
- doAssert matches[0] == "a"
- else:
- doAssert false
- if match("abcdefg", peg"c {d} ef {g}", matches, 2):
- doAssert matches[0] == "d"
- doAssert matches[1] == "g"
- else:
- doAssert false
- accum = @[]
- for x in findAll("abcdef", peg".", 3):
- accum.add(x)
- doAssert(accum == @["d", "e", "f"])
- for x in findAll("abcdef", peg"^{.}", 3):
- doAssert x == "d"
- if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
- doAssert matches[0] == "f"
- doAssert matches[1] == "a, b"
- else:
- doAssert false
- doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+")
- # ß is not a lower cased letter?!
- doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+")
- doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
- doAssert(not match("456678", peg"(\letter)+"))
- doAssert("var1 = key; var2 = key2".replacef(
- peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
- "var1<-keykey;var2<-key2key2")
- doAssert match("prefix/start", peg"^start$", 7)
- if "foo" =~ peg"{'a'}?.*":
- doAssert matches[0].len == 0
- else: doAssert false
- if "foo" =~ peg"{''}.*":
- doAssert matches[0] == ""
- else: doAssert false
- if "foo" =~ peg"{'foo'}":
- doAssert matches[0] == "foo"
- else: doAssert false
- let empty_test = peg"^\d*"
- let str = "XYZ"
- doAssert(str.find(empty_test) == 0)
- doAssert(str.match(empty_test))
- proc handleMatches(m: int, n: int, c: openArray[string]): string =
- result = ""
- if m > 0:
- result.add ", "
- result.add case n:
- of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'"
- of 1: toLowerAscii(c[0]) & ": ''"
- else: ""
- doAssert("Var1=key1;var2=Key2; VAR3".
- replace(peg"{\ident}('='{\ident})* ';'* \s*",
- handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''")
- doAssert "test1".match(peg"""{@}$""")
- doAssert "test2".match(peg"""{(!$ .)*} $""")
- doAssert "abbb".match(peg"{a} {b} $2 $^1")
- doAssert "abBA".match(peg"{a} {b} i$2 i$^2")
- doAssert "abba".match(peg"{a} {b} $^1 {} $^1")
- block:
- let grammar = peg"""
- program <- {''} stmt* $
- stmt <- call / block
- call <- 'call()' EOL
- EOL <- \n / $
- block <- 'block:' \n indBody
- indBody <- {$^1 ' '+} stmt ($^1 stmt)* {}
- """
- let program = """
- call()
- block:
- block:
- call()
- call()
- call()
- call()
- """
- var c: Captures = default(Captures)
- doAssert program.len == program.rawMatch(grammar, 0, c)
- doAssert c.ml == 1
- block:
- # bug #21632
- let p = peg"""
- atext <- \w / \d
- """
- doAssert "a".match(p)
- doAssert "1".match(p)
- pegsTest()
- static:
- pegsTest()
|