Commit 16e9bae3 authored by Guido van Rossum's avatar Guido van Rossum

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!
parent c2ec3bb4
...@@ -172,7 +172,6 @@ class TALInterpreter: ...@@ -172,7 +172,6 @@ class TALInterpreter:
self.html = 0 self.html = 0
self.endsep = "/>" self.endsep = "/>"
self.macroStack = [] self.macroStack = []
self.definingMacro = None
self.position = None, None # (lineno, offset) self.position = None, None # (lineno, offset)
self.col = 0 self.col = 0
self.level = 0 self.level = 0
...@@ -193,6 +192,23 @@ class TALInterpreter: ...@@ -193,6 +192,23 @@ class TALInterpreter:
assert self.level == level assert self.level == level
assert self.scopeLevel == scopeLevel 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): def __call__(self):
assert self.level == 0 assert self.level == 0
assert self.scopeLevel == 0 assert self.scopeLevel == 0
...@@ -303,33 +319,40 @@ class TALInterpreter: ...@@ -303,33 +319,40 @@ class TALInterpreter:
value = evalue value = evalue
if value is None: if value is None:
ok = 0 ok = 0
elif action == 2 and self.macroStack: elif action == 2 and self.metal:
i = string.rfind(name, ":") + 1 i = string.rfind(name, ":") + 1
prefix, suffix = name[:i], name[i:] prefix, suffix = name[:i], name[i:]
##self.dumpMacroStack(prefix, suffix, value)
what, macroName, slots = self.macroStack[-1]
if suffix == "define-macro": if suffix == "define-macro":
if len(self.macroStack) == 1: if what == "use-macro":
macroName, slots = self.macroStack[-1]
name = prefix + "use-macro" name = prefix + "use-macro"
value = macroName value = macroName
else: else:
ok = 0 assert what == "define-macro"
if suffix == "fill-slot": i = self.macroContext("use-macro")
macroName, slots = self.macroStack[0] if i >= 0:
if not slots.has_key(value): j = self.macroContext("define-slot")
ok = 0 if j > i:
if suffix == "define-slot" and not self.definingMacro: name = prefix + "use-macro"
name = prefix + "fill-slot" 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 elif action == 1: # Unexecuted insert
ok = 0 ok = 0
return ok, name, value return ok, name, value
## def dumpMacroStack(self, prefix, suffix, value): def dumpMacroStack(self, prefix, suffix, value):
## sys.stderr.write("+-- %s%s = %s\n" % (prefix, suffix, value)) sys.stderr.write("+---- %s%s = %s\n" % (prefix, suffix, value))
## for i in range(len(self.macroStack)): for i in range(len(self.macroStack)):
## macroName, slots = self.macroStack[i] what, macroName, slots = self.macroStack[i]
## sys.stderr.write("| %3d. %-20s %s\n" % sys.stderr.write("| %2d. %-12s %-12s %s\n" %
## (i, macroName, slots.keys())) (i, what, macroName, slots and slots.keys()))
## sys.stderr.write("+--------------------------------------\n") sys.stderr.write("+--------------------------------------\n")
def do_endTag(self, name): def do_endTag(self, name):
self.stream_write("</%s>" % name) self.stream_write("</%s>" % name)
...@@ -428,10 +451,12 @@ class TALInterpreter: ...@@ -428,10 +451,12 @@ class TALInterpreter:
self.interpret(block) self.interpret(block)
def do_defineMacro(self, macroName, macro): def do_defineMacro(self, macroName, macro):
save = self.definingMacro if not self.metal:
self.definingMacro = macroName self.interpret(macro)
return
self.pushMacro("define-macro", macroName, None)
self.interpret(macro) self.interpret(macro)
self.definingMacro = save self.popMacro()
def do_useMacro(self, macroName, macroExpr, compiledSlots, block): def do_useMacro(self, macroName, macroExpr, compiledSlots, block):
if not self.metal: if not self.metal:
...@@ -449,24 +474,32 @@ class TALInterpreter: ...@@ -449,24 +474,32 @@ class TALInterpreter:
if mode != (self.html and "html" or "xml"): if mode != (self.html and "html" or "xml"):
raise METALError("macro %s has incompatible mode %s" % raise METALError("macro %s has incompatible mode %s" %
(`macroName`, `mode`), self.position) (`macroName`, `mode`), self.position)
if len(self.macroStack) >= self.stackLimit: self.pushMacro("use-macro", macroName, compiledSlots)
raise METALError("macro nesting limit (%d) exceeded "
"by macro %s" % (self.stackLimit, `macroName`))
self.macroStack.append((macroName, compiledSlots))
self.interpret(macro) self.interpret(macro)
self.macroStack.pop() self.popMacro()
def do_fillSlot(self, slotName, block): def do_fillSlot(self, slotName, block):
if not self.metal:
self.interpret(block)
return
self.pushMacro("fill-slot", slotName, None)
self.interpret(block) self.interpret(block)
self.popMacro()
def do_defineSlot(self, slotName, block): def do_defineSlot(self, slotName, block):
if not self.metal:
self.interpret(block)
return
slot = None slot = None
for macroName, slots in self.macroStack: for what, macroName, slots in self.macroStack:
slot = slots.get(slotName) or slot if what == "use-macro" and slots is not None:
slot = slots.get(slotName, slot)
self.pushMacro("define-slot", slotName, None)
if slot: if slot:
self.interpret(slot) self.interpret(slot)
else: else:
self.interpret(block) self.interpret(block)
self.popMacro()
def do_onError(self, block, handler): def do_onError(self, block, handler):
if not self.tal: if not self.tal:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment