[ZPT] CVS: Packages/TAL - TALInterpreter.py:1.45

guido@digicool.com guido@digicool.com
Fri, 18 May 2001 18:18:04 -0400 (EDT)


Update of /cvs-repository/Packages/TAL
In directory korak.digicool.com:/tmp/cvs-serv26327

Modified Files:
	TALInterpreter.py 
Log Message:
Hopefully this fixes the endcases with nested macros.
At least this now passes Evan's test_metal1.html!

I had to restructure attrAction() and the macroStack() quite a bit.
The macro stack now has a mostly abstract interface (a few lookups
still dig directly into the stack).

Weekend!



--- Updated File TALInterpreter.py in package Packages/TAL --
--- TALInterpreter.py	2001/05/18 18:17:02	1.44
+++ TALInterpreter.py	2001/05/18 22:18:03	1.45
@@ -172,7 +172,6 @@
         self.html = 0
         self.endsep = "/>"
         self.macroStack = []
-        self.definingMacro = None
         self.position = None, None  # (lineno, offset)
         self.col = 0
         self.level = 0
@@ -193,6 +192,23 @@
         assert self.level == level
         assert self.scopeLevel == scopeLevel
 
+    def pushMacro(self, what, macroName, slots):
+        if len(self.macroStack) >= self.stackLimit:
+            raise METALError("macro nesting limit (%d) exceeded "
+                             "by %s %s" % (self.stackLimit, what, `macroName`))
+        self.macroStack.append((what, macroName, slots))
+
+    def popMacro(self):
+        return self.macroStack.pop()
+
+    def macroContext(self, what):
+        i = len(self.macroStack)
+        while i > 0:
+            i = i-1
+            if self.macroStack[i][0] == what:
+                return i
+        return -1
+
     def __call__(self):
         assert self.level == 0
         assert self.scopeLevel == 0
@@ -303,33 +319,40 @@
                     value = evalue
                     if value is None:
                         ok = 0
-        elif action == 2 and self.macroStack:
+        elif action == 2 and self.metal:
             i = string.rfind(name, ":") + 1
             prefix, suffix = name[:i], name[i:]
+            ##self.dumpMacroStack(prefix, suffix, value)
+            what, macroName, slots = self.macroStack[-1]
             if suffix == "define-macro":
-                if len(self.macroStack) == 1:
-                    macroName, slots = self.macroStack[-1]
+                if what == "use-macro":
                     name = prefix + "use-macro"
                     value = macroName
                 else:
-                    ok = 0
-            if suffix == "fill-slot":
-                macroName, slots = self.macroStack[0]
-                if not slots.has_key(value):
-                    ok = 0
-            if suffix == "define-slot" and not self.definingMacro:
-                name = prefix + "fill-slot"
+                    assert what == "define-macro"
+                    i = self.macroContext("use-macro")
+                    if i >= 0:
+                        j = self.macroContext("define-slot")
+                        if j > i:
+                            name = prefix + "use-macro"
+                        else:
+                            ok = 0
+            elif suffix == "define-slot":
+                assert what == "define-slot"
+                if self.macroContext("use-macro") >= 0:
+                    name = prefix + "fill-slot"
+
         elif action == 1: # Unexecuted insert
             ok = 0
         return ok, name, value
 
-##    def dumpMacroStack(self, prefix, suffix, value):
-##        sys.stderr.write("+-- %s%s = %s\n" % (prefix, suffix, value))
-##        for i in range(len(self.macroStack)):
-##            macroName, slots = self.macroStack[i]
-##            sys.stderr.write("|   %3d. %-20s %s\n" %
-##                             (i, macroName, slots.keys()))
-##        sys.stderr.write("+--------------------------------------\n")
+    def dumpMacroStack(self, prefix, suffix, value):
+        sys.stderr.write("+---- %s%s = %s\n" % (prefix, suffix, value))
+        for i in range(len(self.macroStack)):
+            what, macroName, slots = self.macroStack[i]
+            sys.stderr.write("| %2d. %-12s %-12s %s\n" %
+                             (i, what, macroName, slots and slots.keys()))
+        sys.stderr.write("+--------------------------------------\n")
 
     def do_endTag(self, name):
         self.stream_write("</%s>" % name)
@@ -428,10 +451,12 @@
             self.interpret(block)
 
     def do_defineMacro(self, macroName, macro):
-        save = self.definingMacro
-        self.definingMacro = macroName
+        if not self.metal:
+            self.interpret(macro)
+            return
+        self.pushMacro("define-macro", macroName, None)
         self.interpret(macro)
-        self.definingMacro = save
+        self.popMacro()
 
     def do_useMacro(self, macroName, macroExpr, compiledSlots, block):
         if not self.metal:
@@ -449,24 +474,32 @@
         if mode != (self.html and "html" or "xml"):
             raise METALError("macro %s has incompatible mode %s" %
                              (`macroName`, `mode`), self.position)
-        if len(self.macroStack) >= self.stackLimit:
-            raise METALError("macro nesting limit (%d) exceeded "
-                             "by macro %s" % (self.stackLimit, `macroName`))
-        self.macroStack.append((macroName, compiledSlots))
+        self.pushMacro("use-macro", macroName, compiledSlots)
         self.interpret(macro)
-        self.macroStack.pop()
+        self.popMacro()
 
     def do_fillSlot(self, slotName, block):
+        if not self.metal:
+            self.interpret(block)
+            return
+        self.pushMacro("fill-slot", slotName, None)
         self.interpret(block)
+        self.popMacro()
 
     def do_defineSlot(self, slotName, block):
+        if not self.metal:
+            self.interpret(block)
+            return
         slot = None
-        for macroName, slots in self.macroStack:
-            slot = slots.get(slotName) or slot
+        for what, macroName, slots in self.macroStack:
+            if what == "use-macro" and slots is not None:
+                slot = slots.get(slotName, slot)
+        self.pushMacro("define-slot", slotName, None)
         if slot:
             self.interpret(slot)
         else:
             self.interpret(block)
+        self.popMacro()
 
     def do_onError(self, block, handler):
         if not self.tal: