# HG changeset patch # User Paul Boddie # Date 1385683427 -3600 # Node ID fa655857f2bae346e5b09e12e5331c80292c368a # Parent fa8e296dafdfa3fb0544240c04a9b58926ad52a6 Added support for dynamic function initialisation. diff -r fa8e296dafdf -r fa655857f2ba micropython/syspython.py --- a/micropython/syspython.py Fri Nov 29 01:03:05 2013 +0100 +++ b/micropython/syspython.py Fri Nov 29 01:03:47 2013 +0100 @@ -86,17 +86,65 @@ module = self.dispatch(self.module.astnode) stream.write(str(module)) - def get_original_arguments(self, argnames): + def store_value(self, unit, scope, name, value): + + """ + In the given 'unit' and for the given 'scope', store for the given + 'name' the given 'value'. + """ + + if scope == "local": + + # Function locals are stored using a function. + + if isinstance(unit, Function): + return compiler.ast.CallFunc( + special_name("storelocal"), + [special_name(name), value] + ) + + # Class locals are class attribute references. + + elif isinstance(unit, Class): + return compiler.ast.CallFunc( + special_name("storeattrcontext"), + [quoted_ref(unit), special_name(name), value] + ) + + # Module locals are module attribute references. - # NOTE: The special context argument should not be reproduced. - # NOTE: For "dynamic" functions, the context is used to access - # NOTE: things like defaults, but could be extended for closures to - # NOTE: refer to many namespaces. + elif isinstance(unit, Module): + return compiler.ast.CallFunc( + special_name("storeattr"), + [quoted_ref(unit), special_name(name), value] + ) + else: + raise TranslateError("Program unit has no local %r." % name) + + elif scope == "global": + + # Globals are references to module attributes. - if argnames and argnames[0] == "": - return argnames[1:] + return compiler.ast.CallFunc( + special_name("storeattr"), + [quoted_ref(self.get_module()), special_name(name), value] + ) + + elif scope == "builtin": + + # Builtins are accessed via the __builtins__ module. + + return compiler.ast.CallFunc( + special_name("storeattr"), + [special_name("__builtins__"), special_name(name), value] + ) + else: - return argnames + # NOTE: This may happen because a class attribute is optimised away. + return compiler.ast.CallFunc( + special_name("storeunknown"), + [special_name(name), value] + ) def NOP(self, node): return node @@ -342,22 +390,25 @@ self.units.append(node.unit) try: - # NOTE: Need to initialise any defaults outside a definition and to - # NOTE: transfer defaults to locals inside a definition. - if not self.processing_definition(node): - # Generate rebindings of functions. + # Generate rebindings of functions where multiple definitions + # exist within a scope. Also generate dynamic function object + # initialisation. fn = node.unit - if fn.name == fn.original_name: + if fn.name == fn.original_name and not fn.is_dynamic(): return compiler.ast.Stmt([]) else: - return compiler.ast.CallFunc( - special_name("storeattr"), - [quoted_ref(fn.parent), special_name(fn.original_name), - quoted_ref(fn)] - ) + if fn.is_dynamic(): + ref = compiler.ast.CallFunc( + special_name("makedynamic"), + [quoted_ref(fn)] + fn.defaults + ) + else: + ref = quoted_ref(fn) + + return self.store_value(fn.parent, "local", fn.original_name, ref) else: return self._visitFunctionDefinition(node) finally: @@ -383,15 +434,23 @@ ) ] or [] + # Process any local class or function definitions. + + current = self.current_definition + definitions = self.process_definitions(node) + self.current_definition = current + defaults = [self.dispatch(n) for n in node.defaults] + # NOTE: Any required defaults should be copied into the local namespace + # NOTE: using the __context__ reference to the instance of the function. + # NOTE: Should generate guards for attribute usage operations. code = self.dispatch(node.code) - argnames = self.get_original_arguments(node.argnames) - return compiler.ast.Function(node.decorators, node.name, argnames, defaults, node.flags, node.doc, - compiler.ast.Stmt(localnames + globalnames + code.nodes)) + return compiler.ast.Function(node.decorators, node.name, node.argnames, defaults, node.flags, node.doc, + compiler.ast.Stmt(localnames + globalnames + definitions + code.nodes)) visitGlobal = NOP @@ -693,58 +752,8 @@ if scope == "constant": return node - elif scope == "local": - - # Function locals are stored using a function. - - if isinstance(unit, Function): - return compiler.ast.CallFunc( - special_name("storelocal"), - [special_name(node.name), expr] - ) - - # Class locals are class attribute references. - - elif isinstance(unit, Class): - return compiler.ast.CallFunc( - special_name("storeattrcontext"), - [quoted_ref(unit), special_name(node.name), expr] - ) - - # Module locals are module attribute references. - - elif isinstance(unit, Module): - return compiler.ast.CallFunc( - special_name("storeattr"), - [quoted_ref(unit), special_name(node.name), expr] - ) - else: - raise TranslateError("Program unit has no local %r." % name) - - elif scope == "global": - - # Globals are references to module attributes. - - return compiler.ast.CallFunc( - special_name("storeattr"), - [quoted_ref(self.get_module()), special_name(node.name), expr] - ) - - elif scope == "builtin": - - # Builtins are accessed via the __builtins__ module. - - return compiler.ast.CallFunc( - special_name("storeattr"), - [special_name("__builtins__"), special_name(node.name), expr] - ) - else: - # NOTE: This may happen because a class attribute is optimised away. - return compiler.ast.CallFunc( - special_name("storeunknown"), - [special_name(node.name), expr] - ) + return self.store_value(unit, scope, node.name, expr) visitAssTuple = visitAssList @@ -906,13 +915,12 @@ def visitLambda(self, node): self.units.append(node.unit) - # NOTE: Need to initialise any defaults. + # NOTE: Need to initialise any defaults. Lambdas should probably be + # NOTE: expanded to be "real" function definitions. try: - argnames = self.get_original_arguments(node.argnames) - return compiler.ast.Lambda( - argnames, + node.argnames, [self.dispatch(n) for n in node.defaults], node.flags, self.dispatch(node.code)