1.1 --- a/encoders.py Fri Oct 28 22:58:50 2016 +0200
1.2 +++ b/encoders.py Sat Oct 29 00:47:12 2016 +0200
1.3 @@ -178,7 +178,7 @@
1.4 )
1.5
1.6 typename_ops = (
1.7 - "__test_common_instance",
1.8 + "__test_common_instance", "__test_common_object", "__test_common_type",
1.9 )
1.10
1.11 encoding_ops = (
1.12 @@ -253,7 +253,12 @@
1.13 # Substitute the first element of the instruction, which may not be an
1.14 # operation at all.
1.15
1.16 - return "%s%s" % (subs.get(op, op), argstr)
1.17 + if subs.has_key(op):
1.18 + op = subs[op]
1.19 + elif not args:
1.20 + op = "&%s" % encode_path(op)
1.21 +
1.22 + return "%s%s" % (op, argstr)
1.23
1.24 def encode_access_instruction_arg(arg, subs):
1.25
2.1 --- a/templates/ops.c Fri Oct 28 22:58:50 2016 +0200
2.2 +++ b/templates/ops.c Sat Oct 29 00:47:12 2016 +0200
2.3 @@ -62,14 +62,24 @@
2.4
2.5 /* Attribute testing operations. */
2.6
2.7 -int __test_specific_instance(__ref obj, __ref type)
2.8 +__ref __test_specific_instance(__ref obj, __ref type)
2.9 {
2.10 - return __get_class(obj) == type;
2.11 + return __get_class(obj) == type ? obj : 0;
2.12 }
2.13
2.14 -int __test_common_instance(__ref obj, int pos, int code)
2.15 +__ref __test_common_instance(__ref obj, int pos, int code)
2.16 +{
2.17 + return __HASATTR(__get_class(obj), pos, code) ? obj : 0;
2.18 +}
2.19 +
2.20 +__ref __test_common_object(__ref obj, int pos, int code)
2.21 {
2.22 - return __HASATTR(__get_class(obj), pos, code);
2.23 + return __test_common_type(obj, pos, code) || __test_common_instance(obj, pos, code) ? obj : 0;
2.24 +}
2.25 +
2.26 +__ref __test_common_type(__ref obj, int pos, int code)
2.27 +{
2.28 + return __HASATTR(obj, pos, code) ? obj : 0;
2.29 }
2.30
2.31 /* Attribute testing and retrieval operations. */
2.32 @@ -186,7 +196,7 @@
2.33
2.34 /* Type testing. */
2.35
2.36 -int __ISFUNC(__ref obj)
2.37 +__ref __ISFUNC(__ref obj)
2.38 {
2.39 return __test_specific_instance(obj, &__FUNCTION_TYPE);
2.40 }
3.1 --- a/templates/ops.h Fri Oct 28 22:58:50 2016 +0200
3.2 +++ b/templates/ops.h Sat Oct 29 00:47:12 2016 +0200
3.3 @@ -31,8 +31,10 @@
3.4
3.5 /* Attribute testing operations. */
3.6
3.7 -int __test_common_instance(__ref obj, int pos, int code);
3.8 -int __test_specific_instance(__ref obj, __ref type);
3.9 +__ref __test_common_instance(__ref obj, int pos, int code);
3.10 +__ref __test_common_object(__ref obj, int pos, int code);
3.11 +__ref __test_common_type(__ref obj, int pos, int code);
3.12 +__ref __test_specific_instance(__ref obj, __ref type);
3.13
3.14 /* Attribute testing and retrieval operations. */
3.15
3.16 @@ -69,7 +71,7 @@
3.17
3.18 /* Type testing. */
3.19
3.20 -int __ISFUNC(__ref obj);
3.21 +__ref __ISFUNC(__ref obj);
3.22 int __ISNULL(__attr value);
3.23
3.24 /* __TEST(obj, __A) -> test obj for the special type attribute __A */
6.1 --- a/translator.py Fri Oct 28 22:58:50 2016 +0200
6.2 +++ b/translator.py Sat Oct 29 00:47:12 2016 +0200
6.3 @@ -56,6 +56,12 @@
6.4
6.5 pass
6.6
6.7 +class ReturnRef(TranslationResult):
6.8 +
6.9 + "Indicates usage of a return statement."
6.10 +
6.11 + pass
6.12 +
6.13 class Expression(results.Result, TranslationResult):
6.14
6.15 "A general expression."
6.16 @@ -98,14 +104,14 @@
6.17 if self.static() and isinstance(self.expr, results.ResolvedNameRef) and self.expr.static():
6.18 return ""
6.19 else:
6.20 - return "%s = %s" % (name, self.expr)
6.21 + return "%s = %s" % (dynamic_name, self.expr)
6.22
6.23 # Expressions.
6.24
6.25 elif static_name:
6.26 parent = ref.parent()
6.27 context = ref.has_kind("<function>") and encode_path(parent) or None
6.28 - return "((__attr) {&%s, &%s})" % (context or "0", static_name)
6.29 + return "((__attr) {%s, &%s})" % (context and "&%s" % context or "0", static_name)
6.30
6.31 else:
6.32 return dynamic_name
6.33 @@ -207,6 +213,10 @@
6.34 self.namespaces = []
6.35 self.in_conditional = False
6.36
6.37 + # Exception raising adjustments.
6.38 +
6.39 + self.in_try_finally = False
6.40 +
6.41 # Attribute access counting.
6.42
6.43 self.attr_accesses = {}
6.44 @@ -370,10 +380,22 @@
6.45
6.46 "Process the given 'node' or result."
6.47
6.48 + # Handle processing requests on results.
6.49 +
6.50 if isinstance(node, results.Result):
6.51 return node
6.52 +
6.53 + # Handle processing requests on nodes.
6.54 +
6.55 else:
6.56 - return CommonModule.process_structure(self, node)
6.57 + l = CommonModule.process_structure(self, node)
6.58 +
6.59 + # Return indications of return statement usage.
6.60 +
6.61 + if l and isinstance(l[-1], ReturnRef):
6.62 + return l[-1]
6.63 + else:
6.64 + return None
6.65
6.66 def process_structure_node(self, n):
6.67
6.68 @@ -482,12 +504,11 @@
6.69 elif isinstance(n, compiler.ast.Continue):
6.70 self.writestmt("continue;")
6.71
6.72 + elif isinstance(n, compiler.ast.Raise):
6.73 + self.process_raise_node(n)
6.74 +
6.75 elif isinstance(n, compiler.ast.Return):
6.76 - expr = self.process_structure_node(n.value)
6.77 - if expr:
6.78 - self.writestmt("return %s;" % expr)
6.79 - else:
6.80 - self.writestmt("return;")
6.81 + return self.process_return_node(n)
6.82
6.83 # Invocations.
6.84
6.85 @@ -514,7 +535,7 @@
6.86 # All other nodes are processed depth-first.
6.87
6.88 else:
6.89 - self.process_structure(n)
6.90 + return self.process_structure(n)
6.91
6.92 def process_assignment_node(self, n, expr):
6.93
6.94 @@ -641,7 +662,8 @@
6.95 access = name, attrnames
6.96 if name:
6.97 init_item(self.attr_accesses, path, dict)
6.98 - init_item(self.attr_accesses[path], access, lambda: 1)
6.99 + init_item(self.attr_accesses[path], access, lambda: 0)
6.100 + self.attr_accesses[path][access] += 1
6.101
6.102 def process_class_node(self, n):
6.103
6.104 @@ -672,13 +694,13 @@
6.105 in_conditional = self.in_conditional
6.106 self.in_conditional = False
6.107
6.108 - expr = self.process_structure_node(n.code)
6.109 - if expr:
6.110 + expr = self.process_structure_node(n.code) or PredefinedConstantRef("None")
6.111 + if not isinstance(expr, ReturnRef):
6.112 self.writestmt("return %s;" % expr)
6.113
6.114 self.in_conditional = in_conditional
6.115
6.116 - self.end_function()
6.117 + self.end_function(function_name)
6.118
6.119 def process_function_node(self, n):
6.120
6.121 @@ -1007,7 +1029,28 @@
6.122 # NOTE: This needs to evaluate whether the operand is true or false
6.123 # NOTE: according to Python rules.
6.124
6.125 - return make_expression("(!(%s))" % n.expr)
6.126 + return make_expression("(__BOOL(%s) ? %s : %s)" %
6.127 + (n.expr, PredefinedConstantRef("False"), PredefinedConstantRef("True")))
6.128 +
6.129 + def process_raise_node(self, n):
6.130 +
6.131 + "Process the given raise node 'n'."
6.132 +
6.133 + # NOTE: Determine which raise statement variants should be permitted.
6.134 +
6.135 + self.writestmt("__Raise(%s);" % self.process_structure_node(n.expr1))
6.136 +
6.137 + def process_return_node(self, n):
6.138 +
6.139 + "Process the given return node 'n'."
6.140 +
6.141 + expr = self.process_structure_node(n.value) or PredefinedConstantRef("None")
6.142 + if self.in_try_finally:
6.143 + self.writestmt("__Return(%s);" % expr)
6.144 + else:
6.145 + self.writestmt("return %s;" % expr)
6.146 +
6.147 + return ReturnRef()
6.148
6.149 def process_try_node(self, n):
6.150
6.151 @@ -1015,28 +1058,81 @@
6.152 Process the given "try...except" node 'n'.
6.153 """
6.154
6.155 - # NOTE: Placeholders/macros.
6.156 + # Use macros to implement exception handling.
6.157
6.158 - self.writeline("TRY")
6.159 + self.writestmt("__Try")
6.160 self.writeline("{")
6.161 self.indent += 1
6.162 self.process_structure_node(n.body)
6.163 +
6.164 + # Put the else statement in another try block that handles any raised
6.165 + # exceptions and converts them to exceptions that will not be handled by
6.166 + # the main handling block.
6.167 +
6.168 + if n.else_:
6.169 + self.writestmt("__Try")
6.170 + self.writeline("{")
6.171 + self.indent += 1
6.172 + self.process_structure_node(n.else_)
6.173 + self.indent -= 1
6.174 + self.writeline("}")
6.175 + self.writeline("__Catch (__tmp_exc)")
6.176 + self.writeline("{")
6.177 + self.indent += 1
6.178 + self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);")
6.179 + self.indent -= 1
6.180 + self.writeline("}")
6.181 +
6.182 + # Complete the try block and enter the finally block, if appropriate.
6.183 +
6.184 + if self.in_try_finally:
6.185 + self.writestmt("__Complete;")
6.186 +
6.187 self.indent -= 1
6.188 self.writeline("}")
6.189
6.190 + # Handlers are tests within a common handler block.
6.191 +
6.192 + self.writeline("__Catch (__tmp_exc)")
6.193 + self.writeline("{")
6.194 + self.indent += 1
6.195 +
6.196 + # Handle exceptions in else blocks converted to __RaiseElse, converting
6.197 + # them back to normal exceptions.
6.198 +
6.199 + else_str = ""
6.200 +
6.201 + if n.else_:
6.202 + self.writeline("if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);")
6.203 + else_str = "else "
6.204 +
6.205 + # Handle the completion of try blocks or the execution of return
6.206 + # statements where finally blocks apply.
6.207 +
6.208 + if self.in_try_finally:
6.209 + self.writeline("%sif (__tmp_exc.completing) __Throw(__tmp_exc);" % else_str)
6.210 + else_str = "else "
6.211 +
6.212 + # Exception handling.
6.213 +
6.214 for name, var, handler in n.handlers:
6.215 +
6.216 + # Test for specific exceptions.
6.217 +
6.218 if name is not None:
6.219 name_ref = self.process_structure_node(name)
6.220 - self.writeline("EXCEPT(%s)" % name_ref)
6.221 + self.writeline("%sif (__BOOL(__fn_native__isinstance((__attr[]) {__tmp_exc.arg, %s})))" % (else_str, name_ref))
6.222 + else:
6.223 + self.writeline("%sif (1)" % else_str)
6.224 + else_str = "else "
6.225
6.226 self.writeline("{")
6.227 self.indent += 1
6.228
6.229 # Establish the local for the handler.
6.230 - # NOTE: Need to provide the exception value.
6.231
6.232 if var is not None:
6.233 - var_ref = self.process_structure_node(var)
6.234 + var_ref = self.process_name_node(var, make_expression("__tmp_exc"))
6.235
6.236 if handler is not None:
6.237 self.process_structure_node(handler)
6.238 @@ -1044,8 +1140,14 @@
6.239 self.indent -= 1
6.240 self.writeline("}")
6.241
6.242 - if n.else_:
6.243 - self.process_structure_node(n.else_)
6.244 + # Re-raise unhandled exceptions.
6.245 +
6.246 + self.writeline("%s__Throw(__tmp_exc);" % else_str)
6.247 +
6.248 + # End the handler block.
6.249 +
6.250 + self.indent -= 1
6.251 + self.writeline("}")
6.252
6.253 def process_try_finally_node(self, n):
6.254
6.255 @@ -1053,18 +1155,37 @@
6.256 Process the given "try...finally" node 'n'.
6.257 """
6.258
6.259 - # NOTE: Placeholders/macros.
6.260 + in_try_finally = self.in_try_finally
6.261 + self.in_try_finally = True
6.262
6.263 - self.writeline("TRY")
6.264 + # Use macros to implement exception handling.
6.265 +
6.266 + self.writestmt("__Try")
6.267 self.writeline("{")
6.268 self.indent += 1
6.269 self.process_structure_node(n.body)
6.270 self.indent -= 1
6.271 self.writeline("}")
6.272 - self.writeline("FINALLY")
6.273 +
6.274 + self.in_try_finally = in_try_finally
6.275 +
6.276 + # Finally clauses handle special exceptions.
6.277 +
6.278 + self.writeline("__Catch (__tmp_exc)")
6.279 self.writeline("{")
6.280 self.indent += 1
6.281 self.process_structure_node(n.final)
6.282 +
6.283 + # Test for the completion of a try block.
6.284 +
6.285 + self.writestmt("if (__tmp_exc.completing)")
6.286 + self.writeline("{")
6.287 + self.indent += 1
6.288 + self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;")
6.289 + self.indent -= 1
6.290 + self.writeline("}")
6.291 + self.writeline("else __Throw(__tmp_exc);")
6.292 +
6.293 self.indent -= 1
6.294 self.writeline("}")
6.295
6.296 @@ -1085,7 +1206,7 @@
6.297 # NOTE: This needs to evaluate whether the operand is true or false
6.298 # NOTE: according to Python rules.
6.299
6.300 - self.writeline("if (!(%s))" % test)
6.301 + self.writeline("if (!__BOOL(%s))" % test)
6.302 self.writeline("{")
6.303 self.indent += 1
6.304 if n.else_:
6.305 @@ -1107,6 +1228,7 @@
6.306 def start_output(self):
6.307 print >>self.out, """\
6.308 #include "types.h"
6.309 +#include "exceptions.h"
6.310 #include "ops.h"
6.311 #include "progconsts.h"
6.312 #include "progops.h"
6.313 @@ -1121,7 +1243,7 @@
6.314
6.315 def end_module(self):
6.316 self.indent -= 1
6.317 - self.end_function()
6.318 + print >>self.out, "}"
6.319
6.320 def start_function(self, name):
6.321 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name)
6.322 @@ -1129,12 +1251,13 @@
6.323 self.indent += 1
6.324 self.writeline("__ref __tmp_context, __tmp_value;")
6.325 self.writeline("__attr __tmp_target, __tmp_result;")
6.326 + self.writeline("__exc __tmp_exc;")
6.327
6.328 # Obtain local names from parameters.
6.329
6.330 parameters = self.importer.function_parameters[name]
6.331 + locals = self.importer.function_locals[name].keys()
6.332 names = []
6.333 - locals = self.importer.function_locals[name].keys()
6.334
6.335 for n in locals:
6.336
6.337 @@ -1152,27 +1275,39 @@
6.338 names.sort()
6.339 self.writeline("__attr %s;" % ", ".join(names))
6.340
6.341 + self.write_parameters(name, True)
6.342 +
6.343 + def end_function(self, name):
6.344 + self.write_parameters(name, False)
6.345 + self.indent -= 1
6.346 + print >>self.out, "}"
6.347 + print >>self.out
6.348 +
6.349 + def write_parameters(self, name, define=True):
6.350 + parameters = self.importer.function_parameters[name]
6.351 +
6.352 # Generate any self reference.
6.353
6.354 if self.in_method(name):
6.355 - self.writeline("#define self (__args[0])")
6.356 + if define:
6.357 + self.writeline("#define self (__args[0])")
6.358 + else:
6.359 + self.writeline("#undef self")
6.360
6.361 # Generate aliases for the parameters.
6.362
6.363 for i, parameter in enumerate(parameters):
6.364 - self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1))
6.365 -
6.366 - def end_function(self):
6.367 - self.indent -= 1
6.368 - print >>self.out, "}"
6.369 - print >>self.out
6.370 + if define:
6.371 + self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1))
6.372 + else:
6.373 + self.writeline("#undef %s" % encode_path(parameter))
6.374
6.375 def start_if(self, first, test_ref):
6.376
6.377 # NOTE: This needs to evaluate whether the operand is true or false
6.378 # NOTE: according to Python rules.
6.379
6.380 - self.writestmt("%sif (%s)" % (not first and "else " or "", test_ref))
6.381 + self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref))
6.382 self.writeline("{")
6.383 self.indent += 1
6.384