Commit d742f37b authored by Guido van Rossum's avatar Guido van Rossum

Add several new keyword arguments to the TALInterpreter class:

- metal to do macro expansion (default on)

- tal to do TAL expansion (default on)

- html for XHTML heuristics (default off).  See
  http://www.w3.org/TR/xhtml1/#guidelines for what this should do;
  currently all it does is to suppress the XML declaration and insert
  a space before the /> in minimized elements.

Changed the TALCompiler class to generate enough code to be able to
implement the tal=0 and metal=0 options to TALInterpreter; this meant
e.g. compiling the original contents of nodes subject to replacement.
parent 296f4fc6
...@@ -247,7 +247,10 @@ class METALCompiler(DOMVisitor): ...@@ -247,7 +247,10 @@ class METALCompiler(DOMVisitor):
self.visitElement(slotNode) self.visitElement(slotNode)
compiledSlots[slotName] = self.popProgram() compiledSlots[slotName] = self.popProgram()
cexpr = self.compileExpression(macroName) cexpr = self.compileExpression(macroName)
self.emit("useMacro", cexpr, compiledSlots) self.pushProgram()
self.compileElement(node)
block = self.popProgram()
self.emit("useMacro", cexpr, compiledSlots, block)
return return
macroName = node.getAttributeNS(ZOPE_METAL_NS, "define-macro") macroName = node.getAttributeNS(ZOPE_METAL_NS, "define-macro")
if macroName: if macroName:
...@@ -394,7 +397,10 @@ class TALCompiler(METALCompiler): ...@@ -394,7 +397,10 @@ class TALCompiler(METALCompiler):
if not key: if not key:
return 0 return 0
self.emitStartTag(node) self.emitStartTag(node)
self.doSubstitution(key, expr, {}) self.pushProgram()
self.visitAllChildren(node)
block = self.popProgram()
self.doSubstitution(key, expr, {}, block)
self.emitEndTag(node) self.emitEndTag(node)
return 1 return 1
...@@ -403,18 +409,21 @@ class TALCompiler(METALCompiler): ...@@ -403,18 +409,21 @@ class TALCompiler(METALCompiler):
if not key: if not key:
return 0 return 0
attrDict = self.getAttributeReplacements(node) attrDict = self.getAttributeReplacements(node)
self.doSubstitution(key, expr, attrDict) self.pushProgram()
self.emitElement(node)
block = self.popProgram()
self.doSubstitution(key, expr, attrDict, block)
return 1 return 1
def doSubstitution(self, key, expr, attrDict): def doSubstitution(self, key, expr, attrDict, block):
cexpr = self.compileExpression(expr) cexpr = self.compileExpression(expr)
if key == "text": if key == "text":
if attrDict: if attrDict:
print "Warning: z:attributes unused for text replacement" print "Warning: z:attributes unused for text replacement"
self.emit("insertText", cexpr) self.emit("insertText", cexpr, block)
else: else:
assert key == "structure" assert key == "structure"
self.emit("insertStructure", cexpr, attrDict) self.emit("insertStructure", cexpr, attrDict, block)
def doRepeat(self, node, arg): def doRepeat(self, node, arg):
m = re.match("\s*(%s)\s+(.*)" % NAME_RE, arg) m = re.match("\s*(%s)\s+(.*)" % NAME_RE, arg)
......
...@@ -96,17 +96,25 @@ from TALCompiler import TALCompiler ...@@ -96,17 +96,25 @@ from TALCompiler import TALCompiler
class TALInterpreter: class TALInterpreter:
def __init__(self, program, macros, engine, stream=None, def __init__(self, program, macros, engine, stream=None,
debug=0, wrap=60): debug=0, wrap=60, metal=1, tal=1, html=0):
self.program = program self.program = program
self.macros = macros self.macros = macros
self.engine = engine self.engine = engine
self.stream = stream or sys.stdout self.stream = stream or sys.stdout
self.debug = debug self.debug = debug
self.wrap = wrap self.wrap = wrap
self.metal = metal
self.tal = tal
self.html = html
self.slots = {} self.slots = {}
self.currentMacro = None self.currentMacro = None
def __call__(self): def __call__(self):
if self.html:
self.endsep = " />"
else:
self.endsep = "/>"
if not self.html:
self.stream_write('<?xml version="1.0" ?>\n') self.stream_write('<?xml version="1.0" ?>\n')
self.interpret(self.program) self.interpret(self.program)
self.stream_write("\n") self.stream_write("\n")
...@@ -138,7 +146,7 @@ class TALInterpreter: ...@@ -138,7 +146,7 @@ class TALInterpreter:
self.level = self.level - 1 self.level = self.level - 1
def do_startEndTag(self, name, attrList): def do_startEndTag(self, name, attrList):
self.do_startTag(name, attrList, "/>") self.do_startTag(name, attrList, self.endsep)
def do_startTag(self, name, attrList, end=">"): def do_startTag(self, name, attrList, end=">"):
if not attrList: if not attrList:
...@@ -150,10 +158,10 @@ class TALInterpreter: ...@@ -150,10 +158,10 @@ class TALInterpreter:
name, value = item[:2] name, value = item[:2]
if len(item) > 2: if len(item) > 2:
action = item[2] action = item[2]
if action == "replace" and len(item) > 3: if action == "replace" and len(item) > 3 and self.tal:
value = self.engine.evaluateText(item[3]) value = self.engine.evaluateText(item[3])
elif (action == "macroHack" and self.currentMacro and elif (action == "macroHack" and self.currentMacro and
name[-13:] == ":define-macro"): name[-13:] == ":define-macro" and self.metal):
name = name[:-13] + ":use-macro" name = name[:-13] + ":use-macro"
value = self.currentMacro value = self.currentMacro
s = "%s=%s" % (name, quote(value)) s = "%s=%s" % (name, quote(value))
...@@ -176,21 +184,31 @@ class TALInterpreter: ...@@ -176,21 +184,31 @@ class TALInterpreter:
self.engine.endScope() self.engine.endScope()
def do_setLocal(self, name, expr): def do_setLocal(self, name, expr):
if not self.tal:
return
value = self.engine.evaluateValue(expr) value = self.engine.evaluateValue(expr)
self.engine.setLocal(name, value) self.engine.setLocal(name, value)
def do_setGlobal(self, name, expr): def do_setGlobal(self, name, expr):
if not self.tal:
return
value = self.engine.evaluateValue(expr) value = self.engine.evaluateValue(expr)
self.engine.setGlobal(name, value) self.engine.setGlobal(name, value)
def do_insertText(self, expr): def do_insertText(self, expr, block):
if not self.tal:
self.interpret(block)
return
text = self.engine.evaluateText(expr) text = self.engine.evaluateText(expr)
if text is None: if text is None:
return return
text = cgi.escape(text) text = cgi.escape(text)
self.stream_write(text) self.stream_write(text)
def do_insertStructure(self, expr): def do_insertStructure(self, expr, block):
if not self.tal:
self.interpret(block)
return
structure = self.engine.evaluateStructure(expr) structure = self.engine.evaluateStructure(expr)
if structure is None: if structure is None:
return return
...@@ -203,11 +221,15 @@ class TALInterpreter: ...@@ -203,11 +221,15 @@ class TALInterpreter:
self.macros = saveMacros self.macros = saveMacros
def do_loop(self, name, expr, block): def do_loop(self, name, expr, block):
if not self.tal:
self.interpret(block)
return
iterator = self.engine.setRepeat(name, expr) iterator = self.engine.setRepeat(name, expr)
while iterator.next(): while iterator.next():
self.interpret(block) self.interpret(block)
def do_text(self, text): def do_text(self, text):
text = cgi.escape(text)
self.stream_write(text) self.stream_write(text)
def do_comment(self, text): def do_comment(self, text):
...@@ -216,13 +238,16 @@ class TALInterpreter: ...@@ -216,13 +238,16 @@ class TALInterpreter:
self.stream_write("-->") self.stream_write("-->")
def do_condition(self, condition, block): def do_condition(self, condition, block):
if self.engine.evaluateBoolean(condition): if not self.tal or self.engine.evaluateBoolean(condition):
self.interpret(block) self.interpret(block)
def do_defineMacro(self, macroName, macro): def do_defineMacro(self, macroName, macro):
self.interpret(macro) self.interpret(macro)
def do_useMacro(self, macroName, compiledSlots): def do_useMacro(self, macroName, compiledSlots, block):
if not self.metal:
self.interpret(block)
return
macro = self.engine.evaluateMacro(macroName) macro = self.engine.evaluateMacro(macroName)
save = self.slots, self.currentMacro save = self.slots, self.currentMacro
self.slots = compiledSlots self.slots = compiledSlots
...@@ -230,15 +255,15 @@ class TALInterpreter: ...@@ -230,15 +255,15 @@ class TALInterpreter:
self.interpret(macro) self.interpret(macro)
self.slots, self.currentMacro = save self.slots, self.currentMacro = save
def do_fillSlot(self, slotName, program): def do_fillSlot(self, slotName, block):
self.interpret(program) self.interpret(block)
def do_defineSlot(self, slotName, program): def do_defineSlot(self, slotName, block):
compiledSlot = self.slots.get(slotName) compiledSlot = self.metal and self.slots.get(slotName)
if compiledSlot: if compiledSlot:
self.interpret(compiledSlot) self.interpret(compiledSlot)
else: else:
self.interpret(program) self.interpret(block)
def quote(s): def quote(s):
if '"' in s and "'" not in s: if '"' in s and "'" not in s:
......
...@@ -143,11 +143,8 @@ def main(): ...@@ -143,11 +143,8 @@ def main():
file = FILE file = FILE
doc = parsefile(file) doc = parsefile(file)
if macros or compile: if macros or compile:
if macros:
it = precompiletree(doc)
else:
it = compiletree(doc) it = compiletree(doc)
interpretit(it) interpretit(it, tal=(not macros))
else: else:
doc = talizetree(doc) doc = talizetree(doc)
printtree(doc) printtree(doc)
...@@ -199,12 +196,12 @@ def compiletree(root): ...@@ -199,12 +196,12 @@ def compiletree(root):
from TALCompiler import TALCompiler from TALCompiler import TALCompiler
return TALCompiler(root)() return TALCompiler(root)()
def interpretit(it, engine=None, stream=None): def interpretit(it, engine=None, stream=None, tal=1):
from TALInterpreter import TALInterpreter from TALInterpreter import TALInterpreter
program, macros = it program, macros = it
if engine is None: if engine is None:
engine = DummyEngine(macros) engine = DummyEngine(macros)
TALInterpreter(program, macros, engine, stream, wrap=0)() TALInterpreter(program, macros, engine, stream, wrap=0, tal=tal)()
if __name__ == "__main__": if __name__ == "__main__":
main() main()
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