paul@479 | 1 | #!/usr/bin/env python |
paul@479 | 2 | |
paul@479 | 3 | """ |
paul@479 | 4 | Native library generation. |
paul@479 | 5 | |
paul@479 | 6 | Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk> |
paul@479 | 7 | |
paul@479 | 8 | This program is free software; you can redistribute it and/or modify it under |
paul@479 | 9 | the terms of the GNU General Public License as published by the Free Software |
paul@479 | 10 | Foundation; either version 3 of the License, or (at your option) any later |
paul@479 | 11 | version. |
paul@479 | 12 | |
paul@479 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@479 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@479 | 15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@479 | 16 | details. |
paul@479 | 17 | |
paul@479 | 18 | You should have received a copy of the GNU General Public License along with |
paul@479 | 19 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@479 | 20 | """ |
paul@479 | 21 | |
paul@479 | 22 | from micropython.code import Assembler |
paul@479 | 23 | from micropython.rsvp import * |
paul@479 | 24 | |
paul@479 | 25 | class NativeLibrary(Assembler): |
paul@479 | 26 | |
paul@479 | 27 | "A native library generator providing common routines." |
paul@479 | 28 | |
paul@479 | 29 | def __init__(self, program): |
paul@479 | 30 | |
paul@479 | 31 | """ |
paul@479 | 32 | Initialise a native library for the given 'program'. |
paul@479 | 33 | """ |
paul@479 | 34 | |
paul@479 | 35 | Assembler.__init__(self, program) |
paul@479 | 36 | |
paul@479 | 37 | self.importer = self.program.get_importer() |
paul@479 | 38 | self.builtins = None |
paul@479 | 39 | |
paul@479 | 40 | self.unknown_target_block = None |
paul@479 | 41 | self.unknown_target_testable_self_block = None |
paul@479 | 42 | self.known_target_testable_self_block = None |
paul@479 | 43 | |
paul@479 | 44 | # Reset the assembler. |
paul@479 | 45 | |
paul@479 | 46 | self.reset() |
paul@479 | 47 | |
paul@479 | 48 | def get_native_code(self): |
paul@479 | 49 | self.builtins = self.importer.modules.get("__builtins__") |
paul@479 | 50 | |
paul@479 | 51 | if self.unknown_target_block is not None: |
paul@479 | 52 | self._generateCallFuncUnknownTarget() |
paul@479 | 53 | |
paul@479 | 54 | if self.unknown_target_testable_self_block is not None: |
paul@479 | 55 | self._generateCallFuncUnknownTargetTestableSelf() |
paul@479 | 56 | |
paul@479 | 57 | if self.known_target_testable_self_block is not None: |
paul@479 | 58 | self._generateCallFuncKnownTargetTestableSelf() |
paul@479 | 59 | |
paul@479 | 60 | return self.blocks |
paul@479 | 61 | |
paul@479 | 62 | def _commonCallFunc(self, adjust_block, continue_block): |
paul@479 | 63 | self.new_op(CheckContext(working="source", target="status")) |
paul@479 | 64 | self.new_op(JumpIfFalse(adjust_block, working="status")) |
paul@479 | 65 | |
paul@479 | 66 | # Skip adjustment and tests if the context is not a class. |
paul@479 | 67 | # Classes themselves employ a placeholder context so that |
paul@479 | 68 | # instantiators can be callable with a context which will be |
paul@479 | 69 | # overwritten in the frame. |
paul@479 | 70 | |
paul@479 | 71 | # Here, the source value should still refer to the context. |
paul@479 | 72 | |
paul@479 | 73 | self.new_op(CheckClass(working="source", target="status")) |
paul@479 | 74 | self.new_op(JumpIfFalse(continue_block, working="status")) |
paul@479 | 75 | |
paul@479 | 76 | def _commonTestContext(self, success_block): |
paul@479 | 77 | self.new_op(CheckInstance(source="source", target="status")) |
paul@479 | 78 | self.new_op(JumpIfTrue(success_block, working="status")) |
paul@479 | 79 | |
paul@479 | 80 | # Where the context is inappropriate, drop the incomplete frame and |
paul@479 | 81 | # raise an exception. |
paul@479 | 82 | |
paul@479 | 83 | self.new_op(DropFrame()) |
paul@479 | 84 | |
paul@479 | 85 | self.make_exception("TypeError") |
paul@479 | 86 | self.set_target("exception") |
paul@479 | 87 | self.new_op(RaiseException()) |
paul@479 | 88 | |
paul@479 | 89 | def _commonAdjustFrame(self, adjust_block, continue_block): |
paul@479 | 90 | self.set_block(adjust_block) |
paul@479 | 91 | self.new_op(AdjustFrame(1)) |
paul@479 | 92 | self.set_block(continue_block) |
paul@479 | 93 | |
paul@479 | 94 | def getCallFuncUnknownTarget(self): |
paul@479 | 95 | if self.unknown_target_block is None: |
paul@479 | 96 | self.unknown_target_block = self.new_block() |
paul@479 | 97 | |
paul@479 | 98 | return self.unknown_target_block |
paul@479 | 99 | |
paul@479 | 100 | def _generateCallFuncUnknownTarget(self): |
paul@479 | 101 | |
paul@479 | 102 | """ |
paul@479 | 103 | Some preliminary tests where the target of an invocation is not known. |
paul@479 | 104 | Requires the context in the working value register. |
paul@479 | 105 | """ |
paul@479 | 106 | |
paul@479 | 107 | adjust_block = self.new_block() |
paul@479 | 108 | continue_block = self.new_block() |
paul@479 | 109 | |
paul@479 | 110 | self.set_block(self.unknown_target_block) |
paul@479 | 111 | self._commonCallFunc(adjust_block, continue_block) |
paul@479 | 112 | self._commonAdjustFrame(adjust_block, continue_block) |
paul@479 | 113 | self.new_op(Return()) |
paul@479 | 114 | |
paul@479 | 115 | def getCallFuncUnknownTargetTestableSelf(self): |
paul@479 | 116 | if self.unknown_target_testable_self_block is None: |
paul@479 | 117 | self.unknown_target_testable_self_block = self.new_block() |
paul@479 | 118 | |
paul@479 | 119 | return self.unknown_target_testable_self_block |
paul@479 | 120 | |
paul@479 | 121 | def _generateCallFuncUnknownTargetTestableSelf(self): |
paul@479 | 122 | |
paul@479 | 123 | """ |
paul@479 | 124 | Test any explicit first argument against the context. |
paul@479 | 125 | """ |
paul@479 | 126 | |
paul@479 | 127 | adjust_block = self.new_block() |
paul@479 | 128 | continue_block = self.new_block() |
paul@479 | 129 | |
paul@479 | 130 | self.set_block(self.unknown_target_testable_self_block) |
paul@479 | 131 | self._commonCallFunc(adjust_block, continue_block) |
paul@479 | 132 | self._commonTestContext(adjust_block) |
paul@479 | 133 | self._commonAdjustFrame(adjust_block, continue_block) |
paul@479 | 134 | self.new_op(Return()) |
paul@479 | 135 | |
paul@479 | 136 | def getCallFuncKnownTargetTestableSelf(self): |
paul@479 | 137 | if self.known_target_testable_self_block is None: |
paul@479 | 138 | self.known_target_testable_self_block = self.new_block() |
paul@479 | 139 | |
paul@479 | 140 | return self.known_target_testable_self_block |
paul@479 | 141 | |
paul@479 | 142 | def _generateCallFuncKnownTargetTestableSelf(self): |
paul@479 | 143 | |
paul@479 | 144 | """ |
paul@479 | 145 | Test any explicit first argument against the context. |
paul@479 | 146 | """ |
paul@479 | 147 | |
paul@479 | 148 | adjust_block = self.new_block() |
paul@479 | 149 | continue_block = self.new_block() |
paul@479 | 150 | |
paul@479 | 151 | self.set_block(self.known_target_testable_self_block) |
paul@479 | 152 | self._commonTestContext(continue_block) |
paul@479 | 153 | self._commonAdjustFrame(adjust_block, continue_block) |
paul@479 | 154 | self.new_op(Return()) |
paul@479 | 155 | |
paul@479 | 156 | # vim: tabstop=4 expandtab shiftwidth=4 |