summary refs log tree commit diff stats
path: root/tests/stdlib/tpegs.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tests/stdlib/tpegs.nim')
-rw-r--r--tests/stdlib/tpegs.nim350
1 files changed, 308 insertions, 42 deletions
diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim
index e5b709a66..da3fc14b7 100644
--- a/tests/stdlib/tpegs.nim
+++ b/tests/stdlib/tpegs.nim
@@ -1,5 +1,9 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
   output: '''
+PEG AST traversal output
+------------------------
 pkNonTerminal: Sum @(2, 3)
   pkSequence: (Product (('+' / '-') Product)*)
     pkNonTerminal: Product @(3, 7)
@@ -26,53 +30,315 @@ 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]
 '''
 """
 
-import strutils, streams
-import pegs
+when defined(nimHasEffectsOf):
+  {.experimental: "strictEffects".}
+
+import std/[strutils, streams, pegs, assertions]
 
 const
   indent = "  "
 
 let
-  pegSrc = """
-Expr <- Sum
-Sum <- Product (('+' / '-') Product)*
-Product <- Value (('*' / '/') Value)*
-Value <- [0-9]+ / '(' Expr ')'
-  """
-  pegAst: Peg = pegSrc.peg
-
-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 outp.data
\ No newline at end of file
+  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
+    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]
+    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
+      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()