Commit 4bf04d3d authored by Guido van Rossum's avatar Guido van Rossum

- Fix use-macro expansion to properly retain the use-macro attribute

  value.  This affects TALCompiler.py and TALInterpreter.py, and
  affects the output of the non-local-macro expansion tests.  The
  TALVisitor.py module is *not* yet fixed to do this.

- In order to do this, I had to change the "program code" format for
  the attribute list: the 3rd item of an attribute description tuple,
  if present, now names an action, and the remaining tuple items are
  arguments for that action.  Two actions are recognized: "replace"
  replaces the attribute with the outcome of evaluating the expression
  given by the next tuple  item; "macroHack" replaces the attribute
  name with "use-macro" and its value with the current macro, but
  only if we're inside macro expansion and the attribute name ends in
  ":define-macro".

- The test suite is now error-free for "./runtest.py -c" but shows some
  errors for "./runtest.py".

- Added a primitive debugging flag to the TALInterpreter class.

- Update the README.
parent cc2e1475
......@@ -76,12 +76,9 @@ TO DO
Here are some things that should be done.
- Fix the tweaking of the define-macro attribute on macro expansion so
that:
(1) it is only tweaked if the proper prefix is used; and
(2) the argument is taken from the use-macro attribute.
- Add calls to an expression compiler
- Provide a framework for error messages (currently it just prints to
- Raise exceptions for all errors (currently it just prints to
stdout).
- Provide a dummy implementation of evaluateStructure()?
......
......@@ -84,9 +84,6 @@
##############################################################################
"""
Compile a DOM tree for efficient METAL and TAL expansion.
XXX TO DO:
- get macro define->use substitution in output right (currently ignores prefix)
"""
import string
......@@ -95,7 +92,7 @@ from xml.dom import Node
from DOMVisitor import DOMVisitor
from TALVisitor import ZOPE_TAL_NS, ZOPE_METAL_NS, NAME_RE
from TALVisitor import ZOPE_TAL_NS, ZOPE_METAL_NS, NAME_RE
from TALVisitor import macroIndexer, slotIndexer
from TALVisitor import splitParts, parseAttributeReplacements
from TALVisitor import parseSubstitution
......@@ -169,12 +166,14 @@ class METALCompiler(DOMVisitor):
elif attr.prefix == "xmlns":
self.newNS(attr.localName, attr.value)
list = []
# Add namespace declarations for the node itself
if node.namespaceURI:
if self.newNS(node.prefix, node.namespaceURI):
if node.prefix:
list.append(("xmlns:" + node.prefix, node.namespaceURI))
else:
list.append(("xmlns", node.namespaceURI))
# Add namespace declarations for each attribute
for attr in node.attributes.values():
if attr.namespaceURI:
if self.newNS(attr.prefix, attr.namespaceURI):
......@@ -185,6 +184,7 @@ class METALCompiler(DOMVisitor):
("xmlns:" + attr.prefix, attr.namespaceURI))
else:
list.append(("xmlns", node.namespaceURI))
# Add the node's attributes
list.extend(self.getAttributeList(node))
return list
......@@ -283,7 +283,11 @@ class METALCompiler(DOMVisitor):
return []
attrList = []
for attrNode in node.attributes.values():
attrList.append((attrNode.nodeName, attrNode.nodeValue))
item = attrNode.nodeName, attrNode.nodeValue
if (attrNode.namespaceURI == ZOPE_METAL_NS and
attrNode.localName == "define-macro"):
item = item + ("macroHack",)
attrList.append(item)
return attrList
class TALCompiler(METALCompiler):
......@@ -295,12 +299,12 @@ class TALCompiler(METALCompiler):
if not attrDict:
return attrList
list = []
for key, value in attrList:
for item in attrList:
key, value = item[:2]
if attrDict.has_key(key):
list.append((key, value, attrDict[key]))
item = (key, value, "replace", attrDict[key])
del attrDict[key]
else:
list.append((key, value))
list.append(item)
return list
# Overriding METAL method to compile TAL statements
......
......@@ -95,25 +95,35 @@ from TALCompiler import TALCompiler
class TALInterpreter:
def __init__(self, program, macros, engine, stream=None):
def __init__(self, program, macros, engine, stream=None, debug=0):
self.program = program
self.macros = macros
self.engine = engine
self.stream = stream or sys.stdout
self.debug = debug
self.slots = {}
self.inMacro = 0
self.currentMacro = None
def __call__(self):
self.stream.write('<?xml version="1.0" ?>\n')
self.interpret(self.program)
self.stream.write("\n")
level = 0
def interpret(self, program):
self.level = self.level + 1
for item in program:
methodName = "do_" + item[0]
args = item[1:]
if self.debug:
s = "%s%s%s\n" % (" "*self.level, methodName, repr(args))
if len(s) > 80:
s = s[:76] + "...\n"
sys.stderr.write(s)
method = getattr(self, methodName)
apply(method, args)
self.level = self.level - 1
def do_startEndTag(self, name, attrList):
self.do_startTag(name, attrList, "/>")
......@@ -124,16 +134,16 @@ class TALInterpreter:
return
self.stream.write("<" + name)
for item in attrList:
name = item[0]
if self.inMacro and name[-13:] == ":define-macro":
# XXX should check namespaceURI too
name = name[:-13] + ":use-macro"
if len(item) == 2:
self.stream.write(' %s=%s' % (name, quote(item[1])))
else:
assert len(item) >= 3
value = self.engine.evaluateText(item[2])
self.stream.write(' %s=%s' % (item[0], quote(value)))
name, value = item[:2]
if len(item) > 2:
action = item[2]
if action == "replace" and len(item) > 3:
value = self.engine.evaluateText(item[3])
elif (action == "macroHack" and self.currentMacro and
name[-13:] == ":define-macro"):
name = name[:-13] + ":use-macro"
value = self.currentMacro
self.stream.write(' %s=%s' % (name, quote(value)))
self.stream.write(end)
def do_endTag(self, name):
......@@ -194,11 +204,11 @@ class TALInterpreter:
def do_useMacro(self, macroName, compiledSlots):
macro = self.engine.evaluateMacro(macroName)
save = self.slots, self.inMacro
save = self.slots, self.currentMacro
self.slots = compiledSlots
self.inMacro = 1
self.currentMacro = macroName
self.interpret(macro)
self.slots, self.inMacro = save
self.slots, self.currentMacro = save
def do_fillSlot(self, slotName, program):
self.interpret(program)
......
<?xml version="1.0" ?>
<html>
<body xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="body">
<body xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="test/test5.xml/body">
<h1>This is the body of test5</h1>
......
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="myTable">
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="test/test7.xml/myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
......@@ -7,7 +7,7 @@
</tr>
<tr>
<td>Bottom left</td>
<td><span m:fill-slot="bottomRight">
<td><span xmlns:m="http://xml.zope.org/namespaces/metal" m:fill-slot="bottomRight">
<h1>Some headline</h1>
<p>This is the real contents of the bottom right slot.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
......
<?xml version="1.0" ?>
<html>
<body xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="body">
<body xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="test/test5.xml/body">
<h1>This is the body of test5</h1>
......
<?xml version="1.0" ?>
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="myTable">
<table xmlns:m="http://xml.zope.org/namespaces/metal" m:use-macro="test/test7.xml/myTable">
<!-- macro definition with slots -->
<tr>
<td>Top Left</td>
......@@ -7,7 +7,7 @@
</tr>
<tr>
<td>Bottom left</td>
<td><span m:fill-slot="bottomRight">
<td><span xmlns:m="http://xml.zope.org/namespaces/metal" m:fill-slot="bottomRight">
<h1>Some headline</h1>
<p>This is the real contents of the bottom right slot.</p>
<p>It is supposed to contain a lot of text. Blah, blah, blab.
......
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