def visit_Assignment(self, node): for name in node.names: if name in COMPILER_INTERNALS_OR_DISALLOWED: raise TranslationError( "Name disallowed by compiler.", name ) if name.startswith('__'): raise TranslationError( "Name disallowed by compiler (double underscore).", name ) assignment = self._engine(node.expression, store("__value")) if len(node.names) != 1: target = ast.Tuple( elts=[store_econtext(name) for name in node.names], ctx=ast.Store(), ) else: target = store_econtext(node.names[0]) assignment.append(ast.Assign(targets=[target], value=load("__value"))) for name in node.names: if not node.local: assignment += template( "rcontext[KEY] = __value", KEY=ast.Str(s=native_string(name)) ) return assignment
def visit_Assignment(self, node): for name in node.names: if name in COMPILER_INTERNALS_OR_DISALLOWED: raise TranslationError("Name disallowed by compiler.", name) if name.startswith('__'): raise TranslationError( "Name disallowed by compiler (double underscore).", name) assignment = self._engine(node.expression, store("__value")) if len(node.names) != 1: target = ast.Tuple( elts=[store_econtext(name) for name in node.names], ctx=ast.Store(), ) else: target = store_econtext(node.names[0]) assignment.append(ast.Assign(targets=[target], value=load("__value"))) for name in node.names: if not node.local: assignment += template("rcontext[KEY] = __value", KEY=ast.Str(s=native_string(name))) return assignment
def _leave_assignment(self, names): for name in names: for stmt in template( "deleteitem(econtext, KEY, BACKUP, __marker)", deleteitem=Symbol(deleteitem), BACKUP=identifier("backup_%s" % name, id(names)), KEY=ast.Str(s=native_string(name)), ): yield stmt
def visit_Repeat(self, node): # Used for loop variable definition and restore self._scopes.append(set()) # Variable assignment and repeat key for single- and # multi-variable repeat clause if node.local: contexts = "econtext", else: contexts = "econtext", "rcontext" for name in node.names: if name in COMPILER_INTERNALS_OR_DISALLOWED: raise TranslationError( "Name disallowed by compiler.", name ) if len(node.names) > 1: targets = [ ast.Tuple(elts=[ subscript(native_string(name), load(context), ast.Store()) for name in node.names], ctx=ast.Store()) for context in contexts ] key = ast.Tuple( elts=[ast.Str(s=name) for name in node.names], ctx=ast.Load()) else: name = node.names[0] targets = [ subscript(native_string(name), load(context), ast.Store()) for context in contexts ] key = ast.Str(s=node.names[0]) repeat = identifier("__repeat", id(node)) index = identifier("__index", id(node)) iterator = identifier("__iterator", id(node)) assignment = [ast.Assign(targets=targets, value=load("__item"))] # Make repeat assignment in outer loop names = node.names local = node.local outer = self._engine(node.expression, store(iterator)) if local: outer[:] = list(self._enter_assignment(names)) + outer outer += template( "REPEAT = econtext['repeat'](key, ITERATOR)", key=key, INDEX=index, REPEAT=repeat, ITERATOR=iterator ) outer += template( "INDEX = REPEAT.length", INDEX=index, REPEAT=repeat ) # Set a trivial default value for each name assigned to make # sure we assign a value even if the iteration is empty for name in node.names: outer += [ast.Assign( targets=[store_econtext(name)], value=load("None")) ] inner = template( "REPEAT._next()", REPEAT=repeat ) # Compute inner body inner += self.visit(node.node) # After each iteration, decrease the index inner += template("index -= 1", index=index) # For items up to N - 1, emit repeat whitespace inner += template( "if INDEX > 0: STACK.t(WHITESPACE)", STACK=self._current_stack, INDEX=index, WHITESPACE=ast.Str(s=node.whitespace) ) # Main repeat loop outer += [ast.For( target=store("__item"), iter=load(iterator), body=assignment + inner, )] # Finally, clean up assignment if it's local if outer: outer += self._leave_assignment(names) self._scopes.pop() return outer
def store_rcontext(name): name = native_string(name) return subscript(name, load("rcontext"), ast.Store())
def visit_Translate(self, node): """Translation. Visit items and assign output to a default value. Finally, compile a translation expression and use either result or default. """ body = [] # Track the blocks of this translation self._translations.append(set()) # Prepare new stream append = identifier("append", id(node)) stream = identifier("stream", id(node)) body += template("s = new_list", s=stream, new_list=LIST) + \ template("a = s.append", a=append, s=stream) # Visit body to generate the message body code = self.visit(node.node) swap(ast.Suite(body=code), load(append), "__append") body += code # Reduce white space and assign as message id msgid = identifier("msgid", id(node)) body += template( "msgid = __re_whitespace(''.join(stream)).strip()", msgid=msgid, stream=stream ) default = msgid # Compute translation block mapping if applicable names = self._translations[-1] if names: keys = [] values = [] for name in names: stream, append = self._get_translation_identifiers(name) keys.append(ast.Str(s=name)) values.append(load(stream)) # Initialize value body.insert( 0, ast.Assign( targets=[store(stream)], value=ast.Str(s=native_string("")))) mapping = ast.Dict(keys=keys, values=values) else: mapping = None # if this translation node has a name, use it as the message id if node.msgid: msgid = ast.Str(s=node.msgid) # emit the translation expression body += template( "STACK.t(translate(" "msgid, mapping=mapping, default=default, domain=__i18n_domain))", stack=self._current_stack,msgid=msgid, default=default, mapping=mapping ) # pop away translation block reference self._translations.pop() return body
def visit_Repeat(self, node): # Used for loop variable definition and restore self._scopes.append(set()) # Variable assignment and repeat key for single- and # multi-variable repeat clause if node.local: contexts = "econtext", else: contexts = "econtext", "rcontext" for name in node.names: if name in COMPILER_INTERNALS_OR_DISALLOWED: raise TranslationError("Name disallowed by compiler.", name) if len(node.names) > 1: targets = [ ast.Tuple(elts=[ subscript(native_string(name), load(context), ast.Store()) for name in node.names ], ctx=ast.Store()) for context in contexts ] key = ast.Tuple(elts=[ast.Str(s=name) for name in node.names], ctx=ast.Load()) else: name = node.names[0] targets = [ subscript(native_string(name), load(context), ast.Store()) for context in contexts ] key = ast.Str(s=node.names[0]) repeat = identifier("__repeat", id(node)) index = identifier("__index", id(node)) iterator = identifier("__iterator", id(node)) assignment = [ast.Assign(targets=targets, value=load("__item"))] # Make repeat assignment in outer loop names = node.names local = node.local outer = self._engine(node.expression, store(iterator)) if local: outer[:] = list(self._enter_assignment(names)) + outer outer += template("REPEAT = econtext['repeat'](key, ITERATOR)", key=key, INDEX=index, REPEAT=repeat, ITERATOR=iterator) outer += template("INDEX = REPEAT.length", INDEX=index, REPEAT=repeat) # Set a trivial default value for each name assigned to make # sure we assign a value even if the iteration is empty for name in node.names: outer += [ ast.Assign(targets=[store_econtext(name)], value=load("None")) ] inner = template("REPEAT._next()", REPEAT=repeat) # Compute inner body inner += self.visit(node.node) # After each iteration, decrease the index inner += template("index -= 1", index=index) # For items up to N - 1, emit repeat whitespace inner += template("if INDEX > 0: STACK.t(WHITESPACE)", STACK=self._current_stack, INDEX=index, WHITESPACE=ast.Str(s=node.whitespace)) # Main repeat loop outer += [ ast.For( target=store("__item"), iter=load(iterator), body=assignment + inner, ) ] # Finally, clean up assignment if it's local if outer: outer += self._leave_assignment(names) self._scopes.pop() return outer
def visit_Translate(self, node): """Translation. Visit items and assign output to a default value. Finally, compile a translation expression and use either result or default. """ body = [] # Track the blocks of this translation self._translations.append(set()) # Prepare new stream append = identifier("append", id(node)) stream = identifier("stream", id(node)) body += template("s = new_list", s=stream, new_list=LIST) + \ template("a = s.append", a=append, s=stream) # Visit body to generate the message body code = self.visit(node.node) swap(ast.Suite(body=code), load(append), "__append") body += code # Reduce white space and assign as message id msgid = identifier("msgid", id(node)) body += template("msgid = __re_whitespace(''.join(stream)).strip()", msgid=msgid, stream=stream) default = msgid # Compute translation block mapping if applicable names = self._translations[-1] if names: keys = [] values = [] for name in names: stream, append = self._get_translation_identifiers(name) keys.append(ast.Str(s=name)) values.append(load(stream)) # Initialize value body.insert( 0, ast.Assign(targets=[store(stream)], value=ast.Str(s=native_string("")))) mapping = ast.Dict(keys=keys, values=values) else: mapping = None # if this translation node has a name, use it as the message id if node.msgid: msgid = ast.Str(s=node.msgid) # emit the translation expression body += template( "STACK.t(translate(" "msgid, mapping=mapping, default=default, domain=__i18n_domain))", stack=self._current_stack, msgid=msgid, default=default, mapping=mapping) # pop away translation block reference self._translations.pop() return body