def get_code_for_attribute(self, attribute, value): if attribute[0] == TAL_NS: if attribute[1] in ['content', 'replace']: (engine, value) = get_tales_engine(value) if engine == 'python': m = STRUCTURE_PREFIX.match(value) if m is not None: value = m.group(2) self._assert_valid_python(value) yield value if attribute[1] == 'define': for (scope, var, value) in parse_defines(value): (engine, value) = get_tales_engine(value) if engine == 'python': self._assert_valid_python(value) yield value elif attribute[1] == 'repeat': (engine, value) = get_tales_engine(value.split(None, 1)[1]) if engine == 'python': self._assert_valid_python(value) yield value else: try: for source in get_python_expressions(value): yield source except SyntaxError: print('Aborting due to Python syntax error in %s[%d]: %s', self.filename, self.linenumber, value) sys.exit(1)
def get_code_for_attribute(self, attribute, value): default_engine = self.config['default-engine'] if attribute[0] == TAL_NS: if attribute[1] in ['content', 'replace']: for (engine, value) in split_expression(value, default_engine): if engine == 'python': m = STRUCTURE_PREFIX.match(value) if m is not None: value = m.group(2) m = ENGINE_PREFIX.match(value) if (m is not None) and (m.group(1) == 'python'): m = None value = value.split(':', 1)[1] if m is None: value = '(%s)' % value self._assert_valid_python(value) yield value if attribute[1] == 'define': for (scope, var, value) in parse_defines(value): for (engine, value) in split_expression(value, default_engine): if engine == 'python': value = '(%s)' % value self._assert_valid_python(value) yield value elif attribute[1] == 'repeat': defines = parse_defines(value) if len(defines) != 1: print('Aborting due to syntax error in %s[%d]: %s' % (self.filename, self.linenumber, value)) scope, var, value = defines[0] for (engine, value) in split_expression(value, default_engine): if engine == 'python': self._assert_valid_python(value) yield value else: try: for source in get_python_expressions(value, default_engine): yield source except SyntaxError: print('Aborting due to Python syntax error in %s[%d]: %s' % (self.filename, self.linenumber, value)) sys.exit(1)
def get_code_for_attribute(self, attribute, value): default_engine = self.config['default-engine'] if attribute[0] == TAL_NS: if attribute[1] in ['content', 'replace']: for (engine, value) in split_expression(value, default_engine): if engine == 'python': m = STRUCTURE_PREFIX.match(value) if m is not None: value = m.group(2) m = ENGINE_PREFIX.match(value) if (m is not None) and (m.group(1) == 'python'): m = None value = value.split(':', 1)[1] if m is None: value = '(%s)' % value self._assert_valid_python(value) yield value if attribute[1] == 'define': for (scope, var, value) in parse_defines(value): for (engine, value) in split_expression(value, default_engine): if engine == 'python': value = '(%s)' % value self._assert_valid_python(value) yield value elif attribute[1] == 'repeat': defines = parse_defines(value) if len(defines) != 1: print('Aborting due to syntax error in %s[%d]: %s' % ( self.filename, self.linenumber, value)) scope, var, value = defines[0] for (engine, value) in split_expression(value, default_engine): if engine == 'python': self._assert_valid_python(value) yield value else: try: for source in get_python_expressions(value, default_engine): yield source except SyntaxError: print('Aborting due to Python syntax error in %s[%d]: %s' % (self.filename, self.linenumber, value)) sys.exit(1)
def get_code_for_attribute(self, attribute, value): if attribute[0] == TAL_NS: if attribute[1] in ['content', 'replace']: yield value if attribute[1] == 'define': for (scope, var, value) in parse_defines(value): yield value elif attribute[1] == 'repeat': yield value.split(None, 1)[1] else: for source in EXPRESSION.findall(value): yield source
def get_code_for_attribute(self, attribute, value): if attribute[0] == TAL_NS: if attribute[1] in ['content', 'replace']: for exp in self.iter_python_expressions(value): yield exp if attribute[1] == 'define': for (scope, var, value) in parse_defines(value): for exp in self.iter_python_expressions(value): yield value elif attribute[1] == 'repeat': yield REPEAT_EXPR.match(value.strip()).group('expr') else: for source in EXPRESSION.findall(value): for exp in self.iter_python_expressions(source): yield exp
def prev_visit_element(self, start, end, children): ns = start['ns_attrs'] for (prefix, attr), encoded in tuple(ns.items()): if prefix == TAL: ns[prefix, attr] = decode_htmlentities(encoded) # Validate namespace attributes validate_attributes(ns, TAL, tal.WHITELIST) validate_attributes(ns, I18N, i18n.WHITELIST) # Check attributes for language errors self._check_attributes(start['namespace'], ns) # Remember whitespace for item repetition if self._last is not None: self._whitespace = "\n" + " " * len(self._last.rsplit('\n', 1)[-1]) # Set element-local whitespace whitespace = self._whitespace # Set up switch try: clause = ns[TAL, 'switch'] except KeyError: switch = None else: switch = nodes.Value(clause) self._switches.append(switch) body = [] content = nodes.Sequence(body) # tal:content try: clause = ns[TAL, 'content'] except KeyError: pass else: key, value = tal.parse_substitution(clause) xlate = True if ns.get((I18N, 'translate')) == '' else False content = self._make_content_node(value, content, key, xlate) if end is None: # Make sure start-tag has opening suffix. start['suffix'] = ">" # Explicitly set end-tag. end = { 'prefix': '</', 'name': start['name'], 'space': '', 'suffix': '>' } # i18n:translate try: clause = ns[I18N, 'translate'] except KeyError: pass else: dynamic = ns.get((TAL, 'content')) or ns.get((TAL, 'replace')) if not dynamic: content = nodes.Translate(clause, content) # tal:attributes try: clause = ns[TAL, 'attributes'] except KeyError: TAL_ATTRIBUTES = {} else: TAL_ATTRIBUTES = tal.parse_attributes(clause) # i18n:attributes try: clause = ns[I18N, 'attributes'] except KeyError: I18N_ATTRIBUTES = {} else: I18N_ATTRIBUTES = i18n.parse_attributes(clause) # Prepare attributes from TAL language prepared = tal.prepare_attributes( start['attrs'], TAL_ATTRIBUTES, I18N_ATTRIBUTES, ns, self.DROP_NS ) # Create attribute nodes STATIC_ATTRIBUTES = self._create_static_attributes(prepared) ATTRIBUTES = self._create_attributes_nodes( prepared, I18N_ATTRIBUTES ) # Start- and end nodes start_tag = nodes.Start( start['name'], self._maybe_trim(start['prefix']), self._maybe_trim(start['suffix']), ATTRIBUTES ) stag = start_tag end_tag = nodes.End( end['name'], end['space'], self._maybe_trim(end['prefix']), self._maybe_trim(end['suffix']), ) if end is not None else None # tal:omit-tag try: clause = ns[TAL, 'omit-tag'] except KeyError: omit = False else: clause = clause.strip() if clause == "": omit = True else: expression = nodes.Negate(nodes.Value(clause)) omit = expression # Wrap start- and end-tags in condition start_tag = nodes.Condition(expression, start_tag) if end_tag is not None: end_tag = nodes.Condition(expression, end_tag) if omit is True or start['namespace'] in self.DROP_NS: inner = content else: inner = nodes.Element( start_tag, end_tag, content, ) # Assign static attributes dictionary to "attrs" value inner = nodes.Define( [nodes.Alias(["attrs"], STATIC_ATTRIBUTES)], inner, ) if omit is not False: inner = nodes.Cache([omit], inner) # tal:replace try: clause = ns[TAL, 'replace'] except KeyError: pass else: key, value = tal.parse_substitution(clause) xlate = True if ns.get((I18N, 'translate')) == '' else False inner = self._make_content_node(value, inner, key, xlate) # tal:define try: clause = ns[TAL, 'define'] except KeyError: DEFINE = skip else: defines = tal.parse_defines(clause) if defines is None: raise ParseError("Invalid define syntax.", clause) DEFINE = partial( nodes.Define, [nodes.Assignment( names, nodes.Value(expr), context == "local") for (context, names, expr) in defines], ) # tal:case try: clause = ns[TAL, 'case'] except KeyError: CASE = skip else: value = nodes.Value(clause) for switch in reversed(self._switches): if switch is not None: break else: raise LanguageError( "Must define switch on a parent element.", clause ) CASE = lambda node: nodes.Define( [nodes.Assignment(["default"], switch, True)], nodes.Condition( nodes.Equality(switch, value), node, ) ) # tal:repeat try: clause = ns[TAL, 'repeat'] except KeyError: REPEAT = skip else: defines = tal.parse_defines(clause) assert len(defines) == 1 context, names, expr = defines[0] expression = nodes.Value(expr) REPEAT = partial( nodes.Repeat, names, expression, context == "local", whitespace ) # tal:condition try: clause = ns[TAL, 'condition'] except KeyError: CONDITION = skip else: expression = nodes.Value(clause) CONDITION = partial(nodes.Condition, expression) # tal:switch if switch is None: SWITCH = skip else: SWITCH = partial(nodes.Cache, [switch]) # i18n:domain try: clause = ns[I18N, 'domain'] except KeyError: DOMAIN = skip else: DOMAIN = partial(nodes.Domain, clause) # i18n:name try: clause = ns[I18N, 'name'] except KeyError: NAME = skip else: NAME = partial(nodes.Name, clause) # The "slot" node next is the first node level that can serve # as a macro slot slot = wrap( inner, DEFINE, CASE, CONDITION, REPEAT, SWITCH, DOMAIN, ) slot = wrap( slot, NAME ) # tal:on-error try: clause = ns[TAL, 'on-error'] except KeyError: ON_ERROR = skip else: key, value = tal.parse_substitution(clause) translate = True if ns.get((I18N, 'translate')) == '' else False fallback = self._make_content_node(value, None, key, translate) if omit is False and start['namespace'] not in self.DROP_NS: fallback = nodes.Element( start_tag, end_tag, fallback, ) ON_ERROR = partial(nodes.OnError, fallback, 'error') clause = ns.get((META, 'interpolation')) if clause in ('false', 'off'): INTERPOLATION = False elif clause in ('true', 'on'): INTERPOLATION = True elif clause is None: INTERPOLATION = self._interpolation[-1] else: raise LanguageError("Bad interpolation setting.", clause) self._interpolation.append(INTERPOLATION) # Visit content body for child in children: body.append(self.visit(*child)) self._switches.pop() self._interpolation.pop() slot = wrap( slot, ON_ERROR ) stag.replayable = False if self.binds: try: bind_replay_clause = ns[(PRAMTAL, "bind-replay")] splits = bind_replay_clause.split(" ") if len(splits) != 2: raise LanguageError("Invalid bind replay.", bind_replay_clause) events = splits[1].split(";") slot = BindReplay(splits[0], events, slot) stag.replayable = True except KeyError: pass if self.binds: try: bind_clause = ns[(PRAMTAL, "bind-change")] bind_splits = bind_clause.strip().split(" ") if len(bind_splits) > 3: raise LanguageError("Invalid bind syntax.", bind_clause) if not "#" in bind_splits[0]: raise LanguageError("No bind model target specified.", bind_clause) first_split = bind_splits[0][1:] if "." in first_split: bind_model,bind_ons = first_split.split(".", 1) bind_ons = bind_ons.strip().split(".") else: bind_model = first_split bind_ons = [] bind_attrs = [] if len(bind_splits) > 1: bind_attrs = bind_splits[1].split(";") stag.replayable = True slot = BindChange(bind_model, bind_ons, bind_attrs, slot ) except KeyError: pass stag.repeatable = False if self.binds: try: bind_repeat_clause = ns[(PRAMTAL, "bind-repeat")] except KeyError: pass else: splits = bind_repeat_clause.split(" ") if len(splits) != 2: raise LanguageError("Invalid define model.", bind_repeat_clause) if not splits[0].startswith("#"): raise LanguageError("need # in alias.", bind_repeat_clause) slot = BindRepeat(splits[0][1:], splits[1], slot) stag.repeatable = True try: define_model_clause = ns[(PRAMTAL, "define-model")] except KeyError: pass else: pairs = define_model_clause.split(";") models = [] for pair in pairs: pair = pair.strip() splits = pair.split(" ") if len(splits) != 2: raise LanguageError("Invalid define model.", pair) if not splits[0].startswith("#"): raise LanguageError("need # in alias.", pair) models.append((splits[0][1:], splits[1])) slot = DefineModel(models, slot) return slot
def visit_element(self, start, end, children): ns = start['ns_attrs'] ADDITIONAL_ATTRS = {} for (prefix, attr), encoded in tuple(ns.items()): if prefix == TAL: ns[prefix, attr] = decode_htmlentities(encoded) # Validate namespace attributes validate_attributes(ns, TAL, tal.WHITELIST) validate_attributes(ns, METAL, metal.WHITELIST) validate_attributes(ns, I18N, i18n.WHITELIST) # Check attributes for language errors self._check_attributes(start['namespace'], ns) # Remember whitespace for item repetition if self._last is not None: self._whitespace = "\n" + " " * len(self._last.rsplit('\n', 1)[-1]) # Set element-local whitespace whitespace = self._whitespace # Set up switch try: clause = ns[TAL, 'switch'] except KeyError: switch = None else: value = nodes.Value(clause) switch = value, nodes.Copy(value) self._switches.append(switch) body = [] # Include macro use_macro = ns.get((METAL, 'use-macro')) extend_macro = ns.get((METAL, 'extend-macro')) if use_macro or extend_macro: omit = True slots = [] self._use_macro.append(slots) if use_macro: inner = nodes.UseExternalMacro( nodes.Value(use_macro), slots, False ) else: inner = nodes.UseExternalMacro( nodes.Value(extend_macro), slots, True ) # -or- include tag else: content = nodes.Sequence(body) # tal:content try: clause = ns[TAL, 'content'] except KeyError: pass else: clause = self.get_semantic(clause, ns, 'content') key, value = tal.parse_substitution(clause) xlate = True if ns.get((I18N, 'translate')) == '' else False content = self._make_content_node(value, content, key, xlate) if end is None: # Make sure start-tag has opening suffix. start['suffix'] = ">" # Explicitly set end-tag. end = { 'prefix': '</', 'name': start['name'], 'space': '', 'suffix': '>' } # i18n:translate try: clause = ns[I18N, 'translate'] except KeyError: pass else: dynamic = ns.get((TAL, 'content')) or ns.get((TAL, 'replace')) if not dynamic: content = nodes.Translate(clause, content) # tal:attributes try: clause = ns[TAL, 'attributes'] except KeyError: TAL_ATTRIBUTES = [] else: TAL_ATTRIBUTES = tal.parse_attributes(clause) # i18n:attributes try: clause = ns[I18N, 'attributes'] except KeyError: I18N_ATTRIBUTES = {} else: I18N_ATTRIBUTES = i18n.parse_attributes(clause) # Prepare attributes from TAL language prepared = tal.prepare_attributes( start['attrs'], TAL_ATTRIBUTES, I18N_ATTRIBUTES, ns, self.DROP_NS ) # Create attribute nodes STATIC_ATTRIBUTES = self._create_static_attributes(prepared) ATTRIBUTES = self._create_attributes_nodes( prepared, I18N_ATTRIBUTES, STATIC_ATTRIBUTES ) # Start- and end nodes start_tag = nodes.Start( start['name'], self._maybe_trim(start['prefix']), self._maybe_trim(start['suffix']), ATTRIBUTES ) end_tag = nodes.End( end['name'], end['space'], self._maybe_trim(end['prefix']), self._maybe_trim(end['suffix']), ) if end is not None else None # tal:omit-tag try: clause = ns[TAL, 'omit-tag'] except KeyError: omit = False else: clause = clause.strip() if clause == "": omit = True else: expression = nodes.Negate(nodes.Value(clause)) omit = expression # Wrap start- and end-tags in condition start_tag = nodes.Condition(expression, start_tag) if end_tag is not None: end_tag = nodes.Condition(expression, end_tag) if omit is True or start['namespace'] in self.DROP_NS: inner = content else: inner = nodes.Element( start_tag, end_tag, content, ) # Assign static attributes dictionary to "attrs" value inner = nodes.Define( [nodes.Alias(["attrs"], STATIC_ATTRIBUTES or EMPTY_DICT)], inner, ) if omit is not False: inner = nodes.Cache([omit], inner) # tal:replace try: clause = ns[TAL, 'replace'] except KeyError: pass else: clause = self.get_semantic(clause, ns, 'replace') key, value = tal.parse_substitution(clause) xlate = True if ns.get((I18N, 'translate')) == '' else False inner = self._make_content_node(value, inner, key, xlate) # metal:define-slot try: clause = ns[METAL, 'define-slot'] except KeyError: DEFINE_SLOT = skip else: DEFINE_SLOT = partial(nodes.DefineSlot, clause) # tal:define try: clause = ns[TAL, 'define'] except KeyError: DEFINE = skip else: defines = tal.parse_defines(clause) if defines is None: raise ParseError("Invalid define syntax.", clause) DEFINE = partial( nodes.Define, [nodes.Assignment( names, nodes.Value(expr), context == "local") for (context, names, expr) in defines], ) # tal:case try: clause = ns[TAL, 'case'] except KeyError: CASE = skip else: value = nodes.Value(clause) for switch in reversed(self._switches): if switch is not None: break else: raise LanguageError( "Must define switch on a parent element.", clause ) CASE = lambda node: nodes.Define( [nodes.Alias(["default"], switch[1], False)], nodes.Condition( nodes.Equality(switch[0], value), nodes.Cancel([switch[0]], node), )) # tal:repeat try: clause = ns[TAL, 'repeat'] except KeyError: REPEAT = skip else: defines = tal.parse_defines(clause) assert len(defines) == 1 context, names, expr = defines[0] expression = nodes.Value(expr) if start['namespace'] == TAL: self._last = None self._whitespace = whitespace.lstrip('\n') whitespace = "" REPEAT = partial( nodes.Repeat, names, expression, context == "local", whitespace ) # tal:condition try: clause = ns[TAL, 'condition'] except KeyError: CONDITION = skip else: expression = nodes.Value(clause) CONDITION = partial(nodes.Condition, expression) # tal:switch if switch is None: SWITCH = skip else: SWITCH = partial(nodes.Cache, list(switch)) # i18n:domain try: clause = ns[I18N, 'domain'] except KeyError: DOMAIN = skip else: DOMAIN = partial(nodes.Domain, clause) # i18n:name try: clause = ns[I18N, 'name'] except KeyError: NAME = skip else: if not clause.strip(): NAME = skip else: NAME = partial(nodes.Name, clause) # The "slot" node next is the first node level that can serve # as a macro slot slot = wrap( inner, DEFINE_SLOT, DEFINE, CASE, CONDITION, REPEAT, SWITCH, DOMAIN, ) # metal:fill-slot try: clause = ns[METAL, 'fill-slot'] except KeyError: pass else: if not clause.strip(): raise LanguageError( "Must provide a non-trivial string for metal:fill-slot.", clause ) index = -(1 + int(bool(use_macro or extend_macro))) try: slots = self._use_macro[index] except IndexError: raise LanguageError( "Cannot use metal:fill-slot without metal:use-macro.", clause ) slots = self._use_macro[index] slots.append(nodes.FillSlot(clause, slot)) # metal:define-macro try: clause = ns[METAL, 'define-macro'] except KeyError: pass else: self._macros[clause] = slot slot = nodes.UseInternalMacro(clause) slot = wrap( slot, NAME ) # tal:on-error try: clause = ns[TAL, 'on-error'] except KeyError: ON_ERROR = skip else: key, value = tal.parse_substitution(clause) translate = True if ns.get((I18N, 'translate')) == '' else False fallback = self._make_content_node(value, None, key, translate) if omit is False and start['namespace'] not in self.DROP_NS: start_tag = copy(start_tag) start_tag.attributes = nodes.Sequence( start_tag.attributes.extract( lambda attribute: isinstance(attribute, nodes.Attribute) and isinstance(attribute.expression, ast.Str) ) ) if end_tag is None: # Make sure start-tag has opening suffix. We don't # allow self-closing element here. start_tag.suffix = ">" # Explicitly set end-tag. end_tag = nodes.End(start_tag.name, '', '</', '>',) fallback = nodes.Element( start_tag, end_tag, fallback, ) ON_ERROR = partial(nodes.OnError, fallback, 'error') clause = ns.get((META, 'interpolation')) if clause in ('false', 'off'): INTERPOLATION = False elif clause in ('true', 'on'): INTERPOLATION = True elif clause is None: INTERPOLATION = self._interpolation[-1] else: raise LanguageError("Bad interpolation setting.", clause) self._interpolation.append(INTERPOLATION) # Visit content body for child in children: body.append(self.visit(*child)) self._switches.pop() self._interpolation.pop() if use_macro: self._use_macro.pop() return wrap( slot, ON_ERROR )
def prev_visit_element(self, start, end, children): ns = start['ns_attrs'] for (prefix, attr), encoded in tuple(ns.items()): if prefix == TAL: ns[prefix, attr] = decode_htmlentities(encoded) # Validate namespace attributes validate_attributes(ns, TAL, tal.WHITELIST) validate_attributes(ns, I18N, i18n.WHITELIST) # Check attributes for language errors self._check_attributes(start['namespace'], ns) # Remember whitespace for item repetition if self._last is not None: self._whitespace = "\n" + " " * len(self._last.rsplit('\n', 1)[-1]) # Set element-local whitespace whitespace = self._whitespace # Set up switch try: clause = ns[TAL, 'switch'] except KeyError: switch = None else: switch = nodes.Value(clause) self._switches.append(switch) body = [] content = nodes.Sequence(body) # tal:content try: clause = ns[TAL, 'content'] except KeyError: pass else: key, value = tal.parse_substitution(clause) xlate = True if ns.get((I18N, 'translate')) == '' else False content = self._make_content_node(value, content, key, xlate) if end is None: # Make sure start-tag has opening suffix. start['suffix'] = ">" # Explicitly set end-tag. end = { 'prefix': '</', 'name': start['name'], 'space': '', 'suffix': '>' } # i18n:translate try: clause = ns[I18N, 'translate'] except KeyError: pass else: dynamic = ns.get((TAL, 'content')) or ns.get((TAL, 'replace')) if not dynamic: content = nodes.Translate(clause, content) # tal:attributes try: clause = ns[TAL, 'attributes'] except KeyError: TAL_ATTRIBUTES = {} else: TAL_ATTRIBUTES = tal.parse_attributes(clause) # i18n:attributes try: clause = ns[I18N, 'attributes'] except KeyError: I18N_ATTRIBUTES = {} else: I18N_ATTRIBUTES = i18n.parse_attributes(clause) # Prepare attributes from TAL language prepared = tal.prepare_attributes(start['attrs'], TAL_ATTRIBUTES, I18N_ATTRIBUTES, ns, self.DROP_NS) # Create attribute nodes STATIC_ATTRIBUTES = self._create_static_attributes(prepared) ATTRIBUTES = self._create_attributes_nodes(prepared, I18N_ATTRIBUTES) # Start- and end nodes start_tag = nodes.Start(start['name'], self._maybe_trim(start['prefix']), self._maybe_trim(start['suffix']), ATTRIBUTES) stag = start_tag end_tag = nodes.End( end['name'], end['space'], self._maybe_trim(end['prefix']), self._maybe_trim(end['suffix']), ) if end is not None else None # tal:omit-tag try: clause = ns[TAL, 'omit-tag'] except KeyError: omit = False else: clause = clause.strip() if clause == "": omit = True else: expression = nodes.Negate(nodes.Value(clause)) omit = expression # Wrap start- and end-tags in condition start_tag = nodes.Condition(expression, start_tag) if end_tag is not None: end_tag = nodes.Condition(expression, end_tag) if omit is True or start['namespace'] in self.DROP_NS: inner = content else: inner = nodes.Element( start_tag, end_tag, content, ) # Assign static attributes dictionary to "attrs" value inner = nodes.Define( [nodes.Alias(["attrs"], STATIC_ATTRIBUTES)], inner, ) if omit is not False: inner = nodes.Cache([omit], inner) # tal:replace try: clause = ns[TAL, 'replace'] except KeyError: pass else: key, value = tal.parse_substitution(clause) xlate = True if ns.get((I18N, 'translate')) == '' else False inner = self._make_content_node(value, inner, key, xlate) # tal:define try: clause = ns[TAL, 'define'] except KeyError: DEFINE = skip else: defines = tal.parse_defines(clause) if defines is None: raise ParseError("Invalid define syntax.", clause) DEFINE = partial( nodes.Define, [ nodes.Assignment(names, nodes.Value(expr), context == "local") for (context, names, expr) in defines ], ) # tal:case try: clause = ns[TAL, 'case'] except KeyError: CASE = skip else: value = nodes.Value(clause) for switch in reversed(self._switches): if switch is not None: break else: raise LanguageError("Must define switch on a parent element.", clause) CASE = lambda node: nodes.Define([ nodes.Assignment(["default"], switch, True) ], nodes.Condition( nodes.Equality(switch, value), node, )) # tal:repeat try: clause = ns[TAL, 'repeat'] except KeyError: REPEAT = skip else: defines = tal.parse_defines(clause) assert len(defines) == 1 context, names, expr = defines[0] expression = nodes.Value(expr) REPEAT = partial(nodes.Repeat, names, expression, context == "local", whitespace) # tal:condition try: clause = ns[TAL, 'condition'] except KeyError: CONDITION = skip else: expression = nodes.Value(clause) CONDITION = partial(nodes.Condition, expression) # tal:switch if switch is None: SWITCH = skip else: SWITCH = partial(nodes.Cache, [switch]) # i18n:domain try: clause = ns[I18N, 'domain'] except KeyError: DOMAIN = skip else: DOMAIN = partial(nodes.Domain, clause) # i18n:name try: clause = ns[I18N, 'name'] except KeyError: NAME = skip else: NAME = partial(nodes.Name, clause) # The "slot" node next is the first node level that can serve # as a macro slot slot = wrap( inner, DEFINE, CASE, CONDITION, REPEAT, SWITCH, DOMAIN, ) slot = wrap(slot, NAME) # tal:on-error try: clause = ns[TAL, 'on-error'] except KeyError: ON_ERROR = skip else: key, value = tal.parse_substitution(clause) translate = True if ns.get((I18N, 'translate')) == '' else False fallback = self._make_content_node(value, None, key, translate) if omit is False and start['namespace'] not in self.DROP_NS: fallback = nodes.Element( start_tag, end_tag, fallback, ) ON_ERROR = partial(nodes.OnError, fallback, 'error') clause = ns.get((META, 'interpolation')) if clause in ('false', 'off'): INTERPOLATION = False elif clause in ('true', 'on'): INTERPOLATION = True elif clause is None: INTERPOLATION = self._interpolation[-1] else: raise LanguageError("Bad interpolation setting.", clause) self._interpolation.append(INTERPOLATION) # Visit content body for child in children: body.append(self.visit(*child)) self._switches.pop() self._interpolation.pop() slot = wrap(slot, ON_ERROR) stag.replayable = False if self.binds: try: bind_replay_clause = ns[(PRAMTAL, "bind-replay")] splits = bind_replay_clause.split(" ") if len(splits) != 2: raise LanguageError("Invalid bind replay.", bind_replay_clause) events = splits[1].split(";") slot = BindReplay(splits[0], events, slot) stag.replayable = True except KeyError: pass if self.binds: try: bind_clause = ns[(PRAMTAL, "bind-change")] bind_splits = bind_clause.strip().split(" ") if len(bind_splits) > 3: raise LanguageError("Invalid bind syntax.", bind_clause) if not "#" in bind_splits[0]: raise LanguageError("No bind model target specified.", bind_clause) first_split = bind_splits[0][1:] if "." in first_split: bind_model, bind_ons = first_split.split(".", 1) bind_ons = bind_ons.strip().split(".") else: bind_model = first_split bind_ons = [] bind_attrs = [] if len(bind_splits) > 1: bind_attrs = bind_splits[1].split(";") stag.replayable = True slot = BindChange(bind_model, bind_ons, bind_attrs, slot) except KeyError: pass stag.repeatable = False if self.binds: try: bind_repeat_clause = ns[(PRAMTAL, "bind-repeat")] except KeyError: pass else: splits = bind_repeat_clause.split(" ") if len(splits) != 2: raise LanguageError("Invalid define model.", bind_repeat_clause) if not splits[0].startswith("#"): raise LanguageError("need # in alias.", bind_repeat_clause) slot = BindRepeat(splits[0][1:], splits[1], slot) stag.repeatable = True try: define_model_clause = ns[(PRAMTAL, "define-model")] except KeyError: pass else: pairs = define_model_clause.split(";") models = [] for pair in pairs: pair = pair.strip() splits = pair.split(" ") if len(splits) != 2: raise LanguageError("Invalid define model.", pair) if not splits[0].startswith("#"): raise LanguageError("need # in alias.", pair) models.append((splits[0][1:], splits[1])) slot = DefineModel(models, slot) return slot