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

Implement revised TAL language:

- z:omit is gone

- new, separate command to loop over a subtree: <tag z:repeat="var expr">

- remove syntactic sugar from z:define (no "as"), z:attributes (no "=")

- refactored a bit to accommodate this
parent 9142fb81
...@@ -131,11 +131,6 @@ class TALVisitor(CopyingDOMVisitor): ...@@ -131,11 +131,6 @@ class TALVisitor(CopyingDOMVisitor):
if slotNode: if slotNode:
self.visitElement(slotNode) self.visitElement(slotNode)
return return
if node.hasAttributeNS(ZOPE_TAL_NS, "omit"):
# XXX Question: should 'omit' be done before or after
# 'define'? (I.e., is it a shortcut for
# z:condition:"false" or is it stronger?)
return
defines = node.getAttributeNS(ZOPE_TAL_NS, "define") defines = node.getAttributeNS(ZOPE_TAL_NS, "define")
if defines: if defines:
self.engine.beginScope() self.engine.beginScope()
...@@ -155,18 +150,24 @@ class TALVisitor(CopyingDOMVisitor): ...@@ -155,18 +150,24 @@ class TALVisitor(CopyingDOMVisitor):
attrDict = parseAttributeReplacements(attributes) attrDict = parseAttributeReplacements(attributes)
insert = node.getAttributeNS(ZOPE_TAL_NS, "insert") insert = node.getAttributeNS(ZOPE_TAL_NS, "insert")
replace = node.getAttributeNS(ZOPE_TAL_NS, "replace") replace = node.getAttributeNS(ZOPE_TAL_NS, "replace")
if not (insert or replace): repeat = node.getAttributeNS(ZOPE_TAL_NS, "repeat")
done = 0 n = 0
else: if insert: n = n+1
if insert and replace: if replace: n = n+1
print "Warning: z:insert overrides z:replace on the same node" if repeat: n = n+1
# XXX check for replace on documentElement if n > 1:
done = self.doModify(node, insert, insert or replace, attrDict) print "Please use only one of z:insert, z:replace, z:repeat"
if not done: ok = 0
self.copyElement(node) if insert:
self.copyAttributes(node, attrDict) ok = self.doInsert(node, insert, attrDict)
self.visitAllChildren(node) if not ok and replace:
self.backUp() # XXX Check that this isn't the documentElement
ok = self.doReplace(node, replace, attrDict)
if not ok and repeat:
# XXX Check that this isn't the documentElement
ok = self.doRepeat(node, repeat, attrDict)
if not ok:
self.copySubtree(node, attrDict)
def findMacro(self, macroName): def findMacro(self, macroName):
# XXX This is not written for speed :-) # XXX This is not written for speed :-)
...@@ -191,7 +192,7 @@ class TALVisitor(CopyingDOMVisitor): ...@@ -191,7 +192,7 @@ class TALVisitor(CopyingDOMVisitor):
def doDefine(self, arg): def doDefine(self, arg):
for part in splitParts(arg): for part in splitParts(arg):
m = re.match( m = re.match(
r"\s*(?:(global|local)\s+)?(%s)\s+as\s+(.*)" % NAME_RE, part) r"\s*(?:(global|local)\s+)?(%s)\s+(.*)" % NAME_RE, part)
if not m: if not m:
print "Bad syntax in z:define argument:", `part` print "Bad syntax in z:define argument:", `part`
else: else:
...@@ -203,62 +204,33 @@ class TALVisitor(CopyingDOMVisitor): ...@@ -203,62 +204,33 @@ class TALVisitor(CopyingDOMVisitor):
else: else:
self.engine.setGlobal(name, value) self.engine.setGlobal(name, value)
def doModify(self, node, inserting, arg, attrDict): def doInsert(self, node, arg, attrDict):
m = re.match( key, expr = parseSubstitution(arg)
r"(?:\s*(text|structure|for\s+(%s)\s+in)\s+)?(.*)" % NAME_RE, arg)
if not m:
print "Bad syntax in z:insert/replace:", `arg`
return 0
key, name, expr = m.group(1, 2, 3)
if not key: if not key:
key = "text" return 0
saveNode = self.curNode
if key[:3] == "for":
if inserting:
rv = self.doInsertLoop(node, name, expr, attrDict)
else:
rv = self.doReplaceLoop(node, name, expr, attrDict)
else:
rv = self.doNonLoop(node, inserting, key, expr, attrDict)
self.curNode = saveNode
return rv
def doInsertLoop(self, node, name, expr, attrDict):
sequence = self.engine.evaluateSequence(expr)
self.copyElement(node) self.copyElement(node)
self.copyAttributes(node, attrDict) self.copyAttributes(node, attrDict)
for item in sequence: self.doSubstitution(key, expr, {})
self.engine.setLocal(name, item)
self.visitAllChildren(node)
self.backUp() self.backUp()
return 1 return 1
def doReplaceLoop(self, node, name, expr, attrDict): def doReplace(self, node, arg, attrDict):
if not self.newDocument: key, expr = parseSubstitution(arg)
print "Can't have a z:replace for loop on the documentElement" if not key:
return 0 return 0
sequence = self.engine.evaluateSequence(expr) self.doSubstitution(key, expr, attrDict)
for item in sequence:
self.engine.setLocal(name, item)
self.copyElement(node)
self.copyAttributes(node, attrDict)
self.visitAllChildren(node)
self.backUp()
return 1 return 1
def doNonLoop(self, node, inserting, key, expr, attrDict): def doSubstitution(self, key, expr, attrDict):
if inserting:
self.copyElement(node)
self.copyAttributes(node, attrDict)
if key == "text": if key == "text":
if attrDict and not inserting: if attrDict:
print "Warning: z:attributes unused for text replacement" print "Warning: z:attributes unused for text replacement"
data = self.engine.evaluateText(expr) data = self.engine.evaluateText(expr)
newChild = self.newDocument.createTextNode(str(data)) newChild = self.newDocument.createTextNode(str(data))
self.curNode.appendChild(newChild) self.curNode.appendChild(newChild)
if key == "structure": elif key == "structure":
data = self.engine.evaluateStructure(expr) data = self.engine.evaluateStructure(expr)
attrDone = inserting or not attrDict attrDone = not attrDict
for newChild in data: for newChild in data:
self.curNode.appendChild(newChild) self.curNode.appendChild(newChild)
if not attrDone and newChild.nodeType == Node.ELEMENT_NODE: if not attrDone and newChild.nodeType == Node.ELEMENT_NODE:
...@@ -267,8 +239,27 @@ class TALVisitor(CopyingDOMVisitor): ...@@ -267,8 +239,27 @@ class TALVisitor(CopyingDOMVisitor):
if not attrDone: if not attrDone:
# Apparently no element nodes were inserted # Apparently no element nodes were inserted
print "Warning: z:attributes unused for struct replacement" print "Warning: z:attributes unused for struct replacement"
def doRepeat(self, node, arg, attrDict):
if not self.newDocument:
print "Can't have z:repeat on the documentElement"
return 0
m = re.match("\s*(%s)\s+(.*)" % NAME_RE, arg)
if not m:
print "Bad syntax in z:repeat:", `arg`
return 0
name, expr = m.group(1, 2)
iterator = self.engine.setupLoop(name, expr)
while iterator.next():
self.copySubtree(node, attrDict)
return 1 return 1
def copySubtree(self, node, attrDict):
self.copyElement(node)
self.copyAttributes(node, attrDict)
self.visitAllChildren(node)
self.backUp()
def copyAttributes(self, node, attrDict): def copyAttributes(self, node, attrDict):
for attr in node.attributes.values(): for attr in node.attributes.values():
namespaceURI = attr.namespaceURI namespaceURI = attr.namespaceURI
...@@ -294,7 +285,7 @@ class TALVisitor(CopyingDOMVisitor): ...@@ -294,7 +285,7 @@ class TALVisitor(CopyingDOMVisitor):
def parseAttributeReplacements(arg): def parseAttributeReplacements(arg):
dict = {} dict = {}
for part in splitParts(arg): for part in splitParts(arg):
m = re.match(r"\s*([^\s=]+)\s*=\s*(.*)", part) m = re.match(r"\s*([^\s]+)\s*(.*)", part)
if not m: if not m:
print "Bad syntax in z:attributes:", `part` print "Bad syntax in z:attributes:", `part`
continue continue
...@@ -305,6 +296,16 @@ def parseAttributeReplacements(arg): ...@@ -305,6 +296,16 @@ def parseAttributeReplacements(arg):
dict[name] = expr dict[name] = expr
return dict return dict
def parseSubstitution(arg):
m = re.match(r"\s*(?:(text|structure)\s+)?(.*)", arg)
if not m:
print "Bad syntax in z:insert/replace:", `arg`
return None, None
key, expr = m.group(1, 2)
if not key:
key = "text"
return key, expr
def splitParts(arg): def splitParts(arg):
# Break in pieces at undoubled semicolons and # Break in pieces at undoubled semicolons and
# change double semicolons to singles: # change double semicolons to singles:
......
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