annotate roundup/cgi/TAL/TALGenerator.py @ 1103:db787cef1385

handled some XXXs
author Richard Jones <richard@users.sourceforge.net>
date Tue, 10 Sep 2002 12:44:42 +0000
parents b9988e118055
children 8dd4f736370b
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
1 ##############################################################################
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
2 #
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
3 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
4 # All Rights Reserved.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
5 #
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
6 # This software is subject to the provisions of the Zope Public License,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
7 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
11 # FOR A PARTICULAR PURPOSE
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
12 #
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
13 ##############################################################################
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
14 """
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
15 Code generator for TALInterpreter intermediate code.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
16 """
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
17
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
18 import string
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
19 import re
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
20 import cgi
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
21
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
22 from TALDefs import *
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
23
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
24 class TALGenerator:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
25
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
26 inMacroUse = 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
27 inMacroDef = 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
28 source_file = None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
29
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
30 def __init__(self, expressionCompiler=None, xml=1, source_file=None):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
31 if not expressionCompiler:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
32 from DummyEngine import DummyEngine
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
33 expressionCompiler = DummyEngine()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
34 self.expressionCompiler = expressionCompiler
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
35 self.CompilerError = expressionCompiler.getCompilerError()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
36 self.program = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
37 self.stack = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
38 self.todoStack = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
39 self.macros = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
40 self.slots = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
41 self.slotStack = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
42 self.xml = xml
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
43 self.emit("version", TAL_VERSION)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
44 self.emit("mode", xml and "xml" or "html")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
45 if source_file is not None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
46 self.source_file = source_file
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
47 self.emit("setSourceFile", source_file)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
48
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
49 def getCode(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
50 assert not self.stack
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
51 assert not self.todoStack
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
52 return self.optimize(self.program), self.macros
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
53
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
54 def optimize(self, program):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
55 output = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
56 collect = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
57 rawseen = cursor = 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
58 if self.xml:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
59 endsep = "/>"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
60 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
61 endsep = " />"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
62 for cursor in xrange(len(program)+1):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
63 try:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
64 item = program[cursor]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
65 except IndexError:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
66 item = (None, None)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
67 opcode = item[0]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
68 if opcode == "rawtext":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
69 collect.append(item[1])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
70 continue
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
71 if opcode == "endTag":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
72 collect.append("</%s>" % item[1])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
73 continue
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
74 if opcode == "startTag":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
75 if self.optimizeStartTag(collect, item[1], item[2], ">"):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
76 continue
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
77 if opcode == "startEndTag":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
78 if self.optimizeStartTag(collect, item[1], item[2], endsep):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
79 continue
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
80 if opcode in ("beginScope", "endScope"):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
81 # Push *Scope instructions in front of any text instructions;
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
82 # this allows text instructions separated only by *Scope
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
83 # instructions to be joined together.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
84 output.append(self.optimizeArgsList(item))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
85 continue
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
86 text = string.join(collect, "")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
87 if text:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
88 i = string.rfind(text, "\n")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
89 if i >= 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
90 i = len(text) - (i + 1)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
91 output.append(("rawtextColumn", (text, i)))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
92 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
93 output.append(("rawtextOffset", (text, len(text))))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
94 if opcode != None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
95 output.append(self.optimizeArgsList(item))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
96 rawseen = cursor+1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
97 collect = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
98 return self.optimizeCommonTriple(output)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
99
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
100 def optimizeArgsList(self, item):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
101 if len(item) == 2:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
102 return item
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
103 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
104 return item[0], tuple(item[1:])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
105
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
106 actionIndex = {"replace":0, "insert":1, "metal":2, "tal":3, "xmlns":4,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
107 0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
108 def optimizeStartTag(self, collect, name, attrlist, end):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
109 if not attrlist:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
110 collect.append("<%s%s" % (name, end))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
111 return 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
112 opt = 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
113 new = ["<" + name]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
114 for i in range(len(attrlist)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
115 item = attrlist[i]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
116 if len(item) > 2:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
117 opt = 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
118 name, value, action = item[:3]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
119 action = self.actionIndex[action]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
120 attrlist[i] = (name, value, action) + item[3:]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
121 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
122 if item[1] is None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
123 s = item[0]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
124 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
125 s = "%s=%s" % (item[0], quote(item[1]))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
126 attrlist[i] = item[0], s
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
127 if item[1] is None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
128 new.append(" " + item[0])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
129 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
130 new.append(" %s=%s" % (item[0], quote(item[1])))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
131 if opt:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
132 new.append(end)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
133 collect.extend(new)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
134 return opt
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
135
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
136 def optimizeCommonTriple(self, program):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
137 if len(program) < 3:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
138 return program
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
139 output = program[:2]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
140 prev2, prev1 = output
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
141 for item in program[2:]:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
142 if ( item[0] == "beginScope"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
143 and prev1[0] == "setPosition"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
144 and prev2[0] == "rawtextColumn"):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
145 position = output.pop()[1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
146 text, column = output.pop()[1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
147 prev1 = None, None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
148 closeprev = 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
149 if output and output[-1][0] == "endScope":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
150 closeprev = 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
151 output.pop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
152 item = ("rawtextBeginScope",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
153 (text, column, position, closeprev, item[1]))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
154 output.append(item)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
155 prev2 = prev1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
156 prev1 = item
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
157 return output
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
158
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
159 def todoPush(self, todo):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
160 self.todoStack.append(todo)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
161
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
162 def todoPop(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
163 return self.todoStack.pop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
164
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
165 def compileExpression(self, expr):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
166 try:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
167 return self.expressionCompiler.compile(expr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
168 except self.CompilerError, err:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
169 raise TALError('%s in expression %s' % (err.args[0], `expr`),
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
170 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
171
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
172 def pushProgram(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
173 self.stack.append(self.program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
174 self.program = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
175
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
176 def popProgram(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
177 program = self.program
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
178 self.program = self.stack.pop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
179 return self.optimize(program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
180
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
181 def pushSlots(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
182 self.slotStack.append(self.slots)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
183 self.slots = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
184
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
185 def popSlots(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
186 slots = self.slots
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
187 self.slots = self.slotStack.pop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
188 return slots
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
189
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
190 def emit(self, *instruction):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
191 self.program.append(instruction)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
192
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
193 def emitStartTag(self, name, attrlist, isend=0):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
194 if isend:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
195 opcode = "startEndTag"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
196 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
197 opcode = "startTag"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
198 self.emit(opcode, name, attrlist)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
199
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
200 def emitEndTag(self, name):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
201 if self.xml and self.program and self.program[-1][0] == "startTag":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
202 # Minimize empty element
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
203 self.program[-1] = ("startEndTag",) + self.program[-1][1:]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
204 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
205 self.emit("endTag", name)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
206
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
207 def emitOptTag(self, name, optTag, isend):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
208 program = self.popProgram() #block
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
209 start = self.popProgram() #start tag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
210 if (isend or not program) and self.xml:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
211 # Minimize empty element
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
212 start[-1] = ("startEndTag",) + start[-1][1:]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
213 isend = 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
214 cexpr = optTag[0]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
215 if cexpr:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
216 cexpr = self.compileExpression(optTag[0])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
217 self.emit("optTag", name, cexpr, optTag[1], isend, start, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
218
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
219 def emitRawText(self, text):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
220 self.emit("rawtext", text)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
221
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
222 def emitText(self, text):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
223 self.emitRawText(cgi.escape(text))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
224
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
225 def emitDefines(self, defines):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
226 for part in splitParts(defines):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
227 m = re.match(
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
228 r"(?s)\s*(?:(global|local)\s+)?(%s)\s+(.*)\Z" % NAME_RE, part)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
229 if not m:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
230 raise TALError("invalid define syntax: " + `part`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
231 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
232 scope, name, expr = m.group(1, 2, 3)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
233 scope = scope or "local"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
234 cexpr = self.compileExpression(expr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
235 if scope == "local":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
236 self.emit("setLocal", name, cexpr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
237 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
238 self.emit("setGlobal", name, cexpr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
239
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
240 def emitOnError(self, name, onError):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
241 block = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
242 key, expr = parseSubstitution(onError)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
243 cexpr = self.compileExpression(expr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
244 if key == "text":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
245 self.emit("insertText", cexpr, [])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
246 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
247 assert key == "structure"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
248 self.emit("insertStructure", cexpr, {}, [])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
249 self.emitEndTag(name)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
250 handler = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
251 self.emit("onError", block, handler)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
252
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
253 def emitCondition(self, expr):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
254 cexpr = self.compileExpression(expr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
255 program = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
256 self.emit("condition", cexpr, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
257
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
258 def emitRepeat(self, arg):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
259 m = re.match("(?s)\s*(%s)\s+(.*)\Z" % NAME_RE, arg)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
260 if not m:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
261 raise TALError("invalid repeat syntax: " + `arg`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
262 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
263 name, expr = m.group(1, 2)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
264 cexpr = self.compileExpression(expr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
265 program = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
266 self.emit("loop", name, cexpr, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
267
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
268 def emitSubstitution(self, arg, attrDict={}):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
269 key, expr = parseSubstitution(arg)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
270 cexpr = self.compileExpression(expr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
271 program = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
272 if key == "text":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
273 self.emit("insertText", cexpr, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
274 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
275 assert key == "structure"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
276 self.emit("insertStructure", cexpr, attrDict, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
277
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
278 def emitDefineMacro(self, macroName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
279 program = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
280 macroName = string.strip(macroName)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
281 if self.macros.has_key(macroName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
282 raise METALError("duplicate macro definition: %s" % `macroName`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
283 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
284 if not re.match('%s$' % NAME_RE, macroName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
285 raise METALError("invalid macro name: %s" % `macroName`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
286 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
287 self.macros[macroName] = program
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
288 self.inMacroDef = self.inMacroDef - 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
289 self.emit("defineMacro", macroName, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
290
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
291 def emitUseMacro(self, expr):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
292 cexpr = self.compileExpression(expr)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
293 program = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
294 self.inMacroUse = 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
295 self.emit("useMacro", expr, cexpr, self.popSlots(), program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
296
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
297 def emitDefineSlot(self, slotName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
298 program = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
299 slotName = string.strip(slotName)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
300 if not re.match('%s$' % NAME_RE, slotName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
301 raise METALError("invalid slot name: %s" % `slotName`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
302 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
303 self.emit("defineSlot", slotName, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
304
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
305 def emitFillSlot(self, slotName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
306 program = self.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
307 slotName = string.strip(slotName)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
308 if self.slots.has_key(slotName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
309 raise METALError("duplicate fill-slot name: %s" % `slotName`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
310 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
311 if not re.match('%s$' % NAME_RE, slotName):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
312 raise METALError("invalid slot name: %s" % `slotName`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
313 self.position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
314 self.slots[slotName] = program
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
315 self.inMacroUse = 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
316 self.emit("fillSlot", slotName, program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
317
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
318 def unEmitWhitespace(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
319 collect = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
320 i = len(self.program) - 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
321 while i >= 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
322 item = self.program[i]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
323 if item[0] != "rawtext":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
324 break
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
325 text = item[1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
326 if not re.match(r"\A\s*\Z", text):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
327 break
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
328 collect.append(text)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
329 i = i-1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
330 del self.program[i+1:]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
331 if i >= 0 and self.program[i][0] == "rawtext":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
332 text = self.program[i][1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
333 m = re.search(r"\s+\Z", text)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
334 if m:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
335 self.program[i] = ("rawtext", text[:m.start()])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
336 collect.append(m.group())
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
337 collect.reverse()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
338 return string.join(collect, "")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
339
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
340 def unEmitNewlineWhitespace(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
341 collect = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
342 i = len(self.program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
343 while i > 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
344 i = i-1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
345 item = self.program[i]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
346 if item[0] != "rawtext":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
347 break
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
348 text = item[1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
349 if re.match(r"\A[ \t]*\Z", text):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
350 collect.append(text)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
351 continue
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
352 m = re.match(r"(?s)^(.*)(\n[ \t]*)\Z", text)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
353 if not m:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
354 break
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
355 text, rest = m.group(1, 2)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
356 collect.reverse()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
357 rest = rest + string.join(collect, "")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
358 del self.program[i:]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
359 if text:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
360 self.emit("rawtext", text)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
361 return rest
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
362 return None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
363
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
364 def replaceAttrs(self, attrlist, repldict):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
365 if not repldict:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
366 return attrlist
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
367 newlist = []
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
368 for item in attrlist:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
369 key = item[0]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
370 if repldict.has_key(key):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
371 item = item[:2] + ("replace", repldict[key])
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
372 del repldict[key]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
373 newlist.append(item)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
374 for key, value in repldict.items(): # Add dynamic-only attributes
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
375 item = (key, None, "insert", value)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
376 newlist.append(item)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
377 return newlist
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
378
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
379 def emitStartElement(self, name, attrlist, taldict, metaldict,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
380 position=(None, None), isend=0):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
381 if not taldict and not metaldict:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
382 # Handle the simple, common case
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
383 self.emitStartTag(name, attrlist, isend)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
384 self.todoPush({})
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
385 if isend:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
386 self.emitEndElement(name, isend)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
387 return
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
388
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
389 self.position = position
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
390 for key, value in taldict.items():
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
391 if key not in KNOWN_TAL_ATTRIBUTES:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
392 raise TALError("bad TAL attribute: " + `key`, position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
393 if not (value or key == 'omit-tag'):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
394 raise TALError("missing value for TAL attribute: " +
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
395 `key`, position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
396 for key, value in metaldict.items():
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
397 if key not in KNOWN_METAL_ATTRIBUTES:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
398 raise METALError("bad METAL attribute: " + `key`,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
399 position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
400 if not value:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
401 raise TALError("missing value for METAL attribute: " +
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
402 `key`, position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
403 todo = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
404 defineMacro = metaldict.get("define-macro")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
405 useMacro = metaldict.get("use-macro")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
406 defineSlot = metaldict.get("define-slot")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
407 fillSlot = metaldict.get("fill-slot")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
408 define = taldict.get("define")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
409 condition = taldict.get("condition")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
410 repeat = taldict.get("repeat")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
411 content = taldict.get("content")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
412 replace = taldict.get("replace")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
413 attrsubst = taldict.get("attributes")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
414 onError = taldict.get("on-error")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
415 omitTag = taldict.get("omit-tag")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
416 TALtag = taldict.get("tal tag")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
417 if len(metaldict) > 1 and (defineMacro or useMacro):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
418 raise METALError("define-macro and use-macro cannot be used "
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
419 "together or with define-slot or fill-slot",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
420 position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
421 if content and replace:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
422 raise TALError("content and replace are mutually exclusive",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
423 position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
424
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
425 repeatWhitespace = None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
426 if repeat:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
427 # Hack to include preceding whitespace in the loop program
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
428 repeatWhitespace = self.unEmitNewlineWhitespace()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
429 if position != (None, None):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
430 # XXX at some point we should insist on a non-trivial position
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
431 self.emit("setPosition", position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
432 if self.inMacroUse:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
433 if fillSlot:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
434 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
435 if self.source_file is not None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
436 self.emit("setSourceFile", self.source_file)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
437 todo["fillSlot"] = fillSlot
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
438 self.inMacroUse = 0
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
439 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
440 if fillSlot:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
441 raise METALError, ("fill-slot must be within a use-macro",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
442 position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
443 if not self.inMacroUse:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
444 if defineMacro:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
445 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
446 self.emit("version", TAL_VERSION)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
447 self.emit("mode", self.xml and "xml" or "html")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
448 if self.source_file is not None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
449 self.emit("setSourceFile", self.source_file)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
450 todo["defineMacro"] = defineMacro
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
451 self.inMacroDef = self.inMacroDef + 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
452 if useMacro:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
453 self.pushSlots()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
454 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
455 todo["useMacro"] = useMacro
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
456 self.inMacroUse = 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
457 if defineSlot:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
458 if not self.inMacroDef:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
459 raise METALError, (
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
460 "define-slot must be within a define-macro",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
461 position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
462 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
463 todo["defineSlot"] = defineSlot
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
464
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
465 if taldict:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
466 dict = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
467 for item in attrlist:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
468 key, value = item[:2]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
469 dict[key] = value
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
470 self.emit("beginScope", dict)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
471 todo["scope"] = 1
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
472 if onError:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
473 self.pushProgram() # handler
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
474 self.emitStartTag(name, list(attrlist)) # Must copy attrlist!
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
475 self.pushProgram() # block
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
476 todo["onError"] = onError
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
477 if define:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
478 self.emitDefines(define)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
479 todo["define"] = define
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
480 if condition:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
481 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
482 todo["condition"] = condition
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
483 if repeat:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
484 todo["repeat"] = repeat
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
485 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
486 if repeatWhitespace:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
487 self.emitText(repeatWhitespace)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
488 if content:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
489 todo["content"] = content
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
490 if replace:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
491 todo["replace"] = replace
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
492 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
493 optTag = omitTag is not None or TALtag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
494 if optTag:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
495 todo["optional tag"] = omitTag, TALtag
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
496 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
497 if attrsubst:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
498 repldict = parseAttributeReplacements(attrsubst)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
499 for key, value in repldict.items():
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
500 repldict[key] = self.compileExpression(value)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
501 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
502 repldict = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
503 if replace:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
504 todo["repldict"] = repldict
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
505 repldict = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
506 self.emitStartTag(name, self.replaceAttrs(attrlist, repldict), isend)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
507 if optTag:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
508 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
509 if content:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
510 self.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
511 if todo and position != (None, None):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
512 todo["position"] = position
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
513 self.todoPush(todo)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
514 if isend:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
515 self.emitEndElement(name, isend)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
516
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
517 def emitEndElement(self, name, isend=0, implied=0):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
518 todo = self.todoPop()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
519 if not todo:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
520 # Shortcut
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
521 if not isend:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
522 self.emitEndTag(name)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
523 return
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
524
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
525 self.position = position = todo.get("position", (None, None))
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
526 defineMacro = todo.get("defineMacro")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
527 useMacro = todo.get("useMacro")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
528 defineSlot = todo.get("defineSlot")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
529 fillSlot = todo.get("fillSlot")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
530 repeat = todo.get("repeat")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
531 content = todo.get("content")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
532 replace = todo.get("replace")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
533 condition = todo.get("condition")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
534 onError = todo.get("onError")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
535 define = todo.get("define")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
536 repldict = todo.get("repldict", {})
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
537 scope = todo.get("scope")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
538 optTag = todo.get("optional tag")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
539
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
540 if implied > 0:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
541 if defineMacro or useMacro or defineSlot or fillSlot:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
542 exc = METALError
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
543 what = "METAL"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
544 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
545 exc = TALError
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
546 what = "TAL"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
547 raise exc("%s attributes on <%s> require explicit </%s>" %
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
548 (what, name, name), position)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
549
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
550 if content:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
551 self.emitSubstitution(content, {})
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
552 if optTag:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
553 self.emitOptTag(name, optTag, isend)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
554 elif not isend:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
555 self.emitEndTag(name)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
556 if replace:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
557 self.emitSubstitution(replace, repldict)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
558 if repeat:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
559 self.emitRepeat(repeat)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
560 if condition:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
561 self.emitCondition(condition)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
562 if onError:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
563 self.emitOnError(name, onError)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
564 if scope:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
565 self.emit("endScope")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
566 if defineSlot:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
567 self.emitDefineSlot(defineSlot)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
568 if fillSlot:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
569 self.emitFillSlot(fillSlot)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
570 if useMacro:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
571 self.emitUseMacro(useMacro)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
572 if defineMacro:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
573 self.emitDefineMacro(defineMacro)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
574
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
575 def test():
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
576 t = TALGenerator()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
577 t.pushProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
578 t.emit("bar")
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
579 p = t.popProgram()
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
580 t.emit("foo", p)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
581
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
582 if __name__ == "__main__":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
583 test()

Roundup Issue Tracker: http://roundup-tracker.org/