[ZPT] CVS: Packages/TAL - CHANGES.txt:1.7.2.1 HISTORY.txt:1.3.2.1 TALGenerator.py:1.48.2.1

Evan Simpson evan@zope.com
Tue, 2 Oct 2001 14:20:08 -0400


Update of /cvs-repository/Packages/TAL
In directory cvs.zope.org:/tmp/cvs-serv30568

Modified Files:
      Tag: tal-1_4_0
	CHANGES.txt HISTORY.txt TALGenerator.py 
Log Message:
Bugfixes from trunk


=== Packages/TAL/CHANGES.txt 1.7 => 1.7.2.1 ===
   file HISTORY.txt.
 
-    Version 1.4.0
+    Version 1.4.1
 
-      Features Added
-
-        - Added TAL statement: omit_tag="[<boolean expr>]" replaces
-          the statement tag with its contents if the boolean
-          expression is true or omitted.
+      Bugs Fixed
 
-        - The TAL and METAL namespaces can be applied to tag names,
-          tags in these namespaces are removed from rendered output
-          (leaving the contents in place, as with omit_tag)
-          whenever attributes in these namespaces would be, and
-          tag attributes without explicit namespaces default to the
-          tag's namespace (per XML spec).
+        - tal:on-error was mangling other attributes
 
-      Bugs Fixed
+        - TAL and METAL attributes with blank values were ignored.
 
+        - METAL statement nesting was not enforced.


=== Packages/TAL/HISTORY.txt 1.3 => 1.3.2.1 ===
   in the file CHANGES.txt.
 
+    Version 1.4.0
+
+      Features Added
+
+        - Added TAL statement: omit_tag="[<boolean expr>]" replaces
+          the statement tag with its contents if the boolean
+          expression is true or omitted.
+
+        - The TAL and METAL namespaces can be applied to tag names,
+          tags in these namespaces are removed from rendered output
+          (leaving the contents in place, as with omit_tag)
+          whenever attributes in these namespaces would be, and
+          tag attributes without explicit namespaces default to the
+          tag's namespace (per XML spec).
+
     Version 1.3.3
 
       Bugs Fixed


=== Packages/TAL/TALGenerator.py 1.48 => 1.48.2.1 ===
 class TALGenerator:
 
+    inMacroUse = 0
+    inMacroDef = 0
+    
     def __init__(self, expressionCompiler=None, xml=1):
         if not expressionCompiler:
             from DummyEngine import DummyEngine
@@ -334,27 +337,39 @@
 
     def emitDefineMacro(self, macroName, position=(None, None)):
         program = self.popProgram()
+        macroName = string.strip(macroName)
         if self.macros.has_key(macroName):
-            raise METALError("duplicate macro definition: %s" % macroName,
+            raise METALError("duplicate macro definition: %s" % `macroName`,
                              position)
+        if not re.match('%s$' % NAME_RE, macroName):
+            raise METALError("invalid macro name: %s" % `macroName`, position)
         self.macros[macroName] = program
+        self.inMacroDef = self.inMacroDef - 1
         self.emit("defineMacro", macroName, program)
 
     def emitUseMacro(self, expr):
         cexpr = self.compileExpression(expr)
         program = self.popProgram()
+        self.inMacroUse = 0
         self.emit("useMacro", expr, cexpr, self.popSlots(), program)
 
-    def emitDefineSlot(self, slotName):
+    def emitDefineSlot(self, slotName, position=(None, None)):
         program = self.popProgram()
+        slotName = string.strip(slotName)
+        if not re.match('%s$' % NAME_RE, slotName):
+            raise METALError("invalid slot name: %s" % `slotName`, position)
         self.emit("defineSlot", slotName, program)
 
     def emitFillSlot(self, slotName, position=(None, None)):
         program = self.popProgram()
+        slotName = string.strip(slotName)
         if self.slots.has_key(slotName):
-            raise METALError("duplicate fill-slot name: %s" % slotName,
+            raise METALError("duplicate fill-slot name: %s" % `slotName`,
                              position)
+        if not re.match('%s$' % NAME_RE, slotName):
+            raise METALError("invalid slot name: %s" % `slotName`, position)
         self.slots[slotName] = program
+        self.inMacroUse = 1
         self.emit("fillSlot", slotName, program)
 
     def unEmitWhitespace(self):
@@ -428,12 +443,19 @@
                 self.emitEndElement(name, isend)
             return
 
-        for key in taldict.keys():
+        for key, value in taldict.items():
             if key not in KNOWN_TAL_ATTRIBUTES:
                 raise TALError("bad TAL attribute: " + `key`, position)
-        for key in metaldict.keys():
+            if not (value or key == 'omit-tag'):
+                raise TALError("missing value for TAL attribute: " +
+                               `key`, position)
+        for key, value in metaldict.items():
             if key not in KNOWN_METAL_ATTRIBUTES:
-                raise METALError("bad METAL attribute: " + `key`, position)
+                raise METALError("bad METAL attribute: " + `key`,
+                position)
+            if not value:
+                raise TALError("missing value for METAL attribute: " +
+                               `key`, position)
         todo = {}
         defineMacro = metaldict.get("define-macro")
         useMacro = metaldict.get("use-macro")
@@ -463,21 +485,35 @@
         if position != (None, None):
             # XXX at some point we should insist on a non-trivial position
             self.emit("setPosition", position)
-        if defineMacro:
-            self.pushProgram()
-            self.emit("version", TAL_VERSION)
-            self.emit("mode", self.xml and "xml" or "html")
-            todo["defineMacro"] = defineMacro
-        if useMacro:
-            self.pushSlots()
-            self.pushProgram()
-            todo["useMacro"] = useMacro
-        if fillSlot:
-            self.pushProgram()
-            todo["fillSlot"] = fillSlot
-        if defineSlot:
-            self.pushProgram()
-            todo["defineSlot"] = defineSlot
+        if self.inMacroUse:
+            if fillSlot:
+                self.pushProgram()
+                todo["fillSlot"] = fillSlot
+                self.inMacroUse = 0
+        else:
+            if fillSlot:
+                raise METALError, ("fill-slot must be within a use-macro",
+                                   position)
+        if not self.inMacroUse:
+            if defineMacro:
+                self.pushProgram()
+                self.emit("version", TAL_VERSION)
+                self.emit("mode", self.xml and "xml" or "html")
+                todo["defineMacro"] = defineMacro
+                self.inMacroDef = self.inMacroDef + 1
+            if useMacro:
+                self.pushSlots()
+                self.pushProgram()
+                todo["useMacro"] = useMacro
+                self.inMacroUse = 1
+            if defineSlot:
+                if not self.inMacroDef:
+                    raise METALError, (
+                        "define-slot must be within a define-macro",
+                        position)
+                self.pushProgram()
+                todo["defineSlot"] = defineSlot
+
         if taldict:
             dict = {}
             for item in attrlist:
@@ -487,7 +523,7 @@
             todo["scope"] = 1
         if onError:
             self.pushProgram() # handler
-            self.emitStartTag(name, attrlist)
+            self.emitStartTag(name, list(attrlist)) # Must copy attrlist!
             self.pushProgram() # block
             todo["onError"] = onError
         if define:
@@ -580,7 +616,7 @@
         if scope:
             self.emit("endScope")
         if defineSlot:
-            self.emitDefineSlot(defineSlot)
+            self.emitDefineSlot(defineSlot, position)
         if fillSlot:
             self.emitFillSlot(fillSlot, position)
         if useMacro: