[Checkins] SVN: z3c.pt/trunk/ Added support for semi-colon literals in string-expressions.

Malthe Borch mborch at gmail.com
Mon Aug 11 10:53:12 EDT 2008


Log message for revision 89653:
  Added support for semi-colon literals in string-expressions.

Changed:
  U   z3c.pt/trunk/CHANGES.txt
  U   z3c.pt/trunk/src/z3c/pt/expressions.py

-=-
Modified: z3c.pt/trunk/CHANGES.txt
===================================================================
--- z3c.pt/trunk/CHANGES.txt	2008-08-11 14:04:40 UTC (rev 89652)
+++ z3c.pt/trunk/CHANGES.txt	2008-08-11 14:53:12 UTC (rev 89653)
@@ -4,6 +4,9 @@
 Version 1.0dev
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+- String-expressions may now contain semi-colons using a double
+  semi-colon literal (;;). [malthe]
+
 - Get rid of package-relative magic in constructor of BaseTemplateFile
   in favor of just requiring an absolute path or a path relative
   to getcwd(). Rationale: it didn't work when called from __main__

Modified: z3c.pt/trunk/src/z3c/pt/expressions.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/expressions.py	2008-08-11 14:04:40 UTC (rev 89652)
+++ z3c.pt/trunk/src/z3c/pt/expressions.py	2008-08-11 14:53:12 UTC (rev 89653)
@@ -154,7 +154,12 @@
         """
         
         >>> class MockExpressionTranslation(ExpressionTranslation):
+        ...     def validate(self, string):
+        ...         if string == '' or ';' in string:
+        ...             raise SyntaxError()
+        ...
         ...     def expression(self, string):
+        ...         self.validate(string)
         ...         return types.value(string.strip())
         
         >>> definitions = MockExpressionTranslation().definitions
@@ -211,7 +216,6 @@
         string = string.replace('\n', '').strip()
 
         defines = []
-
         i = 0
         while i < len(string):
             while string[i] == ' ':
@@ -238,32 +242,41 @@
 
             # get expression
             i = j + len(string) - j - len(string[j:].lstrip())
-            while j < len(string):
-                token = string[i:]
-                if token.startswith('=='):
-                    raise ValueError("Invalid variable definition (%s)." % string)
-                elif token.startswith('='):
-                    i += 1
-                elif token.startswith('in'):
-                    i += 2
-                
-                j = string.find(';', j+1)
-                if j == -1:
-                    j = len(string)
 
+            token = string[i:]
+            if token.startswith('=='):
+                raise ValueError("Invalid variable definition (%s)." % string)
+            elif token.startswith('='):
+                i += 1
+            elif token.startswith('in'):
+                i += 2
+
+            try:
+                expr = self.expression(string[i:])
+                j = -1
+            except SyntaxError, e:
+                expr = None
+                j = len(string)
+            
+            while j > i:
+                j = string.rfind(';', i, j)
+                if j < 0:
+                    raise e
+
                 try:
                     expr = self.expression(string[i:j])
                 except SyntaxError, e:
-                    if j < len(string):
+                    if string.rfind(';', i, j) > 0:
                         continue
-                        
                     raise e
+                
                 break
-            else:
-                expr = None
-
+                
             defines.append((var, expr))
 
+            if j < 0:
+                break
+            
             i = j + 1
 
         return types.definitions(defines)
@@ -475,6 +488,7 @@
 
     def validate(self, string):
         self.interpolate(string)
+        self.split(string)
 
     def translate(self, string):
         return types.join(self.split(string))
@@ -520,14 +534,14 @@
 
         m = self.translator.interpolate(string)
         if m is None:
-            return (string,)
+            return (self._unescape(string),)
 
         parts = []
         
         start = m.start()
         if start > 0:
             text = string[:m.start()+1]
-            parts.append(text)
+            parts.append(self._unescape(text))
 
         expression = m.group('expression')
         parts.append(self.translator.expression(expression))
@@ -538,6 +552,31 @@
 
         return tuple(parts)
 
+    def definitions(self, string):
+        """
+        
+        >>> definitions = StringTranslation(PythonTranslation).definitions
+        
+        Semi-colon literal.
+        
+        >>> definitions("variable part1;; part2")
+        definitions((declaration('variable',), join('part1; part2',)),)
+
+        >>> definitions("variable1 part1;; part2; variable2 part3")
+        definitions((declaration('variable1',), join('part1; part2',)),
+                    (declaration('variable2',), join('part3',)))
+    
+        """
+
+        return super(StringTranslation, self).definitions(string)
+
+    def _unescape(self, string):
+        i = string.rfind(';')
+        if i > 0 and i != string.rfind(';'+';') + 1:
+            raise SyntaxError(
+                "Semi-colons in string-expressions must be escaped.")
+        return string.replace(';;', ';')
+        
 class PathTranslation(ExpressionTranslation):
     path_regex = re.compile(r'^((nocall|not):\s*)*([A-Za-z_]+)(/[A-Za-z_ at -]+)*$')
 



More information about the Checkins mailing list