]> mj.ucw.cz Git - eval.git/commitdiff
Implemented varname as a shorthand for "{varname}"
authorTomas Gavenciak <gavento@ucw.cz>
Sat, 10 Jul 2010 11:05:23 +0000 (13:05 +0200)
committerTomas Gavenciak <gavento@ucw.cz>
Sat, 10 Jul 2010 11:08:28 +0000 (13:08 +0200)
Fixed: variable parsing at end of file
Updated grammar and tests, new test

t/moe/confparser.py
t/moe/conftest.py

index 31783403a3a78c640a5b413a62b321e25b5cd287..0ac7bb29b65d34a7045646e1d7cbeb6d12166863 100644 (file)
@@ -39,7 +39,7 @@ NOTE: ';' or '\n' is currently required even after CONDITION and SUBTREE block
   TODO: change to OPERATION only
 NOTE: Formula may contain additional/extra parentheses
 
-EXPRESSION = '"' ( ECHAR | '{' VARNAME '}' )* '"' | re"'[^'\\n]*'"
+EXPRESSION = '"' ( ECHAR | '{' VARNAME '}' )* '"' | re"'[^'\\n]*'" | VARNAME
 ECHAR = re('([^\\{}]|\\\\|\\{|\\}|\\n)*')
 VARNAME = re('[a-zA-Z0-9-_]+(\.[a-zA-Z0-9-_]+)*')
 """
@@ -278,7 +278,7 @@ class ConfigParser(object):
   def p_VARNAME(self):
     self.dbg() # Debug
     vnl = []
-    while self.peek().isalnum() or self.peek() in u'-_.':
+    while self.preread(1) and (self.peek().isalnum() or self.peek() in u'-_.'):
       vnl.append(self.next())
     vn = u''.join(vnl)
     if not conf.re_VARNAME.match(vn):
@@ -287,9 +287,11 @@ class ConfigParser(object):
 
   def p_EXPRESSION(self):
     self.dbg() # Debug
+    if self.peek() not in '\'"':
+      # Expect a variable name 
+      varname = self.p_VARNAME()
+      return conf.ConfigExpression((self.tree.lookup(varname),), varname)
     op = self.next()
-    if op not in '\'"':
-      self.syntax_error('Invalid start of expression')
     # Parse literal expression 
     if op == u'\'':
       exl = []
index b065d04b6c19ce3c8ce5d98a752f5c8ccb964a00..85cf7dfb81ba28d56e55fd066de252ffd538f82e 100644 (file)
@@ -25,15 +25,16 @@ class TestConfig(unittest.TestCase):
     return s.var(varname, create=False).value()
 
   def eqparse(s, string, *args, **kwargs):
+    "Parse expression `s`, return parts that should be equal to anoter run of `eqparse(s)`."
     return [(i[0], i[1].operation) for i in s.parse(string, *args, **kwargs)]
 
 
 class TestParser(TestConfig):
-  s1 = r"""a="1";z{b='2';w{S.Tr_an-g.e='""'}};c.d='\n';e="{a}{b}";e+='{c.d}';a+="\"\n\{\}";f+='Z{a.b}'"""
+  s1 = r"""a="1";z{b='2';w{S.Tr_an-g.e='"'}};c.d='\n';e="{a}{b}";e+='{c.d}';a+="\"\n\{\}";f+='Z{a.b}';e+=c.d;e+=c;e+=a"""
   s2 = '\t\n \n ' + s1.replace('=', '= \n ').replace(';', '\t \n\t \n ').replace('+=',' \n += ') + '\n\n '
 
   def test_noWS(s):
-    assert len(s.parse(s.s1)) == 8
+    assert len(s.parse(s.s1)) == 11
 
   def test_noWS_COMMENT(s):
     assert s.eqparse(s.s1+'#COMMENT') == s.eqparse(s.s1+'#') == s.eqparse(s.s1+'#\n') == s.eqparse(s.s1+'\n#')
@@ -53,6 +54,8 @@ class TestParser(TestConfig):
     s.assertRaises(ConfigSyntaxError, s.parse, "a='\"")
     s.assertRaises(ConfigSyntaxError, s.parse, 'a="{a@b}"')
     s.assertRaises(ConfigSyntaxError, s.parse, 'a="A{A"')
+    s.assertRaises(ConfigSyntaxError, s.parse, 'a=b"42"')
+    s.assertRaises(ConfigSyntaxError, s.parse, 'a=b.c.d.')
 
   def test_error_location(s):
     try: s.parse('\t \n  \n  { \n \n ')
@@ -72,6 +75,7 @@ class TestParser(TestConfig):
     s.assertRaises(ConfigSyntaxError, s.parse, "if '{a}'=='{b}' and ''!='' {}")
     s.parse('if ((#C\n (\n (not not not""!="")\n#C\n)\t ) ) {}')
     s.parse('if (""=="" and not (not not ""!="" or ""=="")){}')
+    s.parse('if ((a=="{b}" and a.b.c!=c.b.a)or x!=y){}')
     s.parse('if(""==""){a{if(""==""){if(""==""){b{if(""==""){if(""==""){}}}}}}}')
     s.assertRaises(ConfigSyntaxError, s.parse, "if notnot'{a}'=='{b}' {}")
     s.assertRaises(ConfigSyntaxError, s.parse, "if ('{a}'=='{b}' not and ''!='') {}")
@@ -96,6 +100,11 @@ class TestConfigEval(TestConfig):
   def test_escape_chars(s):
     s.parse(r"""a='{a}\\\\#\n'; b="{a}'\"\{\}"; c='\'; c+="\{{b}\}";""")
     assert s.val('c') == r"""\{{a}\\\\#\n'"{}}"""
+
+  def test_expressions(s):
+    s.parse('A="4"; B.B=\'2\'; B.A=A; B.C="{B.A}{B.B}"; if B.C=="42" {D=C}; C="OK"')
+    assert s.val('D') == 'OK'
+  
   ts = 'a="A:"; if "{c1}"=="1" {a+="C1"; b="B"; if ("{c2a}"=="1" or not "{c2b}"=="1") { a+="C2"; '\
     'if ("{c3a}"=="1" and "{c3b}"=="1") { a+="C3" }}}'
 
@@ -200,7 +209,7 @@ class TestConfigEval(TestConfig):
 
 
 
-# TODO: Test conditions
+# TODO: Test priority
 # TODO: Fail on 1st April
 # TODO: Somehow add log.debug('Maximum encountered depth: %d', conf.debug_maxdepth)