1.1 --- a/translator.py Fri Oct 28 22:58:50 2016 +0200
1.2 +++ b/translator.py Sat Oct 29 00:47:12 2016 +0200
1.3 @@ -56,6 +56,12 @@
1.4
1.5 pass
1.6
1.7 +class ReturnRef(TranslationResult):
1.8 +
1.9 + "Indicates usage of a return statement."
1.10 +
1.11 + pass
1.12 +
1.13 class Expression(results.Result, TranslationResult):
1.14
1.15 "A general expression."
1.16 @@ -98,14 +104,14 @@
1.17 if self.static() and isinstance(self.expr, results.ResolvedNameRef) and self.expr.static():
1.18 return ""
1.19 else:
1.20 - return "%s = %s" % (name, self.expr)
1.21 + return "%s = %s" % (dynamic_name, self.expr)
1.22
1.23 # Expressions.
1.24
1.25 elif static_name:
1.26 parent = ref.parent()
1.27 context = ref.has_kind("<function>") and encode_path(parent) or None
1.28 - return "((__attr) {&%s, &%s})" % (context or "0", static_name)
1.29 + return "((__attr) {%s, &%s})" % (context and "&%s" % context or "0", static_name)
1.30
1.31 else:
1.32 return dynamic_name
1.33 @@ -207,6 +213,10 @@
1.34 self.namespaces = []
1.35 self.in_conditional = False
1.36
1.37 + # Exception raising adjustments.
1.38 +
1.39 + self.in_try_finally = False
1.40 +
1.41 # Attribute access counting.
1.42
1.43 self.attr_accesses = {}
1.44 @@ -370,10 +380,22 @@
1.45
1.46 "Process the given 'node' or result."
1.47
1.48 + # Handle processing requests on results.
1.49 +
1.50 if isinstance(node, results.Result):
1.51 return node
1.52 +
1.53 + # Handle processing requests on nodes.
1.54 +
1.55 else:
1.56 - return CommonModule.process_structure(self, node)
1.57 + l = CommonModule.process_structure(self, node)
1.58 +
1.59 + # Return indications of return statement usage.
1.60 +
1.61 + if l and isinstance(l[-1], ReturnRef):
1.62 + return l[-1]
1.63 + else:
1.64 + return None
1.65
1.66 def process_structure_node(self, n):
1.67
1.68 @@ -482,12 +504,11 @@
1.69 elif isinstance(n, compiler.ast.Continue):
1.70 self.writestmt("continue;")
1.71
1.72 + elif isinstance(n, compiler.ast.Raise):
1.73 + self.process_raise_node(n)
1.74 +
1.75 elif isinstance(n, compiler.ast.Return):
1.76 - expr = self.process_structure_node(n.value)
1.77 - if expr:
1.78 - self.writestmt("return %s;" % expr)
1.79 - else:
1.80 - self.writestmt("return;")
1.81 + return self.process_return_node(n)
1.82
1.83 # Invocations.
1.84
1.85 @@ -514,7 +535,7 @@
1.86 # All other nodes are processed depth-first.
1.87
1.88 else:
1.89 - self.process_structure(n)
1.90 + return self.process_structure(n)
1.91
1.92 def process_assignment_node(self, n, expr):
1.93
1.94 @@ -641,7 +662,8 @@
1.95 access = name, attrnames
1.96 if name:
1.97 init_item(self.attr_accesses, path, dict)
1.98 - init_item(self.attr_accesses[path], access, lambda: 1)
1.99 + init_item(self.attr_accesses[path], access, lambda: 0)
1.100 + self.attr_accesses[path][access] += 1
1.101
1.102 def process_class_node(self, n):
1.103
1.104 @@ -672,13 +694,13 @@
1.105 in_conditional = self.in_conditional
1.106 self.in_conditional = False
1.107
1.108 - expr = self.process_structure_node(n.code)
1.109 - if expr:
1.110 + expr = self.process_structure_node(n.code) or PredefinedConstantRef("None")
1.111 + if not isinstance(expr, ReturnRef):
1.112 self.writestmt("return %s;" % expr)
1.113
1.114 self.in_conditional = in_conditional
1.115
1.116 - self.end_function()
1.117 + self.end_function(function_name)
1.118
1.119 def process_function_node(self, n):
1.120
1.121 @@ -1007,7 +1029,28 @@
1.122 # NOTE: This needs to evaluate whether the operand is true or false
1.123 # NOTE: according to Python rules.
1.124
1.125 - return make_expression("(!(%s))" % n.expr)
1.126 + return make_expression("(__BOOL(%s) ? %s : %s)" %
1.127 + (n.expr, PredefinedConstantRef("False"), PredefinedConstantRef("True")))
1.128 +
1.129 + def process_raise_node(self, n):
1.130 +
1.131 + "Process the given raise node 'n'."
1.132 +
1.133 + # NOTE: Determine which raise statement variants should be permitted.
1.134 +
1.135 + self.writestmt("__Raise(%s);" % self.process_structure_node(n.expr1))
1.136 +
1.137 + def process_return_node(self, n):
1.138 +
1.139 + "Process the given return node 'n'."
1.140 +
1.141 + expr = self.process_structure_node(n.value) or PredefinedConstantRef("None")
1.142 + if self.in_try_finally:
1.143 + self.writestmt("__Return(%s);" % expr)
1.144 + else:
1.145 + self.writestmt("return %s;" % expr)
1.146 +
1.147 + return ReturnRef()
1.148
1.149 def process_try_node(self, n):
1.150
1.151 @@ -1015,28 +1058,81 @@
1.152 Process the given "try...except" node 'n'.
1.153 """
1.154
1.155 - # NOTE: Placeholders/macros.
1.156 + # Use macros to implement exception handling.
1.157
1.158 - self.writeline("TRY")
1.159 + self.writestmt("__Try")
1.160 self.writeline("{")
1.161 self.indent += 1
1.162 self.process_structure_node(n.body)
1.163 +
1.164 + # Put the else statement in another try block that handles any raised
1.165 + # exceptions and converts them to exceptions that will not be handled by
1.166 + # the main handling block.
1.167 +
1.168 + if n.else_:
1.169 + self.writestmt("__Try")
1.170 + self.writeline("{")
1.171 + self.indent += 1
1.172 + self.process_structure_node(n.else_)
1.173 + self.indent -= 1
1.174 + self.writeline("}")
1.175 + self.writeline("__Catch (__tmp_exc)")
1.176 + self.writeline("{")
1.177 + self.indent += 1
1.178 + self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);")
1.179 + self.indent -= 1
1.180 + self.writeline("}")
1.181 +
1.182 + # Complete the try block and enter the finally block, if appropriate.
1.183 +
1.184 + if self.in_try_finally:
1.185 + self.writestmt("__Complete;")
1.186 +
1.187 self.indent -= 1
1.188 self.writeline("}")
1.189
1.190 + # Handlers are tests within a common handler block.
1.191 +
1.192 + self.writeline("__Catch (__tmp_exc)")
1.193 + self.writeline("{")
1.194 + self.indent += 1
1.195 +
1.196 + # Handle exceptions in else blocks converted to __RaiseElse, converting
1.197 + # them back to normal exceptions.
1.198 +
1.199 + else_str = ""
1.200 +
1.201 + if n.else_:
1.202 + self.writeline("if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);")
1.203 + else_str = "else "
1.204 +
1.205 + # Handle the completion of try blocks or the execution of return
1.206 + # statements where finally blocks apply.
1.207 +
1.208 + if self.in_try_finally:
1.209 + self.writeline("%sif (__tmp_exc.completing) __Throw(__tmp_exc);" % else_str)
1.210 + else_str = "else "
1.211 +
1.212 + # Exception handling.
1.213 +
1.214 for name, var, handler in n.handlers:
1.215 +
1.216 + # Test for specific exceptions.
1.217 +
1.218 if name is not None:
1.219 name_ref = self.process_structure_node(name)
1.220 - self.writeline("EXCEPT(%s)" % name_ref)
1.221 + self.writeline("%sif (__BOOL(__fn_native__isinstance((__attr[]) {__tmp_exc.arg, %s})))" % (else_str, name_ref))
1.222 + else:
1.223 + self.writeline("%sif (1)" % else_str)
1.224 + else_str = "else "
1.225
1.226 self.writeline("{")
1.227 self.indent += 1
1.228
1.229 # Establish the local for the handler.
1.230 - # NOTE: Need to provide the exception value.
1.231
1.232 if var is not None:
1.233 - var_ref = self.process_structure_node(var)
1.234 + var_ref = self.process_name_node(var, make_expression("__tmp_exc"))
1.235
1.236 if handler is not None:
1.237 self.process_structure_node(handler)
1.238 @@ -1044,8 +1140,14 @@
1.239 self.indent -= 1
1.240 self.writeline("}")
1.241
1.242 - if n.else_:
1.243 - self.process_structure_node(n.else_)
1.244 + # Re-raise unhandled exceptions.
1.245 +
1.246 + self.writeline("%s__Throw(__tmp_exc);" % else_str)
1.247 +
1.248 + # End the handler block.
1.249 +
1.250 + self.indent -= 1
1.251 + self.writeline("}")
1.252
1.253 def process_try_finally_node(self, n):
1.254
1.255 @@ -1053,18 +1155,37 @@
1.256 Process the given "try...finally" node 'n'.
1.257 """
1.258
1.259 - # NOTE: Placeholders/macros.
1.260 + in_try_finally = self.in_try_finally
1.261 + self.in_try_finally = True
1.262
1.263 - self.writeline("TRY")
1.264 + # Use macros to implement exception handling.
1.265 +
1.266 + self.writestmt("__Try")
1.267 self.writeline("{")
1.268 self.indent += 1
1.269 self.process_structure_node(n.body)
1.270 self.indent -= 1
1.271 self.writeline("}")
1.272 - self.writeline("FINALLY")
1.273 +
1.274 + self.in_try_finally = in_try_finally
1.275 +
1.276 + # Finally clauses handle special exceptions.
1.277 +
1.278 + self.writeline("__Catch (__tmp_exc)")
1.279 self.writeline("{")
1.280 self.indent += 1
1.281 self.process_structure_node(n.final)
1.282 +
1.283 + # Test for the completion of a try block.
1.284 +
1.285 + self.writestmt("if (__tmp_exc.completing)")
1.286 + self.writeline("{")
1.287 + self.indent += 1
1.288 + self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;")
1.289 + self.indent -= 1
1.290 + self.writeline("}")
1.291 + self.writeline("else __Throw(__tmp_exc);")
1.292 +
1.293 self.indent -= 1
1.294 self.writeline("}")
1.295
1.296 @@ -1085,7 +1206,7 @@
1.297 # NOTE: This needs to evaluate whether the operand is true or false
1.298 # NOTE: according to Python rules.
1.299
1.300 - self.writeline("if (!(%s))" % test)
1.301 + self.writeline("if (!__BOOL(%s))" % test)
1.302 self.writeline("{")
1.303 self.indent += 1
1.304 if n.else_:
1.305 @@ -1107,6 +1228,7 @@
1.306 def start_output(self):
1.307 print >>self.out, """\
1.308 #include "types.h"
1.309 +#include "exceptions.h"
1.310 #include "ops.h"
1.311 #include "progconsts.h"
1.312 #include "progops.h"
1.313 @@ -1121,7 +1243,7 @@
1.314
1.315 def end_module(self):
1.316 self.indent -= 1
1.317 - self.end_function()
1.318 + print >>self.out, "}"
1.319
1.320 def start_function(self, name):
1.321 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name)
1.322 @@ -1129,12 +1251,13 @@
1.323 self.indent += 1
1.324 self.writeline("__ref __tmp_context, __tmp_value;")
1.325 self.writeline("__attr __tmp_target, __tmp_result;")
1.326 + self.writeline("__exc __tmp_exc;")
1.327
1.328 # Obtain local names from parameters.
1.329
1.330 parameters = self.importer.function_parameters[name]
1.331 + locals = self.importer.function_locals[name].keys()
1.332 names = []
1.333 - locals = self.importer.function_locals[name].keys()
1.334
1.335 for n in locals:
1.336
1.337 @@ -1152,27 +1275,39 @@
1.338 names.sort()
1.339 self.writeline("__attr %s;" % ", ".join(names))
1.340
1.341 + self.write_parameters(name, True)
1.342 +
1.343 + def end_function(self, name):
1.344 + self.write_parameters(name, False)
1.345 + self.indent -= 1
1.346 + print >>self.out, "}"
1.347 + print >>self.out
1.348 +
1.349 + def write_parameters(self, name, define=True):
1.350 + parameters = self.importer.function_parameters[name]
1.351 +
1.352 # Generate any self reference.
1.353
1.354 if self.in_method(name):
1.355 - self.writeline("#define self (__args[0])")
1.356 + if define:
1.357 + self.writeline("#define self (__args[0])")
1.358 + else:
1.359 + self.writeline("#undef self")
1.360
1.361 # Generate aliases for the parameters.
1.362
1.363 for i, parameter in enumerate(parameters):
1.364 - self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1))
1.365 -
1.366 - def end_function(self):
1.367 - self.indent -= 1
1.368 - print >>self.out, "}"
1.369 - print >>self.out
1.370 + if define:
1.371 + self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1))
1.372 + else:
1.373 + self.writeline("#undef %s" % encode_path(parameter))
1.374
1.375 def start_if(self, first, test_ref):
1.376
1.377 # NOTE: This needs to evaluate whether the operand is true or false
1.378 # NOTE: according to Python rules.
1.379
1.380 - self.writestmt("%sif (%s)" % (not first and "else " or "", test_ref))
1.381 + self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref))
1.382 self.writeline("{")
1.383 self.indent += 1
1.384