From cf75331b7163d7a1fa72b3032327bda01489b944 Mon Sep 17 00:00:00 2001
From: Sergio Queiroz <sqmedeiros@gmail.com>
Date: Fri, 7 Jul 2017 10:21:53 -0300
Subject: Adding tests related to labeled choice

---
 testlabel.lua | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 234 insertions(+), 18 deletions(-)

diff --git a/testlabel.lua b/testlabel.lua
index e2833ea..a8439e4 100644
--- a/testlabel.lua
+++ b/testlabel.lua
@@ -246,6 +246,27 @@ p = m.Rec(#(m.P("a") * m.T(22)), m.T(15), 22)
 r, l, serror = p:match("abc")
 assert(r == nil and l == 15 and serror == "bc")
 
+p = m.Lc(#m.T(22), m.P"a", 22)
+assert(p:match("abc") == 2)
+
+p = #m.Lc(m.T(22), m.P"a", 22)
+assert(p:match("abc") == 1)
+
+p = m.Lc(m.T(22), #m.P"a", 22)
+assert(p:match("abc") == 1)
+
+p = m.Lc(#m.T(22), m.P"a", 22)
+r, l, serror = p:match("bbc")
+assert(r == nil and l == 0 and serror == "bbc")
+
+p = m.Lc(#m.P("a") * m.T(22), m.T(15), 22)
+r, l, serror = p:match("abc")
+assert(r == nil and l == 15 and serror == "abc")
+
+p = m.Lc(#(m.P("a") * m.T(22)), m.T(15), 22)
+r, l, serror = p:match("abc")
+assert(r == nil and l == 15 and serror == "abc")
+
 
 
 -- tests related to repetition
@@ -260,7 +281,9 @@ assert(r == nil and l == 1 and serror == "")
 
 -- Bug reported by Matthew Allen
 -- some optmizations performed by LPeg should not be
--- applied in case of labeled choices
+-- applied in case of labels
+
+-- recovery operator
 p = m.Rec(m.P"A", m.P(true), 1) + m.P("B")
 assert(p:match("B") == 2)
 
@@ -268,6 +291,14 @@ p = m.Rec(m.P"A", m.P(false), 1) + m.P("B")
 assert(p:match("B") == 2)
 
 
+-- labeled choices
+p = m.Lc(m.P"A", m.P(true), 1) + m.P("B")
+assert(p:match("B") == 2)
+
+p = m.Lc(m.P"A", m.P(false), 1) + m.P("B")
+assert(p:match("B") == 2)
+
+
 --[[
 S -> A //{1} 'a'
 A -> B
@@ -314,6 +345,53 @@ assert(p:match("abc") == 2)
 r, l, serror = p:match("")
 assert(r == nil and l == 0 and serror == "")
 
+-- labeled choice
+--[[
+S -> A /{1} 'a'
+A -> B
+B -> %1
+]]
+g = m.P{
+	"S",
+	S = m.Lc(m.V"A", m.P"a", 1),
+	A = m.V"B",
+	B = m.T(1),
+}
+assert(g:match("ab") == 2)
+r, l, serror = g:match("bc")
+assert(r == nil and l == 0 and serror == "bc")
+
+
+--[[
+S -> A 
+A -> (B (';' / %{1}))*
+B -> 'a'
+]]
+g = m.P{
+	"S",
+	S = m.V"A",
+	A = m.P(m.V"B" * (";" + m.T(1)))^0,
+	B = m.P'a',
+}
+assert(g:match("a;a;") == 5)
+
+r, l, serror = g:match("a;a")
+assert(r == nil and l == 1 and serror == "")
+
+
+-- %1 /{1,3} %2 /{2} 'a'
+p = m.Lc(m.Lc(m.T(1), m.T(2), 1, 3), m.P"a", 2)
+assert(p:match("abc") == 2)
+
+r, l, serror = p:match("")
+assert(r == nil and l == 0 and serror == "")
+
+p = m.Lc(m.T(1), m.Lc(m.T(2), m.P"a", 2), 1, 3)
+assert(p:match("abc") == 2)
+
+r, l, serror = p:match("")
+assert(r == nil and l == 0 and serror == "")
+
 
 -- Infinte Loop TODO: check the semantics
 -- %1 //{1} %1 
@@ -345,6 +423,15 @@ assert(r == false)
 local r = pcall(m.Rec, m.P"b", m.P"a", -1)
 assert(r == false)
 
+local r = pcall(m.Lc, m.P"b", m.P"a", 0)
+assert(r == false)
+
+local r = pcall(m.Lc, m.P"b", m.P"a", 256)
+assert(r == false)
+
+local r = pcall(m.Lc, m.P"b", m.P"a", -1)
+assert(r == false)
+
 local r = pcall(m.T, 0)
 assert(r == false)
 
@@ -468,7 +555,7 @@ r, l, serror = g:match("g")
 assert(r == nil and l == 0 and serror == "g")
 
 
---[[ grammar based on Figure 8 of paper submitted to SCP
+--[[ grammar based on Figure 8 of paper submitted to SCP (using the recovery operator)
 S  -> S0 //{1} ID //{2} ID '=' Exp //{3} 'unsigned'* 'int' ID //{4} 'unsigned'* ID ID / %error
 S0 -> S1 / S2 / &'int' %3
 S1 -> &(ID '=') %2  /  &(ID !.) %1  /  &ID %4
@@ -510,6 +597,135 @@ r, l, serror = g:match(s)
 assert(r == nil and l == 5 and serror == s)
 
 
+------------------------------------------
+-- Tests related to labeled ordered choice
+------------------------------------------
+
+-- throws a label that is not caught by labeled choice
+s = "abc"
+p = m.Lc(m.T(2), m.P"a", 1, 3)
+r, l, serror = p:match(s)
+assert(r == nil and l == 2 and serror == "abc")
+
+-- modifies previous pattern
+-- adds another labeled choice to catch label "2"
+p = m.Lc(p, m.P"a", 2)
+assert(p:match(s) == 2)
+
+-- throws a label that is caught by labeled choice
+p = m.Lc(m.T(25), m.P"a", 25)
+assert(p:match(s) == 2)
+
+-- "fail" is label "0"
+-- throws the "fail" label that is not caught by the labeled choice
+s = "bola"
+r, l, serror = p:match("bola")
+assert(r == nil and l == 0 and serror == "bola")
+
+-- labeled choice does not catch "fail"
+p = m.Lc(m.P"b", m.P"a", 1)
+
+r, l, serror = p:match("abc") 
+assert(r == nil and l == 0 and serror == "abc")
+assert(p:match("bola") == 2)
+
+-- labeled choice catches "1" or "3"
+p = m.Lc(-m.P"a" * m.T(1) + m.P"a" * m.T(3), m.P"a" + m.P"b", 1, 3)
+assert(p:match("abc") == 2)
+assert(p:match("bac") == 2)
+
+-- associativity
+-- (p1 / %1) /{1} (p2 / %2) /{2} p3
+-- left-associativity
+-- ("a" /{1}  "b") /{2} "c"
+p = m.Lc(m.Lc(m.P"a" + m.T(1), m.P"b" + m.T(2), 1), m.P"c", 2)
+assert(p:match("abc") == 2)
+assert(p:match("bac") == 2)
+assert(p:match("cab") == 2)
+r, l, serror = p:match("dab")
+assert(r == nil and l == 0 and serror == "dab")
+
+
+-- righ-associativity
+-- "a" /{1}  ("b" /{2} "c")
+p = m.Lc(m.P"a" + m.T(1), m.Lc(m.P"b" + m.T(2), m.P"c", 2), 1)
+assert(p:match("abc") == 2)
+assert(p:match("bac") == 2)
+assert(p:match("cab") == 2)
+r, l, serror = p:match("dab")
+assert(r == nil and l == 0 and serror == "dab")
+
+
+-- associativity -> in this case the error thrown by p1 is only
+--                  recovered when we have a left-associative operator
+-- (p1 / %2) /{1} (p2 / %2) /{2} p3
+-- left-associativity
+-- ("a" /{1}  "b") /{2} "c"
+p = m.Lc(m.Lc(m.P"a" + m.T(2), m.P"b" + m.T(2), 1), m.P"c", 2)
+assert(p:match("abc") == 2)
+r, l, serror = p:match("bac")
+assert(r == nil and l == 0 and serror == "bac")
+assert(p:match("cab") == 2)
+r, l, serror = p:match("dab")
+assert(r == nil and l == 0 and serror == "dab")
+
+
+-- righ-associativity
+-- "a" /{1}  ("b" /{2} "c")
+p = m.Lc(m.P"a" + m.T(2), m.Lc(m.P"b" + m.T(2), m.P"c", 2), 1)
+assert(p:match("abc") == 2)
+r, l, serror = p:match("bac")
+assert(r == nil and l == 2 and serror == "bac")
+r, l, serror = p:match("cab")
+assert(r == nil and l == 2 and serror == "cab")
+r, l, serror = p:match("dab")
+assert(r == nil and l == 2 and serror == "dab")
+
+
+
+--[[ grammar based on Figure 8 of paper submitted to SCP (using labeled choice)
+S  -> S0 /{1} ID /{2} ID '=' Exp /{3} 'unsigned'* 'int' ID /{4} 'unsigned'* ID ID / %error
+S0 -> ID S1 / 'unsigned' S2 / 'int' %3
+S1 -> '=' %2  /  !. %1  /  ID %4
+S2 -> 'unsigned' S2  /  ID %4  /  'int' %3 
+]]
+
+
+g = re.compile([[
+	S <- S0 /{1} ID /{2} ID %s* '=' Exp /{3} U* Int ID /{4} U ID ID / %{5}
+  S0 <- ID S1 / U S2 / Int %{3}
+  S1 <- %s* '=' %{2} / !. %{1} / ID %{4}
+  S2 <- U S2 / ID %{4} / Int %{3}
+  ID <- %s* 'a' 
+  U <- %s* 'unsigned'
+  Int <- %s* 'int'
+  Exp <- %s* 'E'
+]])
+
+local s = "a"
+assert(g:match(s) == #s + 1) --1
+s = "a = E"
+assert(g:match(s) == #s + 1) --2
+s = "int a"
+assert(g:match(s) == #s + 1) --3
+s = "unsigned int a"
+assert(g:match(s) == #s + 1) --3
+s = "unsigned a a"
+assert(g:match(s) == #s + 1) --4
+s = "b" 
+r, l, serror = g:match(s)
+assert(r == nil and l == 5 and serror == s)
+s = "unsigned" 
+r, l, serror = g:match(s)
+assert(r == nil and l == 5 and serror == s)
+s = "unsigned a" 
+r, l, serror = g:match(s)
+assert(r == nil and l == 5 and serror == s)
+s = "unsigned int" 
+r, l, serror = g:match(s)
+assert(r == nil and l == 5 and serror == s)
+
+
 
 local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq",
                  ['ifExp'] = "Error in expresion of 'if'",
@@ -861,29 +1077,29 @@ local function eval(input)
   end
 end
 
-print(eval "98-76*(54/32)")
+assert(eval "98-76*(54/32)" == 37.125)
 --> 37.125
 
-print(eval "(1+1-1*2/2")
---> syntax error: missing a closing ')' after the expression (at index 11)
+local e, msg = eval "(1+1-1*2/2"
+assert(e == nil and msg == "syntax error: missing a closing ')' after the expression (at index 11)")
 
-print(eval "(1+)-1*(2/2)")
---> syntax error: expected a term after the operator (at index 4)
+e, msg = eval "(1+)-1*(2/2)"
+assert(e == nil and msg == "syntax error: expected a term after the operator (at index 4)")
 
-print(eval "(1+1)-1*(/2)")
---> syntax error: expected an expression after the parenthesis (at index 10)
+e, msg = eval "(1+1)-1*(/2)"
+assert(e == nil and msg == "syntax error: expected an expression after the parenthesis (at index 10)")
 
-print(eval "1+(1-(1*2))/2x")
---> syntax error: extra chracters found after the expression (at index 14)
+e, msg = eval "1+(1-(1*2))/2x"
+assert(e == nil and msg == "syntax error: extra characters found after the expression (at index 14)")
 
-print(eval "-1+(1-(1*2))/2")
---> syntax error: no expression found (at index 1)
+e, msg = eval "-1+(1-(1*2))/2"
+assert(e == nil and msg == "syntax error: no expression found (at index 1)")
 
-print(eval "(1+1-1*(2/2+)-():")
---> syntax error: expected a term after the operator (at index 13)
---> syntax error: expected an expression after the parenthesis (at index 16)
---> syntax error: missing a closing ')' after the expression (at index 17)
---> syntax error: extra characters found after the expression (at index 
+e, msg = eval "(1+1-1*(2/2+)-():"
+assert(e == nil and msg == "syntax error: expected a term after the operator (at index 13)\n" ..
+                           "syntax error: expected an expression after the parenthesis (at index 16)\n" ..
+                           "syntax error: missing a closing ')' after the expression (at index 17)\n" ..
+                           "syntax error: extra characters found after the expression (at index 17)")
 
 
 print("+")
-- 
cgit v1.2.3-55-g6feb