[Checkins] SVN: Sandbox/malthe/chameleon.core/ Reworked global scope symbol initialization.
Malthe Borch
mborch at gmail.com
Wed Nov 26 18:16:31 EST 2008
Log message for revision 93374:
Reworked global scope symbol initialization.
Changed:
U Sandbox/malthe/chameleon.core/CHANGES.txt
U Sandbox/malthe/chameleon.core/src/chameleon/core/generation.py
U Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py
-=-
Modified: Sandbox/malthe/chameleon.core/CHANGES.txt
===================================================================
--- Sandbox/malthe/chameleon.core/CHANGES.txt 2008-11-26 23:12:40 UTC (rev 93373)
+++ Sandbox/malthe/chameleon.core/CHANGES.txt 2008-11-26 23:16:30 UTC (rev 93374)
@@ -4,6 +4,9 @@
HEAD
~~~~
+- Reworked global scope initialization; we now bind these using a
+ closure. [malthe]
+
- Reworked repeat-variable logic. An iterator would be realized at any
rate, so let's not try to be clever. [malthe]
Modified: Sandbox/malthe/chameleon.core/src/chameleon/core/generation.py
===================================================================
--- Sandbox/malthe/chameleon.core/src/chameleon/core/generation.py 2008-11-26 23:12:40 UTC (rev 93373)
+++ Sandbox/malthe/chameleon.core/src/chameleon/core/generation.py 2008-11-26 23:16:30 UTC (rev 93374)
@@ -5,23 +5,27 @@
import utils
import etree
-template_wrapper = """\
-def render(%(init)s, %(args)s%(extra)s%(language)s=None):
-\t%(out)s, %(write)s = %(init)s.initialize_stream()
-\t%(attributes)s, %(repeat)s = %(init)s.initialize_tal()
-\t%(scope)s = %(init)s.initialize_scope()
-\t%(domain)s = None
-
-%(body)s
-\treturn %(out)s.getvalue()
+function_template = """\
+def bind():
+%(imports)s
+\tdef %(name)s(%(arguments)s):
+%(source)s
+%(return)s
+\treturn %(name)s
"""
-macro_wrapper = """\
-def render(%(init)s, %(kwargs)s%(extra)s):
-\t%(attributes)s, %(repeat)s = %(init)s.initialize_tal()
-\t%(domain)s = None
-%(body)s
-"""
+def indent_block(text, level=2):
+ return "\n".join(("\t" * level + s for s in text.split('\n')))
+
+def function_wrap(name, args, imports, source, return_expr=""):
+ format_values = {
+ 'name': name,
+ 'imports': indent_block('\n'.join(imports), 1),
+ 'arguments': ', '.join(args),
+ 'source': indent_block(source),
+ 'return': indent_block("return %s" % return_expr)}
+
+ return function_template % format_values
class Marker(object):
def __nonzero__(self):
Modified: Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py
===================================================================
--- Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py 2008-11-26 23:12:40 UTC (rev 93373)
+++ Sandbox/malthe/chameleon.core/src/chameleon/core/translation.py 2008-11-26 23:16:30 UTC (rev 93374)
@@ -1,4 +1,5 @@
from StringIO import StringIO
+from cPickle import dumps
import generation
import codegen
@@ -319,11 +320,13 @@
if len(self.element):
raise ValueError(
"Can't translate dynamic text block with elements in it.")
-
+
+ init_stream = types.value('_init_stream()')
+ init_stream.symbol_mapping['_init_stream'] = generation.initialize_stream
+
subclauses = []
subclauses.append(clauses.Define(
- types.declaration((self.symbols.out, self.symbols.write)),
- types.template('%(init)s.initialize_stream()')))
+ types.declaration((self.symbols.out, self.symbols.write)), init_stream))
for part in text:
if isinstance(part, types.expression):
@@ -388,6 +391,9 @@
"%s=%s" % (variable, variable) for variable in \
itertools.chain(*self.stream.scope))
+ init_stream = types.value('_init_stream()')
+ init_stream.symbol_mapping['_init_stream'] = generation.initialize_stream
+
subclauses = []
subclauses.append(
clauses.Method(
@@ -397,8 +403,7 @@
subclauses.append(
clauses.UpdateScope(self.symbols.scope, remote_scope))
subclauses.append(clauses.Assign(
- types.template('%(init)s.initialize_stream()'),
- (self.symbols.out, self.symbols.write)))
+ init_stream, (self.symbols.out, self.symbols.write)))
subclauses.append(clauses.Visit(element.node))
_.append(clauses.Group(subclauses))
@@ -437,10 +442,12 @@
for element in elements:
name = element.node.translation_name
+ init_stream = types.value('_init_stream()')
+ init_stream.symbol_mapping['_init_stream'] = generation.initialize_stream
+
subclauses = []
subclauses.append(clauses.Define(
- types.declaration((self.symbols.out, self.symbols.write)),
- types.template('%(init)s.initialize_stream()')))
+ types.declaration((self.symbols.out, self.symbols.write)), init_stream))
subclauses.append(clauses.Visit(element.node))
subclauses.append(clauses.Assign(
types.template('%(out)s.getvalue()'),
@@ -698,15 +705,10 @@
else:
del element.attrib[utils.metal_attr('define-macro')]
- if global_scope:
- wrapper = generation.template_wrapper
- else:
- wrapper = generation.macro_wrapper
-
# initialize code stream object
stream = generation.CodeIO(
self.root.node.symbols, encoding=self.encoding,
- indentation=1, indentation_string="\t")
+ indentation=0, indentation_string="\t")
# initialize variable scope
stream.scope.append(set(
@@ -717,6 +719,32 @@
stream.symbols.language) + \
tuple(parameters)))
+ # set up initialization code
+ stream.symbol_mapping['_init_stream'] = generation.initialize_stream
+ stream.symbol_mapping['_init_scope'] = generation.initialize_scope
+ stream.symbol_mapping['_init_tal'] = generation.initialize_tal
+
+ if global_scope:
+ assignments = (
+ clauses.Assign(
+ types.value("_init_stream()"), ("%(out)s", "%(write)s")),
+ clauses.Assign(
+ types.value("_init_scope()"), "%(scope)s"),
+ clauses.Assign(
+ types.value("_init_tal()"), ("%(attributes)s", "%(repeat)s")),
+ clauses.Assign(
+ types.template("None"), "%(domain)s"))
+ else:
+ assignments = (
+ clauses.Assign(
+ types.value("_init_tal()"), ("%(attributes)s", "%(repeat)s")),
+ clauses.Assign(
+ types.template("None"), "%(domain)s"))
+
+ for clause in assignments:
+ clause.begin(stream)
+ clause.end(stream)
+
# output XML headers, if applicable
if not macro:
header = ""
@@ -742,54 +770,61 @@
if 'xmlns' in self.root.attrib:
del self.root.attrib['xmlns']
+ # symbols dictionary
+ __dict__ = stream.symbols.__dict__
+
# prepare args
- ignore = 'target_language',
- args = ', '.join((param for param in parameters if param not in ignore))
- if args:
- args += ', '
+ args = list(parameters)
# prepare kwargs
- kwargs = ', '.join("%s=None" % param for param in parameters)
- if kwargs:
- kwargs += ', '
+ defaults = ["%s = None" % param for param in parameters]
# prepare selectors
- extra = ''
for selector in stream.selectors:
- extra += '%s=None, ' % selector
+ args.append('%s = None' % selector)
+ defaults.append('%s = None' % selector)
+ args.append('%(language)s = None' % __dict__)
+
+ # prepare globals
+ _globals = ["from cPickle import loads as _loads"]
+ for symbol, value in stream.symbol_mapping.items():
+ _globals.append(
+ "%s = _loads(%s)" % (symbol, repr(dumps(value))))
+
# wrap generated Python-code in function definition
- mapping = dict(
- args=args, kwargs=kwargs, extra=extra, body=body)
- mapping.update(stream.symbols.__dict__)
- source = wrapper % mapping
+ if global_scope:
+ source = generation.function_wrap(
+ 'render', args, _globals, body,
+ "%(out)s.getvalue()" % stream.symbols.__dict__)
+ else:
+ source = generation.function_wrap(
+ 'render', defaults, _globals, body)
# serialize document
xmldoc = self.implicit_doctype + "\n" + self.root.tostring()
return ByteCodeTemplate(
- source, stream.symbol_mapping,
- xmldoc, self.parser, self.root)
+ source, xmldoc, self.parser, self.root)
class ByteCodeTemplate(object):
"""Template compiled to byte-code."""
func = None
- def __init__(self, source, symbols, xmldoc, parser, tree):
+ def __init__(self, source, xmldoc, parser, tree):
self.source = source
- self.symbols = symbols
self.xmldoc = xmldoc
self.parser = parser
self.tree = tree
def compile(self):
- suite = codegen.Suite(self.source, globals=self.symbols)
- suite._globals.update(self.symbols)
+ suite = codegen.Suite(self.source)
_locals = {}
exec suite.code in suite._globals, _locals
- self.func = _locals['render']
+ self.bind = _locals['bind']
+ self.func = self.bind()
def __reduce__(self):
reconstructor, (cls, base, state), kwargs = \
@@ -805,7 +840,7 @@
def render(self, *args, **kwargs):
kwargs.update(self.selectors)
- return self.func(generation, *args, **kwargs)
+ return self.func(*args, **kwargs)
@property
def selectors(self):
@@ -822,36 +857,34 @@
return selectors
class GhostedByteCodeTemplate(object):
- suite = codegen.Suite("def render(): pass")
+ suite = codegen.Suite("def bind(): pass")
def __init__(self, template):
- self.code = marshal.dumps(template.func.func_code)
- self.defaults = len(template.func.func_defaults or ())
- self.symbols = template.symbols
+ self.code = marshal.dumps(template.bind.func_code)
+ self.defaults = len(template.bind.func_defaults or ())
self.source = template.source
self.xmldoc = template.xmldoc
self.parser = template.parser
@classmethod
def rebuild(cls, state):
- symbols = state['symbols']
source = state['source']
xmldoc = state['xmldoc']
parser = state['parser']
tree, doctype = parser.parse(xmldoc)
_locals = {}
- _globals = symbols.copy()
- _globals.update(cls.suite._globals)
- exec cls.suite.code in _globals, _locals
+ exec cls.suite.code in cls.suite._globals, _locals
+
+ bind = _locals['bind']
+ bind.func_defaults = ((None,)*state['defaults']) or None
+ bind.func_code = marshal.loads(state['code'])
+
+ func = bind()
- func = _locals['render']
- func.func_defaults = ((None,)*state['defaults']) or None
- func.func_code = marshal.loads(state['code'])
-
return dict(
+ bind=bind,
func=func,
- symbols=symbols,
source=source,
xmldoc=xmldoc,
parser=parser,
More information about the Checkins
mailing list