# HG changeset patch # User Paul Boddie # Date 1372971202 -7200 # Node ID 5c759716f9f2a8bbefe4b4c0f21780f7e434a048 # Parent f437f041f6659e036bafc05a63d83af8151e6584 Introduced an explicit special function for invocations - "apply" - removing double underscores from special function names, since such functions can no longer be confused with program function names. Added missing support for the "is" and "is not" operators. diff -r f437f041f665 -r 5c759716f9f2 docs/syspython.txt --- a/docs/syspython.txt Thu Jul 04 22:41:32 2013 +0200 +++ b/docs/syspython.txt Thu Jul 04 22:53:22 2013 +0200 @@ -8,6 +8,21 @@ temporary storage administration and other code generation tasks are to be left to the systems programming language compiler. +Special Functions +----------------- + +In syspython, the function invocation notation is reserved to specify +primitive operations such as attribute access and actual function invocations, +with the latter being expressed as follows: + + fn(y) # original Python + apply(fn, y) # syspython + +Thus, in syspython, whenever the invocation notation is used, the target of +the invocation is always a special function and not a general Python function +or method. Note that the apply function resembles the Python function of the +same name but is not actually that particular function. + Program Data and Data Structure Definition ------------------------------------------ @@ -18,21 +33,21 @@ Explicit constant declaration shall be done at the start of the main module: - __constants__(...) + constants(...) Explicit structure declaration is still performed using class statements, but base classes are omitted and attributes are declared explicitly as follows: class C: - __instattrs__(member...) - __classattrs__(member...) + instattrs(member...) + classattrs(member...) Other object table information, such as inherited class attributes and class compatibility (to support isinstance) are also declared explicitly: - __inherited__(superclass, member...) - __descendants__(class...) + inherited(superclass, member...) + descendants(class...) Other than function definitions, no other code statements shall appear in class definitions; such statements will appear after classes have been @@ -69,10 +84,10 @@ ... def __main__(): - __globalnames__(...) + globalnames(...) ... if something: - __storeattr__(module.C, method, something) + storeattr(module.C, method, something) Imports ------- @@ -82,17 +97,17 @@ # import package package.__main__() - package = __static__(package) + storelocal(package, static(package)) # import package.module package.__main__() package.module.__main__() - package = __static__(package) + storelocal(package, static(package)) # from package.module import cls package.__main__() package.module.__main__() - cls = __loadattribute__(package.module, cls) # see below + storelocal(cls, loadattribute(package.module, cls)) # see below Since import statements can appear in code that may be executed more than once, __main__ functions should test and set a flag indicating whether the @@ -108,17 +123,15 @@ Assignments and name usage involve locals and globals but usage is declared explicitly: - __localnames__(...) + localnames(...) At the function level, locals are genuine local name definitions whereas globals refer to module globals: - __globalnames__(...) + globalnames(...) -At the module level, locals are effectively equivalent to module globals but -are declared as follows: - - __moduleattrs__(...) +At the module level, locals are effectively equivalent to module globals and +are declared as such. Each module's __main__ function will declare any referenced module globals as globals. Note that the __main__ function is not a genuine attribute of any @@ -128,33 +141,33 @@ For example: def f(a, b): - __localnames__(a, b, x, y) - __globalnames__(f, g) + localnames(a, b, x, y) + globalnames(f, g) - __storelocal__(x, 1) - __storelocal__(y, x) - __storelocal__(a, b) - __storeattr__(module, g, f) + storelocal(x, 1) + storelocal(y, x) + storelocal(a, b) + storeattr(module, g, f) Names and Attributes -------------------- -Bare names refer to locals or globals according to the __localnames__ and -__globalnames__ declarations, or to constants such as None, True, False and +Bare names refer to locals or globals according to the localnames and +globalnames declarations, or to constants such as None, True, False and NotImplemented. Storage of local or global names is done using explicit functions as follows: - __storelocal__(name, value) - __storeattr__(module, name, value) # see below + storelocal(name, value) + storeattr(module, name, value) # see below No operator usage: all operators are converted to invocations, including all attribute access except static references to modules or particular class or function definitions using the following notation: - __static__(package) - __static__(package.module) - __static__(package.module.cls) - __static__(package.module.cls.function) + static(package) + static(package.module) + static(package.module.cls) + static(package.module.cls.function) A shorthand dot notation could be employed: @@ -165,26 +178,27 @@ Where multiple definitions of static objects occur, the dot notation cannot be used, and the full name of such definitions must be quoted. For example: - __static__("package.module.cls#1.function") + static("package.module.cls#1.function") In general, attribute access must use an explicit function indicating the kind of access operation being performed. For example: - __loadattr__(obj, attrname) # preserve context - __loadattrcontext__(obj, attrname) # replace context with obj - __loadattrcontextcond__(obj, attrname) # run-time context decision - __loadattrindex__(obj, attrname) # preserve context - __loadattrindexcontext__(obj, attrname) # replace context with obj - __loadattrindexcontextcond__(obj, attrname) # run-time context decision + # context effect + # -------------- + loadattr(obj, attrname) # preserve context + loadattrcontext(parent, attrname, obj) # replace context with obj + loadattrcontextcond(parent, attrname, obj) # run-time context decision + loadattrindex(obj, attrname) # preserve context + loadattrindexcontextcond(obj, attrname) # run-time context decision - __storeattr__(obj, attrname, value) # preserve context - __storeattrcontext__(obj, attrname, value) # replace context - __storeattrindex__(obj, attrname, value) + storeattr(obj, attrname, value) # preserve context + storeattrcontext(parent, attrname, value, obj) # replace context with obj + storeattrindex(obj, attrname, value) Temporary variables could employ similar functions: - __loadtemp__(0) - __storetemp__(0, value) + loadtemp(0) + storetemp(0, value) Operators and Invocations ------------------------- @@ -195,6 +209,7 @@ but might as well be supported directly: __is__(a, b) + __is_not__(a, b) Logical operators involving short-circuit evaluation could be represented as function calls, but the evaluation semantics would be preserved: @@ -218,20 +233,20 @@ Special functions for low-level operations: - __check__(obj, type) - __jump__(callable) + check(obj, type) + jump(callable) Function/subroutine definition with entry points for checked and unchecked parameters. def fn_checked(self, ...): - __check__(self, Type) # raises a TypeError if not isinstance(self, Type) - __jump__(fn_unchecked) # preserves the frame and return address + check(self, Type) # raises a TypeError if not isinstance(self, Type) + jump(fn_unchecked) # preserves the frame and return address def fn_unchecked(self, ...): ... -The __jump__ function might also be used for inlining appropriate functions. +The jump function might also be used for inlining appropriate functions. Exceptions must also be handled in the language. @@ -241,4 +256,4 @@ Occasionally, the type of an object (instance of a particular class, class, and so on) needs to be determined at run-time: - __isclass__(obj) + isclass(obj) diff -r f437f041f665 -r 5c759716f9f2 micropython/syspython.py --- a/micropython/syspython.py Thu Jul 04 22:41:32 2013 +0200 +++ b/micropython/syspython.py Thu Jul 04 22:53:22 2013 +0200 @@ -41,19 +41,19 @@ return compiler.ast.Const(s) def quoted_ref(obj): - return compiler.ast.CallFunc("__static__", [quoted_name(obj.full_name())]) + return compiler.ast.CallFunc("static", [quoted_name(obj.full_name())]) def module_attribute(module_name, attrname): - return compiler.ast.Getattr(special_name(module_name), attrname) + return special_name(module_name + "." + attrname) # Special function names. # Some of the assignment operations cannot be supported unless attribute usage # observations are being made. -assattr_functions = ("__storeattrcontext__", "__storeattrcontext__", "__storeattr__", - "__storeattrindex__", None) -getattr_functions = ("__loadattrcontext__", "__loadattrcontextcond__", "__loadattr__", - "__loadattrindex__", "__loadattrindexcontextcond__") +assattr_functions = ("storeattrcontext", "storeattrcontext", "storeattr", + "storeattrindex", None) +getattr_functions = ("loadattrcontext", "loadattrcontextcond", "loadattr", + "loadattrindex", "loadattrindexcontextcond") # Source code classes. @@ -91,11 +91,11 @@ definitions = self.process_definitions(node) - # __globalnames__(name, ...) + # globalnames(name, ...) globalnames = module.module_attribute_names() and [ compiler.ast.CallFunc( - special_name("__globalnames__"), + special_name("globalnames"), [special_name(attr.name) for attr in module.attributes_as_list()] ) ] or [] @@ -127,7 +127,7 @@ def visitAugAssign(self, node): # lvalue = op(lvalue, expr) - # -> __fn__(lvalue, op(lvalue, expr)) + # -> fn(lvalue, op(lvalue, expr)) op_name = operator_functions[node.op] @@ -157,24 +157,24 @@ def _visitClassDefinition(self, node): cls = node.unit - # __instattrs__(name, ...) - # __clsattrs__(name, ...) + # instattrs(name, ...) + # clsattrs(name, ...) instattrs = cls.instance_attribute_names() and [ compiler.ast.CallFunc( - special_name("__instattrs__"), + special_name("instattrs"), [special_name(attr.name) for attr in cls.instance_attributes_as_list()] ) ] or [] clsattrs = cls.class_attribute_names() and [ compiler.ast.CallFunc( - special_name("__clsattrs__"), + special_name("clsattrs"), [special_name(attr.name) for attr in cls.attributes_as_list()] ) ] or [] - # __inherited__(superclass, name, ...) + # inherited(superclass, name, ...) # ... attrs_by_cls = {} @@ -191,15 +191,15 @@ for supercls, attrnames in attrs_by_cls.items(): inherited.append( compiler.ast.CallFunc( - special_name("__inherited__"), + special_name("inherited"), [quoted_ref(supercls)] + [special_name(name) for name in attrnames] )) - # __descendants__(name, ...) + # descendants(name, ...) descendants = cls.all_descendants() and [ compiler.ast.CallFunc( - special_name("__descendants__"), + special_name("descendants"), [special_name(name) for name in cls.all_descendants().keys()] ) ] or [] @@ -247,8 +247,8 @@ else_nodes = node.else_ and self.dispatch(node.else_).nodes or [] return compiler.ast.Stmt([ - # __storetemp__(_it, __builtins__.iter()) - compiler.ast.CallFunc(special_name("__storetemp__"), [ + # storetemp(_it, __builtins__.iter()) + compiler.ast.CallFunc(special_name("storetemp"), [ temp, compiler.ast.CallFunc( module_attribute("__builtins__", "iter"), @@ -265,8 +265,8 @@ self.dispatch(node.assign, # _it.next() compiler.ast.CallFunc( - compiler.ast.CallFunc(special_name("__loadattrindex__"), [ - compiler.ast.CallFunc(special_name("__loadtemp__"), [temp]), + compiler.ast.CallFunc(special_name("loadattrindex"), [ + compiler.ast.CallFunc(special_name("loadtemp"), [temp]), special_name("next") ]), [] @@ -296,13 +296,14 @@ for name, alias in node.names: statements.append( - compiler.ast.Assign( - [special_name(alias or name)], + compiler.ast.CallFunc( + special_name("storelocal"), + [special_name(alias or name), compiler.ast.CallFunc( - special_name("__loadattr__"), + special_name("loadattr"), [special_name(node.modname), special_name(name)] ) - ) + ]) ) return compiler.ast.Stmt(statements) @@ -323,7 +324,7 @@ return compiler.ast.Stmt([]) else: return compiler.ast.CallFunc( - special_name("__storeattr__"), + special_name("storeattr"), [quoted_ref(fn.parent), special_name(fn.original_name), quoted_ref(fn)] ) @@ -335,19 +336,19 @@ def _visitFunctionDefinition(self, node): fn = node.unit - # __localnames__(name, ...) - # __globalnames__(name, ...) + # localnames(name, ...) + # globalnames(name, ...) localnames = fn.all_locals() and [ compiler.ast.CallFunc( - special_name("__localnames__"), + special_name("localnames"), [special_name(name) for name in fn.all_locals().keys()] ) ] or [] globalnames = fn.globals and [ compiler.ast.CallFunc( - special_name("__globalnames__"), + special_name("globalnames"), [special_name(name) for name in fn.globals] ) ] or [] @@ -383,13 +384,14 @@ ) statements.append( - compiler.ast.Assign( - [special_name(alias or name.split(".")[0])], + compiler.ast.CallFunc( + special_name("storelocal"), + [special_name(alias or name.split(".")[0]), compiler.ast.CallFunc( - special_name("__static__"), + special_name("static"), [special_name(name)] ) - ) + ]) ) return compiler.ast.Stmt(statements) @@ -535,6 +537,11 @@ if expr: args.append(expr) + # Append any context to be set. + + if node._set_context and args[0] is not accessor: + args.append(accessor) + return compiler.ast.CallFunc(special_name(op), args) # Positioned accesses are normal accesses via instances. @@ -556,19 +563,19 @@ if node.attrname == "__class__": - # __storetemp__(n, ) - # __isclass__(n) and __builtins__.type or + # storetemp(n, ) + # isclass(n) and __builtins__.type or temp = quoted_name(unit.temp_usage) unit.temp_usage += 1 return compiler.ast.Stmt([ - compiler.ast.CallFunc(special_name("__storetemp__"), [temp, access]), + compiler.ast.CallFunc(special_name("storetemp"), [temp, access]), compiler.ast.Or([ compiler.ast.And([ compiler.ast.CallFunc( - special_name("__isclass__"), - [compiler.ast.CallFunc(special_name("__loadtemp__"), [temp])] + special_name("isclass"), + [compiler.ast.CallFunc(special_name("loadtemp"), [temp])] ), module_attribute("__builtins__", "type") ]), @@ -637,7 +644,7 @@ if isinstance(unit, Function): return compiler.ast.CallFunc( - special_name("__storelocal__"), + special_name("storelocal"), [special_name(node.name), expr] ) @@ -645,7 +652,7 @@ elif isinstance(unit, Class): return compiler.ast.CallFunc( - special_name("__storeattrcontext__"), + special_name("storeattrcontext"), [quoted_ref(unit), special_name(node.name), expr] ) @@ -653,7 +660,7 @@ elif isinstance(unit, Module): return compiler.ast.CallFunc( - special_name("__storeattr__"), + special_name("storeattr"), [quoted_ref(unit), special_name(node.name), expr] ) else: @@ -664,7 +671,7 @@ # Globals are references to module attributes. return compiler.ast.CallFunc( - special_name("__storeattr__"), + special_name("storeattr"), [quoted_ref(self.get_module()), special_name(node.name), expr] ) @@ -673,14 +680,14 @@ # Builtins are accessed via the __builtins__ module. return compiler.ast.CallFunc( - special_name("__storeattr__"), + 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("storeunknown"), [special_name(node.name), expr] ) @@ -697,8 +704,8 @@ def visitCallFunc(self, node): return compiler.ast.CallFunc( - self.dispatch(node.node), - [self.dispatch(arg) for arg in node.args], + special_name("apply"), + [self.dispatch(node.node)] + [self.dispatch(arg) for arg in node.args], node.star_args and self.dispatch(node.star_args), node.dstar_args and self.dispatch(node.dstar_args) ) @@ -707,12 +714,27 @@ nodes = [] left = node.expr for op_name, right in node.ops: - nodes.append( - compiler.ast.CallFunc( - module_attribute("operator", operator_functions.get(op_name)), - [self.dispatch(left), self.dispatch(right)] + if op_name == "is": + nodes.append( + compiler.ast.CallFunc( + special_name("__is__"), + [self.dispatch(left), self.dispatch(right)] + ) ) - ) + elif op_name == "is not": + nodes.append( + compiler.ast.CallFunc( + special_name("__is_not__"), + [self.dispatch(left), self.dispatch(right)] + ) + ) + else: + nodes.append( + compiler.ast.CallFunc( + module_attribute("operator", operator_functions.get(op_name)), + [self.dispatch(left), self.dispatch(right)] + ) + ) left = right return compiler.ast.And(nodes) @@ -805,8 +827,8 @@ unit.temp_usage += 1 return compiler.ast.Stmt([ - # __storetemp__(_out, __builtins__.list()) - compiler.ast.CallFunc(special_name("__storetemp__"), [ + # storetemp(_out, __builtins__.list()) + compiler.ast.CallFunc(special_name("storetemp"), [ temp, compiler.ast.CallFunc( module_attribute("__builtins__", "list"), @@ -855,8 +877,8 @@ # Wrap the above body in the loop construct. return compiler.ast.Stmt([ - # __storetemp__(_it, __builtins__.iter()) - compiler.ast.CallFunc(special_name("__storetemp__"), [ + # storetemp(_it, __builtins__.iter()) + compiler.ast.CallFunc(special_name("storetemp"), [ temp, compiler.ast.CallFunc( module_attribute("__builtins__", "iter"), @@ -873,8 +895,8 @@ self.dispatch(node.assign, # _it.next() compiler.ast.CallFunc( - compiler.ast.CallFunc(special_name("__loadattrindex__"), [ - compiler.ast.CallFunc(special_name("__loadtemp__"), [temp]), + compiler.ast.CallFunc(special_name("loadattrindex"), [ + compiler.ast.CallFunc(special_name("loadtemp"), [temp]), special_name("next") ]), [] @@ -914,8 +936,8 @@ return compiler.ast.Stmt([ # _out.append() compiler.ast.CallFunc( - compiler.ast.CallFunc(special_name("__loadattrindex__"), [ - compiler.ast.CallFunc(special_name("__loadtemp__"), [out_temp]), + compiler.ast.CallFunc(special_name("loadattrindex"), [ + compiler.ast.CallFunc(special_name("loadtemp"), [out_temp]), special_name("append") ]), [self.dispatch(expr)] @@ -953,7 +975,7 @@ return constant_attribute(quoted_ref(attr.parent), node.name) else: return compiler.ast.CallFunc( - special_name("__loadattr__"), + special_name("loadattr"), [quoted_ref(attr.parent), special_name(node.name)] ) @@ -961,7 +983,7 @@ elif scope == "global": return compiler.ast.CallFunc( - special_name("__loadattr__"), + special_name("loadattr"), [quoted_ref(self.get_module()), special_name(node.name)] ) @@ -970,7 +992,7 @@ else: return compiler.ast.CallFunc( - special_name("__loadunknown__"), + special_name("loadunknown"), [special_name(node.name)] )