# HG changeset patch # User Paul Boddie # Date 1276388675 -7200 # Node ID c7c2119483cf3ce47eb80ecc8ddd0eea5370c663 # Parent 334af78f7931b7fcd05d714d00f44999d7e43325 Fixed exception attribute initialisation for translation errors. Reintroduced the _scope attribute on AST nodes in order to support supposedly harmless changes in scope (such as the "importing" of a built-in or global into a local scope where the name is redefined subsequently). Reorganised the tests according to the above shadowing policy change. Introduced tentative slicing support plus built-in functions that rely on slicing. diff -r 334af78f7931 -r c7c2119483cf TO_DO.txt --- a/TO_DO.txt Sat Jun 12 23:09:30 2010 +0200 +++ b/TO_DO.txt Sun Jun 13 02:24:35 2010 +0200 @@ -1,12 +1,27 @@ +Check name origin where multiple branches could yield multiple scope interpretations: + +---- +try: + set # built-in name +except NameError: + from sets import Set as set # local definition of name + +set # could be confused by the local definition at run-time +---- + Support __init__ traversal (and other implicit names) more effectively. Check context_value initialisation (avoiding or handling None effectively). +__getitem__ could be written in Python, using a native method only to access fragments. +Support slicing. +Consider better "macro" support where new expressions need to be generated and processed. + +**** Constant attribute users need not maintain usage since they are already resolved. **** + Loop entry points should capture usage to update later assignments in the loop. The continue and break statements should affect usage propagation. -Constant attribute users need not maintain usage since they are already resolved. - Consider handling CallFunc in micropython.inspect in order to produce instances of specific classes. Then, consider adding support for guard removal/verification where known instances are involved. Consider handling branches of values within namespaces in order to support more precise value usage. diff -r 334af78f7931 -r c7c2119483cf lib/builtins.py --- a/lib/builtins.py Sat Jun 12 23:09:30 2010 +0200 +++ b/lib/builtins.py Sun Jun 13 02:24:35 2010 +0200 @@ -233,8 +233,7 @@ class set(object): def __init__(self, iterable): pass -class slice(object): - def __init__(self, start_or_end, end=None, step=None): pass +# See below for slice. class str(basestring): pass @@ -277,6 +276,7 @@ self.step = step self.current = self.start + self.limited = self.end is not None def __iter__(self): @@ -288,13 +288,24 @@ "Return the next item or raise a StopIteration exception." - if self.step < 0 and self.current <= self.end or self.step > 0 and self.current >= self.end: - raise StopIteration() + if self.limited: + if self.step < 0 and self.current <= self.end or self.step > 0 and self.current >= self.end: + raise StopIteration() current = self.current self.current += self.step return current +class slice(xrange): + + "Implementation of slice." + + def __init__(self, start_or_end=None, end=None, step=1): + + "Initialise the slice with the given 'start_or_end', 'end' and 'step'." + + xrange.__init__(self, start_or_end, end, step) + # Exceptions and warnings. class BaseException(object): @@ -402,9 +413,29 @@ return obj.__len__() def locals(): pass + def map(function, *args): pass -def max(*args): pass -def min(*args): pass + +def max(*args): + + "Implementation of max." + + highest = args[0] + for arg in args[1:]: + if arg > highest: + highest = arg + return highest + +def min(*args): + + "Implementation of min." + + lowest = args[0] + for arg in args[1:]: + if arg > lowest: + lowest = arg + return lowest + def oct(number): pass def open(name, mode=None, buffering=None): pass def ord(c): pass diff -r 334af78f7931 -r c7c2119483cf micropython/ast.py --- a/micropython/ast.py Sat Jun 12 23:09:30 2010 +0200 +++ b/micropython/ast.py Sun Jun 13 02:24:35 2010 +0200 @@ -429,7 +429,25 @@ else: self._visitName(node, self.name_load_instructions) - def visitSlice(self, node): raise TranslationNotImplementedError("Slice") + def visitSlice(self, node): + if node.lower is None: + if node.upper is None: + args = [] + else: + args = [compiler.ast.Name("None"), node.upper] + else: + args = [node.lower] + + # NOTE: Need to guarantee reliable access to the slice built-in. + + slice = compiler.ast.CallFunc(compiler.ast.Name("slice"), args) + + self.dispatch(node.expr) + self._startCallFunc() + self._generateAttr(node, "__getitem__", self.attribute_load_instructions) + temp_target, target, temp_context = self._generateCallFunc([slice], node) + self._doCallFunc(temp_target, target) + self._endCallFunc(temp_target, target, temp_context) def visitSubscript(self, node): self.dispatch(node.expr) diff -r 334af78f7931 -r c7c2119483cf micropython/common.py --- a/micropython/common.py Sat Jun 12 23:09:30 2010 +0200 +++ b/micropython/common.py Sun Jun 13 02:24:35 2010 +0200 @@ -38,7 +38,13 @@ except NodeProcessingError, exc: if exc.astnode is None: exc.astnode = node - exc.unit_name = self.full_name() + + # NOTE: Should perhaps specialise the subclasses appropriately. + + if hasattr(self, "unit"): + exc.unit_name = self.unit.full_name() + else: + exc.unit_name = self.full_name() raise # Errors. diff -r 334af78f7931 -r c7c2119483cf micropython/inspect.py --- a/micropython/inspect.py Sat Jun 12 23:09:30 2010 +0200 +++ b/micropython/inspect.py Sun Jun 13 02:24:35 2010 +0200 @@ -273,7 +273,7 @@ # Store in the module. if not self.namespaces: - if self.used_in_scope(name, "builtins"): + if self.in_loop and self.used_in_scope(name, "builtins"): raise InspectError("Name %r already used as a built-in." % name) else: self.set(name, obj, not self.in_loop) @@ -283,9 +283,9 @@ else: locals = self.namespaces[-1] - if locals.used_in_scope(name, "global") and not name in locals.globals: + if self.in_loop and locals.used_in_scope(name, "global") and not name in locals.globals: raise InspectError("Name %r already used as global." % name) - elif locals.used_in_scope(name, "builtins"): + elif self.in_loop and locals.used_in_scope(name, "builtins"): raise InspectError("Name %r already used as a built-in." % name) else: locals.set(name, obj, not self.in_loop) @@ -939,6 +939,7 @@ if self.importer.predefined_constants.has_key(name): attr = self.importer.get_predefined_constant(name) + node._scope = "constant" # Locals. @@ -948,6 +949,7 @@ # Note usage of the local (potentially a class attribute). self.use_specific_attribute(None, name) + node._scope = "local" # Globals. @@ -957,27 +959,26 @@ # Note usage of the module attribute. self.use_specific_attribute(self.full_name(), name) + node._scope = "global" # Note global usage in any local namespace. if self.namespaces: - if not self.namespaces[-1].note_scope(name, "global"): - raise InspectError("Name %r cannot be used as global." % name) + self.namespaces[-1].note_scope(name, "global") # Builtins. elif self.builtins is not None and self.builtins.has_key(name): attr = self.builtins[name] self.use_specific_attribute(self.builtins.full_name(), name) + node._scope = "builtins" # Note builtins usage in any local namespace. if self.namespaces: - if not self.namespaces[-1].note_scope(name, "builtins"): - raise InspectError("Name %r cannot be used as a built-in." % name) + self.namespaces[-1].note_scope(name, "builtins") else: - if not self.note_scope(name, "builtins"): - raise InspectError("Name %r cannot be used as a built-in." % name) + self.note_scope(name, "builtins") # Unknown. @@ -1005,7 +1006,10 @@ visitRightShift = _visitBinary - visitSlice = OP + def visitSlice(self, node): + self.use_name("slice", node) + self.use_name("__getitem__", node) + self.OP(node) visitSliceobj = OP diff -r 334af78f7931 -r c7c2119483cf micropython/trans.py --- a/micropython/trans.py Sat Jun 12 23:09:30 2010 +0200 +++ b/micropython/trans.py Sun Jun 13 02:24:35 2010 +0200 @@ -1160,7 +1160,7 @@ # Get the expected scope of the name. - scope = self.get_scope(name) + scope = getattr(node, "_scope", None) or self.get_scope(name) #print self.module.name, node.lineno, name, predicted_scope self._generateName(name, scope, classes, node) diff -r 334af78f7931 -r c7c2119483cf tests/failure/shadow_class_global.py --- a/tests/failure/shadow_class_global.py Sat Jun 12 23:09:30 2010 +0200 +++ b/tests/failure/shadow_class_global.py Sun Jun 13 02:24:35 2010 +0200 @@ -4,7 +4,8 @@ return x class C: - e = e + for x in range(0, 10): + e = e # right hand side name changes origin c = C() diff -r 334af78f7931 -r c7c2119483cf tests/failure/shadow_class_global_reassign.py --- a/tests/failure/shadow_class_global_reassign.py Sat Jun 12 23:09:30 2010 +0200 +++ b/tests/failure/shadow_class_global_reassign.py Sun Jun 13 02:24:35 2010 +0200 @@ -4,12 +4,17 @@ return x class C: - e = f + i = 2 + + while i > 0: + e = f # right hand side name changes origin - def f(self, x): - return x + def f(self, x): + return 3 + + i -= 1 c = C() -c.f(1) +result_3 = c.f(1) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 334af78f7931 -r c7c2119483cf tests/failure/shadow_globals_builtins.py --- a/tests/failure/shadow_globals_builtins.py Sat Jun 12 23:09:30 2010 +0200 +++ b/tests/failure/shadow_globals_builtins.py Sun Jun 13 02:24:35 2010 +0200 @@ -1,10 +1,14 @@ #!/usr/bin/env python -c = max(4, 5) +i = 2 +while i > 0: + c = len([3, 4, 5]) # right hand side name changes origin -def max(a, b): - return a + def len(a): + return a -result_2 = max(2, 3) + i -= 1 + +result_2 = len(2) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 334af78f7931 -r c7c2119483cf tests/failure/shadow_locals_globals.py --- a/tests/failure/shadow_locals_globals.py Sat Jun 12 23:09:30 2010 +0200 +++ b/tests/failure/shadow_locals_globals.py Sun Jun 13 02:24:35 2010 +0200 @@ -3,8 +3,11 @@ a = 1 def before(): - b = a - a = 2 + i = 2 + while i > 0: + b = a # right hand side name changes origin + a = 2 + i -= 1 return b result1_1 = before() diff -r 334af78f7931 -r c7c2119483cf tests/failure/shadow_locals_globals_reassign.py --- a/tests/failure/shadow_locals_globals_reassign.py Sat Jun 12 23:09:30 2010 +0200 +++ b/tests/failure/shadow_locals_globals_reassign.py Sun Jun 13 02:24:35 2010 +0200 @@ -2,16 +2,13 @@ a = 1 -def before(): - b = a - a = 2 - return b - def reassign(): - a = a + i = 2 + while i > 0: + a = a # right hand side name changes origin + i -= 1 return a -result1_1 = before() result2_1 = reassign() # vim: tabstop=4 expandtab shiftwidth=4 diff -r 334af78f7931 -r c7c2119483cf tests/shadow_class_global_reassign.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/shadow_class_global_reassign.py Sun Jun 13 02:24:35 2010 +0200 @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +def f(self, x): + return x + +class C: + e = f + + def f(self, x): + return 3 + +c = C() +result_3 = c.f(1) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 334af78f7931 -r c7c2119483cf tests/shadow_globals_builtins.py --- a/tests/shadow_globals_builtins.py Sat Jun 12 23:09:30 2010 +0200 +++ b/tests/shadow_globals_builtins.py Sun Jun 13 02:24:35 2010 +0200 @@ -1,8 +1,10 @@ #!/usr/bin/env python -def max(a, b): +c = len([3, 4, 5]) + +def len(a): return a -result_2 = max(2, 3) +result_2 = len(2) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 334af78f7931 -r c7c2119483cf tests/shadow_locals_globals_reassign.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/shadow_locals_globals_reassign.py Sun Jun 13 02:24:35 2010 +0200 @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +a = 1 + +def before(): + b = a + a = 2 + return b + +def reassign(): + a = a + return a + +result1_1 = before() +result2_1 = reassign() + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 334af78f7931 -r c7c2119483cf tests/shadow_locals_globals_unbound_local.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/shadow_locals_globals_unbound_local.py Sun Jun 13 02:24:35 2010 +0200 @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +a = 1 + +def before(): + b = a + a = 2 + return b + +result1_1 = before() + +# vim: tabstop=4 expandtab shiftwidth=4