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

Add an optional expressionCompiler argument to the [ME]TALCompiler

class constructor, so a caller can pass in an expression compiler.
Every expression occurring in the syntax is compiled first (even the
macro name in use-macro; but not slot names, nor the macro name in
define-macro).  If the expressionCompiler argument is left
unspecified, a default compiler is chosen whose compiled output is
identical to its input.
parent c2bd6594
...@@ -119,10 +119,18 @@ KNOWN_TAL_ATTRIBUTES = [ ...@@ -119,10 +119,18 @@ KNOWN_TAL_ATTRIBUTES = [
"attributes", "attributes",
] ]
class DummyCompiler:
def compile(self, expr):
return expr
class METALCompiler(DOMVisitor): class METALCompiler(DOMVisitor):
def __init__(self, document): def __init__(self, document, expressionCompiler=None):
DOMVisitor.__init__(self, document) DOMVisitor.__init__(self, document)
if not expressionCompiler:
expressionCompiler = DummyCompiler()
self.expressionCompiler = expressionCompiler
def __call__(self): def __call__(self):
self.macros = {} self.macros = {}
...@@ -134,6 +142,9 @@ class METALCompiler(DOMVisitor): ...@@ -134,6 +142,9 @@ class METALCompiler(DOMVisitor):
assert not self.stack assert not self.stack
return self.program, self.macros return self.program, self.macros
def compileExpression(self, expr):
return self.expressionCompiler.compile(expr)
def pushProgram(self): def pushProgram(self):
self.stack.append(self.program) self.stack.append(self.program)
self.program = [] self.program = []
...@@ -234,7 +245,8 @@ class METALCompiler(DOMVisitor): ...@@ -234,7 +245,8 @@ class METALCompiler(DOMVisitor):
self.pushProgram() self.pushProgram()
self.visitElement(slotNode) self.visitElement(slotNode)
compiledSlots[slotName] = self.popProgram() compiledSlots[slotName] = self.popProgram()
self.emit("useMacro", macroName, compiledSlots) cexpr = self.compileExpression(macroName)
self.emit("useMacro", cexpr, compiledSlots)
return return
macroName = node.getAttributeNS(ZOPE_METAL_NS, "define-macro") macroName = node.getAttributeNS(ZOPE_METAL_NS, "define-macro")
if macroName: if macroName:
...@@ -297,7 +309,7 @@ class TALCompiler(METALCompiler): ...@@ -297,7 +309,7 @@ class TALCompiler(METALCompiler):
# Extending METAL method to add attribute replacements # Extending METAL method to add attribute replacements
def getAttributeList(self, node): def getAttributeList(self, node):
attrList = METALCompiler.getAttributeList(self, node) attrList = METALCompiler.getAttributeList(self, node)
attrDict = getAttributeReplacements(node) attrDict = self.getAttributeReplacements(node)
if not attrDict: if not attrDict:
return attrList return attrList
list = [] list = []
...@@ -337,10 +349,11 @@ class TALCompiler(METALCompiler): ...@@ -337,10 +349,11 @@ class TALCompiler(METALCompiler):
else: else:
scope, name, expr = m.group(1, 2, 3) scope, name, expr = m.group(1, 2, 3)
scope = scope or "local" scope = scope or "local"
cexpr = self.compileExpression(expr)
if scope == "local": if scope == "local":
self.emit("setLocal", name, expr) self.emit("setLocal", name, cexpr)
else: else:
self.emit("setGlobal", name, expr) self.emit("setGlobal", name, cexpr)
def conditionalElement(self, node): def conditionalElement(self, node):
condition = node.getAttributeNS(ZOPE_TAL_NS, "condition") condition = node.getAttributeNS(ZOPE_TAL_NS, "condition")
...@@ -387,18 +400,19 @@ class TALCompiler(METALCompiler): ...@@ -387,18 +400,19 @@ class TALCompiler(METALCompiler):
key, expr = parseSubstitution(arg) key, expr = parseSubstitution(arg)
if not key: if not key:
return 0 return 0
attrDict = getAttributeReplacements(node) attrDict = self.getAttributeReplacements(node)
self.doSubstitution(key, expr, attrDict) self.doSubstitution(key, expr, attrDict)
return 1 return 1
def doSubstitution(self, key, expr, attrDict): def doSubstitution(self, key, expr, attrDict):
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", expr) self.emit("insertText", cexpr)
else: else:
assert key == "structure" assert key == "structure"
self.emit("insertStructure", expr, attrDict) self.emit("insertStructure", cexpr, attrDict)
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)
...@@ -406,18 +420,21 @@ class TALCompiler(METALCompiler): ...@@ -406,18 +420,21 @@ class TALCompiler(METALCompiler):
print "Bad syntax in z:repeat:", `arg` print "Bad syntax in z:repeat:", `arg`
return 0 return 0
name, expr = m.group(1, 2) name, expr = m.group(1, 2)
cexpr = self.compileExpression(expr)
self.pushProgram() self.pushProgram()
self.emitElement(node) self.emitElement(node)
block = self.popProgram() block = self.popProgram()
self.emit("loop", name, expr, block) self.emit("loop", name, cexpr, block)
return 1 return 1
def getAttributeReplacements(node): def getAttributeReplacements(self, node):
attributes = node.getAttributeNS(ZOPE_TAL_NS, "attributes") attrDict = {}
if not attributes: value = node.getAttributeNS(ZOPE_TAL_NS, "attributes")
return {} if value:
else: rawDict = parseAttributeReplacements(value)
return parseAttributeReplacements(attributes) for key, expr in rawDict.items():
attrDict[key] = self.compileExpression(expr)
return attrDict
def test(): def test():
from driver import FILE, parsefile from driver import FILE, parsefile
......
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