[ZPT] CVS: Packages/TAL - CHANGES.txt:1.2.2.1 HISTORY.txt:1.1.2.1 markbench.py:1.2.2.1 DummyEngine.py:1.24.2.1 HTMLParser.py:1.15.6.1 TALDefs.py:1.19.2.1 TALGenerator.py:1.38.2.1 TALInterpreter.py:1.45.2.1 driver.py:1.23.4.1 runtest.py:1.17.2.1
evan@serenade.digicool.com
evan@serenade.digicool.com
Sat, 16 Jun 2001 11:50:07 -0400
Update of /cvs-repository/Packages/TAL
In directory serenade:/home/evan/Zope/pt/lib/python/TAL
Modified Files:
Tag: tal-1_3_0
DummyEngine.py HTMLParser.py TALDefs.py TALGenerator.py
TALInterpreter.py driver.py runtest.py
Added Files:
Tag: tal-1_3_0
CHANGES.txt HISTORY.txt markbench.py
Log Message:
Merge trunk changes for release 1.3.2
--- Added File CHANGES.txt in package Packages/TAL ---
TAL changes
This file contains change information for the current release.
Change information for previous versions can be found in the
file HISTORY.txt.
Version 1.3.2
Features Added
- Adopted Zope-style CHANGES.txt and HISTORY.txt
- Improved execution performance
- Added simple ZPT vs. TAL vs. DTML benchmarks, run by markbench.py
Bugs Fixed
--- Added File HISTORY.txt in package Packages/TAL ---
TAL history
This file contains change information for previous versions.
Change information for the current release can be found
in the file CHANGES.txt.
Version 1.3.0
Features Added
- New builtin variable 'attrs'.
Bug Fixed
- Nested macros were not working correctly.
Version 1.2.0
Features Added
- The 'if' path modifier can cancel any TAL action.
Bug Fixed
- tal:attributes inserted empty attributes into source.
Version 1.1.0
Features Added
- TAL does not try to parse replacement structural text.
- Changed tests to match TAL's omitted attributes.
Version 1.0.0
- Various minor bugs fixed
Version 1.0.0b1
- All functionality described in the Project Wiki is implemented
--- Added File markbench.py in package Packages/TAL ---
#! /usr/bin/env python1.5
'''Run benchmarks of TAL vs. DTML'''
try:
import warnings
except ImportError:
pass
else:
warnings.filterwarnings("ignore", category=DeprecationWarning)
import os
os.environ['NO_SECURITY'] = 'true'
import sys, time
if __name__ == "__main__":
import setpath
from DocumentTemplate.DT_HTML import HTMLFile
from HTMLTALParser import HTMLTALParser
from TALInterpreter import TALInterpreter
from DummyEngine import DummyEngine
from cStringIO import StringIO
def time_apply(f, args, kwargs, count):
for i in range(4):
apply(f, args, kwargs)
r = [None] * count
t0 = time.clock()
for i in r:
pass
t1 = time.clock()
for i in r:
apply(f, args, kwargs)
t = time.clock() - t1 - (t1 - t0)
return t / count
def time_zpt(fn, count):
from Products.PageTemplates.PageTemplate import PageTemplate
pt = PageTemplate()
pt.write(open(fn).read())
return time_apply(pt.pt_render, (), {'extra_context': data}, count)
def time_tal(fn, count):
p = HTMLTALParser()
p.parseFile(fn)
program, macros = p.getCode()
engine = DummyEngine(macros)
engine.globals = data
tal = TALInterpreter(program, macros, engine, StringIO(), wrap=0,
tal=1, strictinsert=0)
return time_apply(tal, (), {}, count)
def time_dtml(fn, count):
html = HTMLFile(fn)
return time_apply(html, (), data, count)
def profile_zpt(fn, count, profiler):
from Products.PageTemplates.PageTemplate import PageTemplate
pt = PageTemplate()
pt.write(open(fn).read())
for i in range(4):
pt.pt_render(extra_context=data)
r = [None] * count
for i in r:
profiler.runcall(pt.pt_render, 0, data)
def profile_tal(fn, count, profiler):
p = HTMLTALParser()
p.parseFile(fn)
program, macros = p.getCode()
engine = DummyEngine(macros)
engine.globals = data
tal = TALInterpreter(program, macros, engine, StringIO(), wrap=0,
tal=1, strictinsert=0)
for i in range(4):
tal()
r = [None] * count
for i in r:
profiler.runcall(tal)
tal_fn = 'benchmark/tal%.2d.html'
dtml_fn = 'benchmark/dtml%.2d.html'
def compare(n, count, profiler=None):
t1 = int(time_zpt(tal_fn % n, count) * 1000 + 0.5)
t2 = int(time_tal(tal_fn % n, count) * 1000 + 0.5)
t3 = int(time_dtml(dtml_fn % n, count) * 1000 + 0.5)
print '%.2d: %10s %10s %10s' % (n, t1, t2, t3)
if profiler:
profile_tal(tal_fn % n, count, profiler)
def main(count, profiler=None):
n = 1
print '##: %10s %10s %10s' % ('ZPT', 'TAL', 'DTML')
while os.path.isfile(tal_fn % n) and os.path.isfile(dtml_fn % n):
compare(n, count, profiler)
n = n + 1
data = {'x':'X', 'r2': range(2), 'r8': range(8), 'r64': range(64)}
for i in range(10):
data['x%s' % i] = 'X%s' % i
if __name__ == "__main__":
filename = "markbench.prof"
profiler = None
if len(sys.argv) > 1 and sys.argv[1] == "-p":
import profile
profiler = profile.Profile()
del sys.argv[1]
if len(sys.argv) > 1:
for arg in sys.argv[1:]:
compare(int(arg), 25, profiler)
else:
main(25, profiler)
if profiler is not None:
profiler.dump_stats(filename)
import pstats
p = pstats.Stats(filename)
p.strip_dirs()
p.sort_stats('time', 'calls')
try:
p.print_stats(20)
except IOError, e:
if e.errno != errno.EPIPE:
raise
--- Updated File DummyEngine.py in package Packages/TAL --
--- DummyEngine.py 2001/05/16 17:12:48 1.24
+++ DummyEngine.py 2001/06/16 15:49:36 1.24.2.1
@@ -88,12 +88,16 @@
import re
import sys
-import string
+from string import rfind, strip
+import driver
+
from TALDefs import NAME_RE, TALError, TALESError
Default = []
+name_match = re.compile(r"(?s)(%s):(.*)\Z" % NAME_RE).match
+
class DummyEngine:
def __init__(self, macros=None):
@@ -128,8 +132,9 @@
self.globals[name] = value
def evaluate(self, expression):
- expression = self.uncompile(expression)
- m = re.match(r"(?s)(%s):(.*)\Z" % NAME_RE, expression)
+ assert expression[:1] == "$" == expression[-1:], expression
+ expression = expression[1:-1]
+ m = name_match(expression)
if m:
type, expr = m.group(1, 2)
else:
@@ -138,7 +143,7 @@
if type in ("string", "str"):
return expr
if type in ("path", "var", "global", "local"):
- expr = string.strip(expr)
+ expr = strip(expr)
if self.locals.has_key(expr):
return self.locals[expr]
elif self.globals.has_key(expr):
@@ -146,15 +151,13 @@
else:
raise TALESError("unknown variable: %s" % `expr`)
if type == "not":
- v = self.evaluate(expr)
- return not v
+ return not self.evaluate(expr)
if type == "exists":
return self.locals.has_key(expr) or self.globals.has_key(expr)
if type == "python":
try:
return eval(expr, self.globals, self.locals)
except:
- t, v, tb = info = sys.exc_info()
raise TALESError("evaluation error in %s" % `expr`,
info=sys.exc_info())
raise TALESError("unrecognized expression: " + `expression`)
@@ -180,15 +183,15 @@
return self.evaluate(expr)
def evaluateMacro(self, macroName):
- macroName = self.uncompile(macroName)
+ assert macroName[:1] == "$" == macroName[-1:], macroName
+ macroName = macroName[1:-1]
file, localName = self.findMacroFile(macroName)
if not file:
# Local macro
macro = self.macros[localName]
else:
# External macro
- from driver import compilefile
- program, macros = compilefile(file)
+ program, macros = driver.compilefile(file)
macro = macros.get(localName)
if not macro:
raise TALESError("macro %s not found in file %s" %
@@ -199,14 +202,13 @@
file, localName = self.findMacroFile(macroName)
if not file:
return file, localName
- from driver import parsefile
- doc = parsefile(file)
+ doc = driver.parsefile(file)
return doc, localName
def findMacroFile(self, macroName):
if not macroName:
raise TALESError("empty macro name")
- i = string.rfind(macroName, '/')
+ i = rfind(macroName, '/')
if i < 0:
# No slash -- must be a locally defined macro
return None, macroName
--- Updated File HTMLParser.py in package Packages/TAL --
--- HTMLParser.py 2001/04/09 17:23:50 1.15
+++ HTMLParser.py 2001/06/16 15:49:36 1.15.6.1
@@ -74,15 +74,19 @@
# HTML parser class -- find tags and call handler functions.
-# Usage: p = HTMLParser(); p.feed(data); ...; p.close().
-# The dtd is defined by deriving a class which defines methods
-# with special names to handle tags: start_foo and end_foo to handle
-# <foo> and </foo>, respectively, or do_foo to handle <foo> by itself.
-# (Tags are converted to lower case for this purpose.) The data
-# between tags is passed to the parser by calling self.handle_data()
-# with some data as argument (the data may be split up in arbitrary
-# chunks). Entity references are passed by calling
-# self.handle_entityref() with the entity reference as argument.
+# Usage:
+#
+# p = HTMLParser(); p.feed(data); ...; p.close()
+
+# Start tags are handled by calling self.handle_starttag() or
+# self.handle_startendtag(); end tags by self.handle_endtag(). The
+# data between tags is passed from the parser to the derived class by
+# calling self.handle_data() with the data as argument (the data may
+# be split up in arbitrary chunks). Entity references are passed by
+# calling self.handle_entityref() with the entity reference as the
+# argument. Numeric character references are passed to
+# self.handle_charref() with the string containing the reference as
+# the argument.
class HTMLParser:
--- Updated File TALDefs.py in package Packages/TAL --
--- TALDefs.py 2001/05/17 04:16:45 1.19
+++ TALDefs.py 2001/06/16 15:49:36 1.19.2.1
@@ -86,8 +86,10 @@
Common definitions used by TAL and METAL compilation an transformation.
"""
-TAL_VERSION = "1.3"
+from types import ListType, TupleType
+TAL_VERSION = "1.3.2"
+
XML_NS = "http://www.w3.org/XML/1998/namespace" # URI for XML namespace
XMLNS_NS = "http://www.w3.org/2000/xmlns/" # URI for XML NS declarations
@@ -195,7 +197,7 @@
def getProgramMode(program):
version = getProgramVersion(program)
- if (version == TAL_VERSION and isinstance(program[1], type(())) and
+ if (version == TAL_VERSION and isinstance(program[1], TupleType) and
len(program[1]) == 2):
opcode, mode = program[1]
if opcode == "mode":
@@ -203,15 +205,14 @@
return None
def getProgramVersion(program):
- if (isinstance(program, type([])) and len(program) >= 2 and
- isinstance(program[0], type(())) and len(program[0]) == 2):
+ if (isinstance(program, ListType) and len(program) >= 2 and
+ isinstance(program[0], TupleType) and len(program[0]) == 2):
opcode, version = program[0]
if opcode == "version":
return version
return None
import cgi
-_cgi = cgi
+def quote(s, escape=cgi.escape):
+ return '"%s"' % escape(s, 1)
del cgi
-def quote(s):
- return '"%s"' % _cgi.escape(s, 1)
--- Updated File TALGenerator.py in package Packages/TAL --
--- TALGenerator.py 2001/05/18 01:24:04 1.38
+++ TALGenerator.py 2001/06/16 15:49:36 1.38.2.1
@@ -91,12 +91,12 @@
import cgi
from TALDefs import *
-from DummyEngine import DummyEngine
class TALGenerator:
def __init__(self, expressionCompiler=None, xml=1):
if not expressionCompiler:
+ from DummyEngine import DummyEngine
expressionCompiler = DummyEngine()
self.expressionCompiler = expressionCompiler
self.program = []
@@ -127,42 +127,97 @@
item = program[cursor]
except IndexError:
item = (None, None)
- if item[0] == "rawtext":
+ opcode = item[0]
+ if opcode == "rawtext":
collect.append(item[1])
continue
- if item[0] == "endTag":
+ if opcode == "endTag":
collect.append("</%s>" % item[1])
continue
- if item[0] == "startTag":
+ if opcode == "startTag":
if self.optimizeStartTag(collect, item[1], item[2], ">"):
continue
- if item[0] == "startEndTag":
+ if opcode == "startEndTag":
if self.optimizeStartTag(collect, item[1], item[2], endsep):
continue
+ if opcode in ("beginScope", "endScope"):
+ # Push *Scope instructions in front of any text instructions;
+ # this allows text instructions separated only by *Scope
+ # instructions to be joined together.
+ output.append(self.optimizeArgsList(item))
+ continue
text = string.join(collect, "")
if text:
- output.append(("rawtext", text))
- if item[0] != None:
- output.append(item)
+ i = string.rfind(text, "\n")
+ if i >= 0:
+ i = len(text) - (i + 1)
+ output.append(("rawtextColumn", (text, i)))
+ else:
+ output.append(("rawtextOffset", (text, len(text))))
+ if opcode != None:
+ output.append(self.optimizeArgsList(item))
rawseen = cursor+1
collect = []
- return output
+ return self.optimizeCommonTriple(output)
+ def optimizeArgsList(self, item):
+ if len(item) == 2:
+ return item
+ else:
+ return item[0], tuple(item[1:])
+
+ actionIndex = {"replace":0, "insert":1, "metal":2, "tal":3, "xmlns":4,
+ 0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
def optimizeStartTag(self, collect, name, attrlist, end):
if not attrlist:
collect.append("<%s%s" % (name, end))
return 1
+ opt = 1
new = ["<" + name]
- for item in attrlist:
+ for i in range(len(attrlist)):
+ item = attrlist[i]
if len(item) > 2:
- return 0
+ opt = 0
+ name, value, action = item[:3]
+ action = self.actionIndex[action]
+ attrlist[i] = (name, value, action) + item[3:]
+ else:
+ if item[1] is None:
+ s = item[0]
+ else:
+ s = "%s=%s" % (item[0], quote(item[1]))
+ attrlist[i] = item[0], s
if item[1] is None:
- new.append(" %s" % item[0])
+ new.append(" " + item[0])
else:
new.append(" %s=%s" % (item[0], quote(item[1])))
- new.append(end)
- collect.extend(new)
- return 1
+ if opt:
+ new.append(end)
+ collect.extend(new)
+ return opt
+
+ def optimizeCommonTriple(self, program):
+ if len(program) < 3:
+ return program
+ output = program[:2]
+ prev2, prev1 = output
+ for item in program[2:]:
+ if ( item[0] == "beginScope"
+ and prev1[0] == "setPosition"
+ and prev2[0] == "rawtextColumn"):
+ position = output.pop()[1]
+ text, column = output.pop()[1]
+ prev1 = None, None
+ closeprev = 0
+ if output and output[-1][0] == "endScope":
+ closeprev = 1
+ output.pop()
+ item = ("rawtextBeginScope",
+ (text, column, position, closeprev, item[1]))
+ output.append(item)
+ prev2 = prev1
+ prev1 = item
+ return output
def todoPush(self, todo):
self.todoStack.append(todo)
@@ -410,8 +465,11 @@
self.pushProgram()
todo["defineSlot"] = defineSlot
if taldict:
- self.emit("beginScope")
- self.emit("rawAttrs", self.makeAttrDict(attrlist))
+ dict = {}
+ for item in attrlist:
+ key, value = item[:2]
+ dict[key] = value
+ self.emit("beginScope", dict)
todo["scope"] = 1
if onError:
self.pushProgram() # handler
@@ -451,13 +509,6 @@
self.todoPush(todo)
if isend:
self.emitEndElement(name, isend)
-
- def makeAttrDict(self, attrlist):
- dict = {}
- for item in attrlist:
- key, value = item[:2]
- dict[key] = value
- return dict
def emitEndElement(self, name, isend=0, implied=0):
todo = self.todoPop()
--- Updated File TALInterpreter.py in package Packages/TAL --
--- TALInterpreter.py 2001/05/18 22:18:03 1.45
+++ TALInterpreter.py 2001/06/16 15:49:36 1.45.2.1
@@ -87,11 +87,16 @@
"""
import sys
-import string
import getopt
-import cgi
+from cgi import escape
+from string import join, lower, rfind
try:
+ from strop import lower, rfind
+except ImportError:
+ pass
+
+try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
@@ -148,6 +153,7 @@
self.repldict = None
return TALGenerator.replaceAttrs(self, attrlist, repldict)
+
class TALInterpreter:
def __init__(self, program, macros, engine, stream=None,
@@ -159,10 +165,15 @@
self.TALESError = engine.getTALESError()
self.Default = engine.getDefault()
self.stream = stream or sys.stdout
+ self._stream_write = self.stream.write
self.debug = debug
self.wrap = wrap
self.metal = metal
self.tal = tal
+ if tal:
+ self.dispatch = self.bytecode_handlers_tal
+ else:
+ self.dispatch = self.bytecode_handlers
assert showtal in (-1, 0, 1)
if showtal == -1:
showtal = (not tal)
@@ -171,7 +182,9 @@
self.stackLimit = stackLimit
self.html = 0
self.endsep = "/>"
+ self.endlen = len(self.endsep)
self.macroStack = []
+ self.popMacro = self.macroStack.pop
self.position = None, None # (lineno, offset)
self.col = 0
self.level = 0
@@ -183,12 +196,15 @@
def restoreState(self, state):
(self.position, self.col, self.stream, scopeLevel, level) = state
+ self._stream_write = self.stream.write
assert self.level == level
while self.scopeLevel > scopeLevel:
- self.do_endScope()
+ self.engine.endScope()
+ self.scopeLevel = self.scopeLevel - 1
def restoreOutputState(self, state):
(dummy, self.col, self.stream, scopeLevel, level) = state
+ self._stream_write = self.stream.write
assert self.level == level
assert self.scopeLevel == scopeLevel
@@ -202,10 +218,11 @@
return self.macroStack.pop()
def macroContext(self, what):
- i = len(self.macroStack)
+ macroStack = self.macroStack
+ i = len(macroStack)
while i > 0:
i = i-1
- if self.macroStack[i][0] == what:
+ if macroStack[i][0] == what:
return i
return -1
@@ -216,35 +233,42 @@
assert self.level == 0
assert self.scopeLevel == 0
if self.col > 0:
- self.stream_write("\n")
+ self._stream_write("\n")
+ self.col = 0
- def stream_write(self, s):
- self.stream.write(s)
- i = string.rfind(s, '\n')
+ def stream_write(self, s,
+ len=len, rfind=rfind):
+ self._stream_write(s)
+ i = rfind(s, '\n')
if i < 0:
self.col = self.col + len(s)
else:
self.col = len(s) - (i + 1)
+
+ bytecode_handlers = {}
- def interpret(self, program):
- self.level = self.level + 1
+ def interpret(self, program, None=None):
+ oldlevel = self.level
+ self.level = oldlevel + 1
+ handlers = self.dispatch
try:
- for item in program:
- methodName = "do_" + item[0]
- args = item[1:]
- if self.debug:
- s = "%s%s%s\n" % (" "*self.level, methodName,
+ if self.debug:
+ for (opcode, args) in program:
+ s = "%sdo_%s%s\n" % (" "*self.level, opcode,
repr(args))
if len(s) > 80:
s = s[:76] + "...\n"
sys.stderr.write(s)
- method = getattr(self, methodName)
- apply(method, args)
+ handlers[opcode](self, args)
+ else:
+ for (opcode, args) in program:
+ handlers[opcode](self, args)
finally:
- self.level = self.level - 1
+ self.level = oldlevel
def do_version(self, version):
assert version == TAL_VERSION
+ bytecode_handlers["version"] = do_version
def do_mode(self, mode):
assert mode in ("html", "xml")
@@ -253,74 +277,116 @@
self.endsep = " />"
else:
self.endsep = "/>"
+ self.endlen = len(self.endsep)
+ bytecode_handlers["mode"] = do_mode
def do_setPosition(self, position):
self.position = position
+ bytecode_handlers["setPosition"] = do_setPosition
- def do_startEndTag(self, name, attrList):
- self.startTagCommon(name, attrList, self.endsep)
+ def do_startEndTag(self, stuff):
+ self.do_startTag(stuff, self.endsep, self.endlen)
+ bytecode_handlers["startEndTag"] = do_startEndTag
+
+ def do_startTag(self, (name, attrList),
+ end=">", endlen=1, _len=len):
+ # The bytecode generator does not cause calls to this method
+ # for start tags with no attributes; those are optimized down
+ # to rawtext events. Hence, there is no special "fast path"
+ # for that case.
+ _stream_write = self._stream_write
+ _stream_write("<" + name)
+ namelen = _len(name)
+ col = self.col + namelen + 1
+ wrap = self.wrap
+ align = col + 1 + namelen
+ if align >= wrap/2:
+ align = 4 # Avoid a narrow column far to the right
+ attrAction = self.dispatch["<attrAction>"]
+ try:
+ for item in attrList:
+ if _len(item) == 2:
+ name, s = item
+ else:
+ ok, name, s = attrAction(self, item)
+ if not ok:
+ continue
+ slen = _len(s)
+ if (wrap and
+ col >= align and
+ col + 1 + slen > wrap):
+ _stream_write("\n" + " "*align)
+ col = align + slen
+ else:
+ s = " " + s
+ col = col + 1 + slen
+ _stream_write(s)
+ _stream_write(end)
+ col = col + endlen
+ finally:
+ self.col = col
+ bytecode_handlers["startTag"] = do_startTag
- def do_startTag(self, name, attrList):
- self.startTagCommon(name, attrList, ">")
+ def attrAction(self, item):
+ name, value, action = item[:3]
+ if action > 1 and not self.showtal:
+ return 0, name, value
+ ok = 1
+ if action == 2 and self.metal:
+ i = rfind(name, ":") + 1
+ prefix, suffix = name[:i], name[i:]
+ ##self.dumpMacroStack(prefix, suffix, value)
+ what, macroName, slots = self.macroStack[-1]
+ if suffix == "define-macro":
+ if what == "use-macro":
+ name = prefix + "use-macro"
+ value = macroName
+ else:
+ assert what == "define-macro"
+ i = self.macroContext("use-macro")
+ if i >= 0:
+ j = self.macroContext("define-slot")
+ if j > i:
+ name = prefix + "use-macro"
+ else:
+ return 0, name, value
+ elif suffix == "define-slot":
+ assert what == "define-slot"
+ if self.macroContext("use-macro") >= 0:
+ name = prefix + "fill-slot"
- def startTagCommon(self, name, attrList, end):
- if not attrList:
- self.stream_write("<%s%s" % (name, end))
- return
- self.stream_write("<" + name)
- align = self.col+1
- if align >= self.wrap/2:
- align = 4 # Avoid a narrow column far to the right
- for item in attrList:
- if len(item) == 2:
- name, value = item[:2]
- else:
- ok, name, value = self.attrAction(item)
- if not ok:
- continue
- if value is None:
- s = name
- else:
- s = "%s=%s" % (name, quote(value))
- if (self.wrap and
- self.col >= align and
- self.col + 1 + len(s) > self.wrap):
- self.stream_write("\n" + " "*align + s)
- else:
- self.stream_write(" " + s)
- self.stream_write(end)
+ if value is None:
+ value = name
+ else:
+ value = "%s=%s" % (name, quote(value))
+ return ok, name, value
- actionIndex = {"replace":0, "insert":1, "metal":2, "tal":3, "xmlns":4}
- def attrAction(self, item):
- name, value = item[:2]
- try:
- action = self.actionIndex[item[2]]
- except KeyError:
- raise TALError, ('Error in TAL program', self.position)
- if not self.showtal and action > 1:
+ def attrAction_tal(self, item):
+ name, value, action = item[:3]
+ if action > 1 and not self.showtal:
return 0, name, value
ok = 1
- if action <= 1 and self.tal:
- if self.html and string.lower(name) in BOOLEAN_HTML_ATTRS:
+ if action <= 1:
+ if self.html and lower(name) in BOOLEAN_HTML_ATTRS:
evalue = self.engine.evaluateBoolean(item[3])
if evalue is self.Default:
if action == 1: # Cancelled insert
ok = 0
- elif not evalue:
- ok = 0
- else:
+ elif evalue:
value = None
+ else:
+ ok = 0
else:
evalue = self.engine.evaluateText(item[3])
if evalue is self.Default:
if action == 1: # Cancelled insert
ok = 0
else:
- value = evalue
- if value is None:
+ if evalue is None:
ok = 0
+ value = evalue
elif action == 2 and self.metal:
- i = string.rfind(name, ":") + 1
+ i = rfind(name, ":") + 1
prefix, suffix = name[:i], name[i:]
##self.dumpMacroStack(prefix, suffix, value)
what, macroName, slots = self.macroStack[-1]
@@ -342,9 +408,13 @@
if self.macroContext("use-macro") >= 0:
name = prefix + "fill-slot"
- elif action == 1: # Unexecuted insert
- ok = 0
+ if ok:
+ if value is None:
+ value = name
+ else:
+ value = "%s=%s" % (name, quote(value))
return ok, name, value
+ bytecode_handlers["<attrAction>"] = attrAction
def dumpMacroStack(self, prefix, suffix, value):
sys.stderr.write("+---- %s%s = %s\n" % (prefix, suffix, value))
@@ -353,51 +423,83 @@
sys.stderr.write("| %2d. %-12s %-12s %s\n" %
(i, what, macroName, slots and slots.keys()))
sys.stderr.write("+--------------------------------------\n")
+
+ def do_rawtextBeginScope(self, (s, col, position, closeprev, dict)):
+ self._stream_write(s)
+ self.col = col
+ self.position = position
+ if closeprev:
+ engine = self.engine
+ engine.endScope()
+ engine.beginScope()
+ else:
+ self.engine.beginScope()
+ self.scopeLevel = self.scopeLevel + 1
- def do_endTag(self, name):
- self.stream_write("</%s>" % name)
+ def do_rawtextBeginScope_tal(self, (s, col, position, closeprev, dict)):
+ self._stream_write(s)
+ self.col = col
+ self.position = position
+ engine = self.engine
+ if closeprev:
+ engine.endScope()
+ engine.beginScope()
+ else:
+ engine.beginScope()
+ self.scopeLevel = self.scopeLevel + 1
+ engine.setLocal("attrs", dict)
+ bytecode_handlers["rawtextBeginScope"] = do_rawtextBeginScope
- def do_beginScope(self):
+ def do_beginScope(self, dict):
self.engine.beginScope()
self.scopeLevel = self.scopeLevel + 1
+
+ def do_beginScope_tal(self, dict):
+ engine = self.engine
+ engine.beginScope()
+ engine.setLocal("attrs", dict)
+ self.scopeLevel = self.scopeLevel + 1
+ bytecode_handlers["beginScope"] = do_beginScope
- def do_endScope(self):
+ def do_endScope(self, notused=None):
self.engine.endScope()
self.scopeLevel = self.scopeLevel - 1
+ bytecode_handlers["endScope"] = do_endScope
- def do_setLocal(self, name, expr):
- if not self.tal:
- return
- value = self.engine.evaluateValue(expr)
- self.engine.setLocal(name, value)
+ def do_setLocal(self, notused):
+ pass
- def do_setGlobal(self, name, expr):
- if not self.tal:
- return
- value = self.engine.evaluateValue(expr)
- self.engine.setGlobal(name, value)
+ def do_setLocal_tal(self, (name, expr)):
+ self.engine.setLocal(name, self.engine.evaluateValue(expr))
+ bytecode_handlers["setLocal"] = do_setLocal
- def do_rawAttrs(self, dict):
- if self.tal:
- self.engine.setLocal("attrs", dict)
+ def do_setGlobal_tal(self, (name, expr)):
+ self.engine.setGlobal(name, self.engine.evaluateValue(expr))
+ bytecode_handlers["setGlobal"] = do_setLocal
- def do_insertText(self, expr, block):
- if not self.tal:
- self.interpret(block)
- return
- text = self.engine.evaluateText(expr)
+ def do_insertText(self, stuff):
+ self.interpret(stuff[1])
+
+ def do_insertText_tal(self, stuff):
+ text = self.engine.evaluateText(stuff[0])
if text is None:
return
if text is self.Default:
- self.interpret(block)
+ self.interpret(stuff[1])
return
- text = cgi.escape(text)
- self.stream_write(text)
+ s = escape(text)
+ self._stream_write(s)
+ i = rfind(s, '\n')
+ if i < 0:
+ self.col = self.col + len(s)
+ else:
+ self.col = len(s) - (i + 1)
+ bytecode_handlers["insertText"] = do_insertText
- def do_insertStructure(self, expr, repldict, block):
- if not self.tal:
- self.interpret(block)
- return
+ def do_insertStructure(self, stuff):
+ self.interpret(stuff[2])
+
+ def do_insertStructure_tal(self, (expr, repldict, block)):
structure = self.engine.evaluateStructure(expr)
if structure is None:
return
@@ -405,7 +507,7 @@
self.interpret(block)
return
text = str(structure)
- if not repldict and not self.strictinsert:
+ if not (repldict or self.strictinsert):
# Take a shortcut, no error checking
self.stream_write(text)
return
@@ -413,6 +515,7 @@
self.insertHTMLStructure(text, repldict)
else:
self.insertXMLStructure(text, repldict)
+ bytecode_handlers["insertStructure"] = do_insertStructure
def insertHTMLStructure(self, text, repldict):
from HTMLTALParser import HTMLTALParser
@@ -435,30 +538,40 @@
program, macros = gen.getCode()
self.interpret(program)
- def do_loop(self, name, expr, block):
- if not self.tal:
- self.interpret(block)
- return
+ def do_loop(self, (name, expr, block)):
+ self.interpret(block)
+
+ def do_loop_tal(self, (name, expr, block)):
iterator = self.engine.setRepeat(name, expr)
while iterator.next():
self.interpret(block)
+ bytecode_handlers["loop"] = do_loop
- def do_rawtext(self, text):
- self.stream_write(text)
+ def do_rawtextColumn(self, (s, col)):
+ self._stream_write(s)
+ self.col = col
+ bytecode_handlers["rawtextColumn"] = do_rawtextColumn
+
+ def do_rawtextOffset(self, (s, offset)):
+ self._stream_write(s)
+ self.col = self.col + offset
+ bytecode_handlers["rawtextOffset"] = do_rawtextOffset
- def do_condition(self, condition, block):
+ def do_condition(self, (condition, block)):
if not self.tal or self.engine.evaluateBoolean(condition):
self.interpret(block)
+ bytecode_handlers["condition"] = do_condition
- def do_defineMacro(self, macroName, macro):
+ def do_defineMacro(self, (macroName, macro)):
if not self.metal:
self.interpret(macro)
return
self.pushMacro("define-macro", macroName, None)
self.interpret(macro)
self.popMacro()
+ bytecode_handlers["defineMacro"] = do_defineMacro
- def do_useMacro(self, macroName, macroExpr, compiledSlots, block):
+ def do_useMacro(self, (macroName, macroExpr, compiledSlots, block)):
if not self.metal:
self.interpret(block)
return
@@ -477,16 +590,18 @@
self.pushMacro("use-macro", macroName, compiledSlots)
self.interpret(macro)
self.popMacro()
+ bytecode_handlers["useMacro"] = do_useMacro
- 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.popMacro()
+ bytecode_handlers["fillSlot"] = do_fillSlot
- def do_defineSlot(self, slotName, block):
+ def do_defineSlot(self, (slotName, block)):
if not self.metal:
self.interpret(block)
return
@@ -500,27 +615,41 @@
else:
self.interpret(block)
self.popMacro()
+ bytecode_handlers["defineSlot"] = do_defineSlot
- def do_onError(self, block, handler):
- if not self.tal:
- self.interpret(block)
- return
+ def do_onError(self, (block, handler)):
+ self.interpret(block)
+
+ def do_onError_tal(self, (block, handler)):
state = self.saveState()
self.stream = stream = StringIO()
+ self._stream_write = stream.write
try:
self.interpret(block)
except self.TALESError, err:
self.restoreState(state)
engine = self.engine
engine.beginScope()
- err.lineno = self.position[0]
- err.offset = self.position[1]
+ err.lineno, err.offset = self.position
engine.setLocal('error', err)
self.interpret(handler)
engine.endScope()
else:
self.restoreOutputState(state)
self.stream_write(stream.getvalue())
+ bytecode_handlers["onError"] = do_onError
+
+ bytecode_handlers_tal = bytecode_handlers.copy()
+ bytecode_handlers_tal["rawtextBeginScope"] = do_rawtextBeginScope_tal
+ bytecode_handlers_tal["beginScope"] = do_beginScope_tal
+ bytecode_handlers_tal["setLocal"] = do_setLocal_tal
+ bytecode_handlers_tal["setGlobal"] = do_setGlobal_tal
+ bytecode_handlers_tal["insertStructure"] = do_insertStructure_tal
+ bytecode_handlers_tal["insertText"] = do_insertText_tal
+ bytecode_handlers_tal["loop"] = do_loop_tal
+ bytecode_handlers_tal["onError"] = do_onError_tal
+ bytecode_handlers_tal["<attrAction>"] = attrAction_tal
+
def test():
from driver import FILE, parsefile
--- Updated File driver.py in package Packages/TAL --
--- driver.py 2001/04/27 17:25:04 1.23
+++ driver.py 2001/06/16 15:49:36 1.23.4.1
@@ -93,15 +93,12 @@
import getopt
-try:
+if __name__ == "__main__":
import setpath # Local hack to tweak sys.path etc.
- import Products.ParsedXML
-except ImportError:
- pass
# Import local classes
import TALDefs
-from DummyEngine import DummyEngine
+import DummyEngine
FILE = "tests/input/test01.xml"
@@ -160,7 +157,7 @@
program, macros = it
assert TALDefs.isCurrentVersion(program)
if engine is None:
- engine = DummyEngine(macros)
+ engine = DummyEngine.DummyEngine(macros)
TALInterpreter(program, macros, engine, stream, wrap=0,
tal=tal, showtal=showtal, strictinsert=strictinsert)()
--- Updated File runtest.py in package Packages/TAL --
--- runtest.py 2001/05/18 19:17:17 1.17
+++ runtest.py 2001/06/16 15:49:36 1.17.2.1
@@ -94,6 +94,9 @@
import glob
import traceback
+if __name__ == "__main__":
+ import setpath # Local hack to tweak sys.path etc.
+
import driver
def showdiff(a, b):