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