1.1 --- a/micropython/ast.py Sun May 11 18:43:58 2008 +0200
1.2 +++ b/micropython/ast.py Sun May 11 21:50:30 2008 +0200
1.3 @@ -699,6 +699,65 @@
1.4 def dispatch(self, node, *args):
1.5 return ASTVisitor.dispatch(self, node, *args)
1.6
1.7 + def _visitUnary(self, node, method):
1.8 +
1.9 + """
1.10 + _t = node.expr
1.11 + try:
1.12 + _result = _t.__pos__()
1.13 + except AttributeError:
1.14 + raise TypeError
1.15 + """
1.16 +
1.17 + end_call_label = self.new_label()
1.18 + end_label = self.new_label()
1.19 +
1.20 + # Evaluate and store the operand in temporary storage.
1.21 +
1.22 + self.dispatch(node.expr)
1.23 + temp = self._optimise_temp_storage()
1.24 +
1.25 + # Produce the invocation.
1.26 +
1.27 + self._startCallFunc()
1.28 + self.new_ops(temp)
1.29 +
1.30 + # Get the method on temp.
1.31 +
1.32 + self._generateAttr(node, method, (LoadAddress, LoadAttr, LoadAttrIndex))
1.33 +
1.34 + # Add exception handling to the method acquisition instructions where
1.35 + # the attribute access cannot be resolved at compile-time.
1.36 +
1.37 + if not self._optimise_known_target():
1.38 + self.dispatch(compiler.ast.Name("AttributeError"))
1.39 + self.new_op(CheckException())
1.40 + self.new_op(JumpIfTrue(end_call_label))
1.41 +
1.42 + temp_method = self._optimise_temp_storage()
1.43 +
1.44 + # Add arguments.
1.45 +
1.46 + self.new_ops(temp) # Explicit context as first argument.
1.47 + self._endCallFunc(temp_method)
1.48 + self.new_op(Jump(end_label))
1.49 +
1.50 + # End method attempt.
1.51 +
1.52 + self.set_label(end_call_label)
1.53 + self.new_op(DropFrame()) # From the method call.
1.54 +
1.55 + # Raise a TypeError.
1.56 +
1.57 + self.dispatch(compiler.ast.Name("TypeError"))
1.58 + self.new_op(RaiseException())
1.59 +
1.60 + self.set_label(end_label)
1.61 +
1.62 + # Compilation duties...
1.63 +
1.64 + self.discard_temp(temp)
1.65 +
1.66 def _visitBinary(self, node, left_method, right_method):
1.67
1.68 """
1.69 @@ -719,6 +778,7 @@
1.70
1.71 end_left_label = self.new_label()
1.72 right_label = self.new_label()
1.73 + end_right_label = self.new_label()
1.74 type_error_label = self.new_label()
1.75 end_label = self.new_label()
1.76
1.77 @@ -787,7 +847,7 @@
1.78 if not self._optimise_known_target():
1.79 self.dispatch(compiler.ast.Name("AttributeError"))
1.80 self.new_op(CheckException())
1.81 - self.new_op(JumpIfTrue(type_error_label))
1.82 + self.new_op(JumpIfTrue(end_right_label))
1.83
1.84 temp_method = self._optimise_temp_storage()
1.85
1.86 @@ -806,6 +866,11 @@
1.87 self.new_op(JumpIfTrue(type_error_label))
1.88 self.new_op(Jump(end_label))
1.89
1.90 + # End right method attempt.
1.91 +
1.92 + self.set_label(end_right_label)
1.93 + self.new_op(DropFrame()) # From the right method call.
1.94 +
1.95 # Raise a TypeError.
1.96
1.97 self.set_label(type_error_label)
1.98 @@ -845,11 +910,14 @@
1.99
1.100 def visitBackquote(self, node): pass
1.101
1.102 - def visitBitand(self, node): pass
1.103 + def visitBitand(self, node):
1.104 + self._visitBinary(node, "__and__", "__rand__")
1.105
1.106 - def visitBitor(self, node): pass
1.107 + def visitBitor(self, node):
1.108 + self._visitBinary(node, "__or__", "__ror__")
1.109
1.110 - def visitBitxor(self, node): pass
1.111 + def visitBitxor(self, node):
1.112 + self._visitBinary(node, "__xor__", "__rxor__")
1.113
1.114 def visitBreak(self, node):
1.115 next_label, exit_label = self.get_loop_labels()
1.116 @@ -1035,13 +1103,15 @@
1.117
1.118 def visitImport(self, node): pass
1.119
1.120 - def visitInvert(self, node): pass
1.121 + def visitInvert(self, node):
1.122 + self._visitUnary(node, "__invert__")
1.123
1.124 def visitKeyword(self, node): pass
1.125
1.126 def visitLambda(self, node): pass
1.127
1.128 - def visitLeftShift(self, node): pass
1.129 + def visitLeftShift(self, node):
1.130 + self._visitBinary(node, "__lshift__", "__rlshift__")
1.131
1.132 def visitList(self, node): pass
1.133
1.134 @@ -1073,7 +1143,8 @@
1.135
1.136 def visitPass(self, node): pass
1.137
1.138 - def visitPower(self, node): pass
1.139 + def visitPower(self, node):
1.140 + self._visitBinary(node, "__pow__", "__rpow__")
1.141
1.142 def visitPrint(self, node): pass
1.143
1.144 @@ -1088,7 +1159,8 @@
1.145 self.dispatch(compiler.ast.Name("None"))
1.146 self.new_op(Return())
1.147
1.148 - def visitRightShift(self, node): pass
1.149 + def visitRightShift(self, node):
1.150 + self._visitBinary(node, "__rshift__", "__rrshift__")
1.151
1.152 def visitSlice(self, node): pass
1.153
1.154 @@ -1102,13 +1174,6 @@
1.155 def visitSubscript(self, node): pass
1.156
1.157 def visitTryExcept(self, node):
1.158 -
1.159 - """
1.160 - Enter try block.
1.161 - Dispatch to code.
1.162 -
1.163 - """
1.164 -
1.165 exit_label = self.new_label()
1.166 handler_label = self.new_label()
1.167
1.168 @@ -1164,9 +1229,11 @@
1.169
1.170 def visitTuple(self, node): pass
1.171
1.172 - def visitUnaryAdd(self, node): pass
1.173 + def visitUnaryAdd(self, node):
1.174 + self._visitUnary(node, "__pos__")
1.175
1.176 - def visitUnarySub(self, node): pass
1.177 + def visitUnarySub(self, node):
1.178 + self._visitUnary(node, "__neg__")
1.179
1.180 def visitWhile(self, node):
1.181 exit_label = self.new_label()
2.1 --- a/micropython/data.py Sun May 11 18:43:58 2008 +0200
2.2 +++ b/micropython/data.py Sun May 11 21:50:30 2008 +0200
2.3 @@ -25,7 +25,6 @@
2.4 * Class
2.5 * Function
2.6 * Module
2.7 - * InspectedModule (derived from Module)
2.8
2.9 All of the above support the Naming interface either explicitly or through
2.10 general conformance, meaning that all can be asked to provide their 'full_name'
2.11 @@ -151,7 +150,11 @@
2.12 for i, attr in enumerate(self.values()):
2.13 attr.position = i
2.14
2.15 -# Program data structures.
2.16 +# Program data structures. There are two separate kinds of structures: those
2.17 +# with context, which are the values manipulated by programs, and those without
2.18 +# context, which are typically constant things which are stored alongside the
2.19 +# program but which are wrapped in context-dependent structures in the running
2.20 +# program.
2.21
2.22 class Attr:
2.23
2.24 @@ -194,7 +197,13 @@
2.25 def __repr__(self):
2.26 return "Attr(%r, %r, %r, %r, %r)" % (self.position, self.parent, self.name, self.value, self.assignments)
2.27
2.28 -class Const:
2.29 +class Constant:
2.30 +
2.31 + "A superclass for all constant or context-free structures."
2.32 +
2.33 + pass
2.34 +
2.35 +class Const(Constant):
2.36
2.37 "A constant object with no context."
2.38
2.39 @@ -222,7 +231,7 @@
2.40 def value_type_name(self):
2.41 return "__builtins__." + self.value.__class__.__name__
2.42
2.43 -class Class(NamespaceDict, Naming):
2.44 +class Class(NamespaceDict, Naming, Constant):
2.45
2.46 "An inspected class."
2.47
2.48 @@ -521,7 +530,7 @@
2.49 self.allattr[name] = attr
2.50 return self.allattr
2.51
2.52 -class Function(NamespaceDict, Naming):
2.53 +class Function(NamespaceDict, Naming, Constant):
2.54
2.55 "An inspected function."
2.56
2.57 @@ -689,7 +698,7 @@
2.58 function.default_attrs = self.default_attrs
2.59 return function
2.60
2.61 -class UnresolvedName(NamespaceDict):
2.62 +class UnresolvedName(NamespaceDict, Constant):
2.63
2.64 "A module, class or function which was mentioned but could not be imported."
2.65
2.66 @@ -713,14 +722,7 @@
2.67 else:
2.68 return self.parent_name
2.69
2.70 -class Instance:
2.71 -
2.72 - "A placeholder indicating the involvement of an instance."
2.73 -
2.74 - def __repr__(self):
2.75 - return "Instance()"
2.76 -
2.77 -class Module(NamespaceDict):
2.78 +class Module(NamespaceDict, Constant):
2.79
2.80 "An inspected module's core details."
2.81
2.82 @@ -772,4 +774,14 @@
2.83
2.84 return dict(self)
2.85
2.86 +# Instances are special in that they need to be wrapped together with context in
2.87 +# a running program, but they are not generally constant.
2.88 +
2.89 +class Instance:
2.90 +
2.91 + "A placeholder indicating the involvement of an instance."
2.92 +
2.93 + def __repr__(self):
2.94 + return "Instance()"
2.95 +
2.96 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/micropython/inspect.py Sun May 11 18:43:58 2008 +0200
3.2 +++ b/micropython/inspect.py Sun May 11 21:50:30 2008 +0200
3.3 @@ -112,6 +112,9 @@
3.4 if not (self.namespaces and isinstance(self.namespaces[-1], Function)):
3.5 self.all_objects.add(obj)
3.6
3.7 + def store_lambda(self, obj):
3.8 + self.all_objects.add(obj)
3.9 +
3.10 def store_instance_attr(self, name):
3.11
3.12 "Record instance attribute 'name' in the current class."
3.13 @@ -147,6 +150,59 @@
3.14 self.dispatch(n)
3.15 return Instance()
3.16
3.17 + def _visitFunction(self, node, name):
3.18 +
3.19 + """
3.20 + Return a function object for the function defined by 'node' with the
3.21 + given 'name'. If a lambda expression is being visited, 'name' should be
3.22 + None.
3.23 + """
3.24 +
3.25 + function = Function(
3.26 + name,
3.27 + self.get_parent(),
3.28 + node.argnames,
3.29 + node.defaults,
3.30 + (node.flags & 4 != 0),
3.31 + (node.flags & 8 != 0),
3.32 + self,
3.33 + node
3.34 + )
3.35 +
3.36 + # Make a back reference from the node for code generation.
3.37 +
3.38 + node.unit = function
3.39 +
3.40 + # Process the defaults.
3.41 +
3.42 + for n in node.defaults:
3.43 + self.expr = self.dispatch(n)
3.44 + if isinstance(self.expr, Attr):
3.45 + function.store_default(self.expr.value)
3.46 + else:
3.47 + function.store_default(self.expr)
3.48 +
3.49 + # Enter the function.
3.50 +
3.51 + self.namespaces.append(function)
3.52 +
3.53 + # Current namespace is the function.
3.54 + # Previous namespace is the class.
3.55 +
3.56 + if name == "__init__" and isinstance(self.namespaces[-2], Class):
3.57 + self.in_init = 1
3.58 +
3.59 + self.dispatch(node.code)
3.60 + self.in_init = 0
3.61 + self.namespaces.pop()
3.62 +
3.63 + if name is not None:
3.64 + self.store(name, function)
3.65 + else:
3.66 + self.store_lambda(function)
3.67 +
3.68 + return function
3.69 +
3.70 visitAdd = OP
3.71
3.72 visitAnd = OP
3.73 @@ -298,46 +354,7 @@
3.74 return None
3.75
3.76 def visitFunction(self, node):
3.77 - function = Function(
3.78 - node.name,
3.79 - self.get_parent(),
3.80 - node.argnames,
3.81 - node.defaults,
3.82 - (node.flags & 4 != 0),
3.83 - (node.flags & 8 != 0),
3.84 - self,
3.85 - node
3.86 - )
3.87 -
3.88 - # Make a back reference from the node for code generation.
3.89 -
3.90 - node.unit = function
3.91 -
3.92 - # Process the defaults.
3.93 -
3.94 - for n in node.defaults:
3.95 - self.expr = self.dispatch(n)
3.96 - if isinstance(self.expr, Attr):
3.97 - function.store_default(self.expr.value)
3.98 - else:
3.99 - function.store_default(self.expr)
3.100 -
3.101 - # Enter the function.
3.102 -
3.103 - self.namespaces.append(function)
3.104 -
3.105 - # Current namespace is the function.
3.106 - # Previous namespace is the class.
3.107 -
3.108 - if node.name == "__init__" and isinstance(self.namespaces[-2], Class):
3.109 - self.in_init = 1
3.110 -
3.111 - self.dispatch(node.code)
3.112 - self.in_init = 0
3.113 - self.namespaces.pop()
3.114 -
3.115 - self.store(node.name, function)
3.116 - return function
3.117 + return self._visitFunction(node, node.name)
3.118
3.119 visitGenExpr = OP
3.120
3.121 @@ -397,7 +414,8 @@
3.122 self.keyword_names.add(node.name)
3.123 return None
3.124
3.125 - visitLambda = OP
3.126 + def visitLambda(self, node):
3.127 + return self._visitFunction(node, None)
3.128
3.129 visitLeftShift = OP
3.130
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/tests/lambda.py Sun May 11 21:50:30 2008 +0200
4.3 @@ -0,0 +1,6 @@
4.4 +#!/usr/bin/env python
4.5 +
4.6 +identity = lambda x: x
4.7 +lambda a, b=2: a + b
4.8 +
4.9 +# vim: tabstop=4 expandtab shiftwidth=4