# HG changeset patch # User Paul Boddie # Date 1309819014 -7200 # Node ID 13aae946513bcbc0e226329dffe3901d6c03b120 # Parent d88f693525282702d3e14cd442fc57650867204d Introduced Instance() in place of None as a result and for the value of the active expression where no definitive object can be deduced. Made all Instance values compare equal to each other in order to avoid duplication in sets. Improved Constant comparisons. Fixed assignment counting where many values are provided in a single assignment. Added inspection support for conditional expressions (since they are used in the standard library). diff -r d88f69352528 -r 13aae946513b micropython/data.py --- a/micropython/data.py Mon Jul 04 23:50:02 2011 +0200 +++ b/micropython/data.py Tue Jul 05 00:36:54 2011 +0200 @@ -236,6 +236,10 @@ assignments in the lifetime of a program). """ + if value is None: + print "Warning: name %r in namespace %r has an unknown value (evaluated to None)." % (name, self.full_name()) + value = Instance() + if name in self.globals: self.module.set(name, value, 0) else: @@ -928,11 +932,15 @@ many assignments may be involved. """ + if self.context_values.issuperset(context_values) and \ + not (Instance(), Instance()) in context_values: + return + if self.assignments is None: if single_assignment: - self.assignments = 1 + self.assignments = len(set(context_values)) else: - self.assignments = AtLeast(1) + self.assignments = AtLeast(len(set(context_values))) else: if single_assignment: self.assignments += 1 @@ -1079,6 +1087,15 @@ def __repr__(self): return "Instance()" + def __eq__(self, other): + return other.__class__ is Instance + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return 0 + __shortrepr__ = __repr__ class Constant: @@ -1111,7 +1128,11 @@ # Support constants as dictionary keys in order to build constant tables. def __eq__(self, other): - return other is not None and self.value == other.value and self.value.__class__ is other.value.__class__ + return other is not None and isinstance(other, Const) and \ + self.value == other.value and self.value.__class__ is other.value.__class__ + + def __ne__(self, other): + return not self.__eq__(other) def __hash__(self): return hash(self.value) diff -r d88f69352528 -r 13aae946513b micropython/inspect.py --- a/micropython/inspect.py Mon Jul 04 23:50:02 2011 +0200 +++ b/micropython/inspect.py Tue Jul 05 00:36:54 2011 +0200 @@ -171,7 +171,7 @@ if isinstance(n, compiler.ast.Global): for name in n.names: if not self.has_key(name): - self[name] = None + self[name] = Instance() else: self.process_globals(n) @@ -419,7 +419,6 @@ def NOP(self, node): for n in node.getChildNodes(): self.dispatch(n) - return None def NOP_ABANDON(self, node): self.NOP(node) @@ -469,21 +468,21 @@ if attrname == "__class__" and isinstance(value, Class): attr = type_class else: - attr = value.get(attrname) + attr = value.get(attrname) or Instance() self.use_specific_attribute(value.full_name(), attrname) elif isinstance(value, UnresolvedName): attr = UnresolvedName(attrname, value.full_name(), self) else: - attr = None + attr = Instance() # Note usage of the attribute where a local is involved. self._visitAttrUser(expr, attrname, node) else: - attr = None + attr = Instance() self.use_name(attrname, node) return attr @@ -613,7 +612,6 @@ for n in node.nodes: self.dispatch(n) self.in_assignment = 0 - return None def visitAssAttr(self, node): expr = self.dispatch(node.expr) @@ -642,8 +640,6 @@ else: self.use_name(attrname, node) - return None - def visitAssList(self, node): # Declare names which will be used by generated code. @@ -655,7 +651,6 @@ for i, n in enumerate(node.nodes): self.dispatch(n) self._visitConst(i) # for __getitem__(i) at run-time - return None def visitAssName(self, node): if hasattr(node, "flags") and node.flags == "OP_DELETE": @@ -677,8 +672,6 @@ ns = self.get_namespace().full_name() self.use_specific_attribute(fn.parent.full_name(), fn.name, "%s.%s" % (ns, node.name)) - return None - visitAssTuple = visitAssList def visitAugAssign(self, node): @@ -705,8 +698,6 @@ self.use_specific_attribute("__builtins__", "slice") self.use_name("__setitem__", node) - return None - visitBackquote = OP visitBitand = _visitBinary @@ -730,7 +721,7 @@ if self.namespaces: print "Warning: class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) - return None + return else: if self.in_loop: print "Warning: class %r in %r defined in a loop." % (node.name, self.full_name()) @@ -757,7 +748,7 @@ if isinstance(expr, Attr): if expr.assignments != 1: - raise InspectError("Base class %r for %r is not constant." % (base, cls.full_name())) + raise InspectError("Base class %r for %r is not constant: %r" % (base, cls.full_name(), expr)) else: cls.add_base(expr.get_value()) @@ -856,6 +847,11 @@ in_loop = self.in_loop self.in_loop = 1 self.dispatch(node.list) + + # NOTE: Could generate AST nodes for the actual operations instead of + # NOTE: manually generating code in micropython.ast. + + self.expr = Instance() # each element is a result of a function call self.dispatch(node.assign) # Enter the loop. @@ -886,8 +882,6 @@ self.resume_broken_branches() - return None - def visitFrom(self, node): module = self.importer.load(node.modname, 1) @@ -916,8 +910,6 @@ if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: self.importer.load(attr.get_value().name) - return None - def visitFunction(self, node): return self._visitFunction(node, node.name) @@ -963,9 +955,24 @@ self.shelve_branch() self.merge_branches() - return None + + def visitIfExp(self, node): + self.new_branchpoint() + + # Propagate attribute usage to branches. + + self.dispatch(node.test) - visitIfExp = NOP + self.new_branch(node.then) + self.dispatch(node.then) + self.shelve_branch() + + self.new_branch(node.else_) + self.dispatch(node.else_) + self.shelve_branch() + + self.merge_branches() + return Instance() # either outcome is possible def visitImport(self, node): for name, alias in node.names: @@ -976,15 +983,12 @@ module = self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self) self.store(name.split(".")[0], module) - return None - visitInvert = _visitUnary def visitKeyword(self, node): self.dispatch(node.expr) self._visitConst(node.name) self.keyword_names.add(node.name) - return None def visitLambda(self, node): fn = self._visitFunction(node, None) @@ -995,12 +999,13 @@ def visitList(self, node): self.use_specific_attribute("__builtins__", "list") - self.OP(node) + return self.OP(node) def visitListComp(self, node): for qual in node.quals: self.dispatch(qual) self.dispatch(node.expr) + return Instance() def visitListCompFor(self, node): self.new_branchpoint() @@ -1013,6 +1018,11 @@ in_loop = self.in_loop self.in_loop = 1 self.dispatch(node.list) + + # NOTE: Could generate AST nodes for the actual operations instead of + # NOTE: manually generating code in micropython.ast. + + self.expr = Instance() # each element is a result of a function call self.dispatch(node.assign) # Enter the loop. @@ -1027,7 +1037,6 @@ self.in_loop = in_loop self.merge_branches() - return None visitListCompIf = NOP @@ -1043,7 +1052,7 @@ visitMul = _visitBinary def visitName(self, node): - return self.get_namespace().get_using_node(node.name, node) + return self.get_namespace().get_using_node(node.name, node) or Instance() visitNot = OP @@ -1070,19 +1079,18 @@ visitRightShift = _visitBinary def visitSlice(self, node): - self._visitOperator(node, self.in_assignment and "AssSlice" or "Slice") + return self._visitOperator(node, self.in_assignment and "AssSlice" or "Slice") visitSliceobj = OP def visitStmt(self, node): for n in node.nodes: self.dispatch(n) - return None visitSub = _visitBinary def visitSubscript(self, node): - self._visitOperator(node, self.in_assignment and "AssSubscript" or "Subscript") + return self._visitOperator(node, self.in_assignment and "AssSubscript" or "Subscript") def visitTryExcept(self, node): self.dispatch(node.body) @@ -1107,7 +1115,6 @@ self.shelve_branch() self.merge_branches() - return None visitTryFinally = NOP @@ -1155,8 +1162,6 @@ self.resume_broken_branches() - return None - visitWith = NOP visitYield = NOP