1 #!/usr/bin/env python 2 3 """ 4 A really simple virtual processor employing a simple set of instructions which 5 ignore low-level operations and merely concentrate on variable access, structure 6 access, structure allocation and function invocations. 7 8 Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk> 9 10 This program is free software; you can redistribute it and/or modify it under 11 the terms of the GNU General Public License as published by the Free Software 12 Foundation; either version 3 of the License, or (at your option) any later 13 version. 14 15 This program is distributed in the hope that it will be useful, but WITHOUT 16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 details. 19 20 You should have received a copy of the GNU General Public License along with 21 this program. If not, see <http://www.gnu.org/licenses/>. 22 23 -------- 24 25 The execution model of the virtual processor involves the following things: 26 27 * Memory contains constants, global variable 28 references and program code 29 30 * PC (program counter) stack contains the return address associated 31 with each function invocation 32 33 * Frame stack contains invocation frames in use and in 34 preparation plus temporary storage 35 36 * Local frame pointer stack refers to the frames in the frame stack 37 38 * Invocation frame pointer stack 39 40 * Exception handler stack 41 42 * Exception handler locals stack refers to the state of the local frame 43 pointer stack 44 45 * Exception handler PC stack refers to the state of the PC stack 46 47 * Registers: current value, 48 boolean status value, 49 source value, 50 current result, 51 current exception, 52 current callable 53 """ 54 55 from micropython.program import DataObject # for creating "nice" new objects 56 57 class IllegalInstruction(Exception): 58 pass 59 60 class IllegalAddress(Exception): 61 def __init__(self, address): 62 self.address = address 63 def __repr__(self): 64 return "IllegalAddress(%r)" % self.address 65 def __str__(self): 66 return repr(self) 67 68 class EmptyPCStack(Exception): 69 pass 70 71 class EmptyFrameStack(Exception): 72 pass 73 74 class BreakpointReached(Exception): 75 pass 76 77 class RSVPMachine: 78 79 "A really simple virtual processor." 80 81 def __init__(self, memory, objlist, paramlist, true_constant, false_constant, pc=None, debug=0): 82 83 """ 84 Initialise the processor with a 'memory' (a list of values containing 85 instructions and data), the object and parameter lists 'objlist' and 86 'paramlist', the addresses 'true_constant' and 'false_constant', and the 87 optional program counter 'pc'. 88 """ 89 90 self.memory = memory 91 self._objlist = objlist 92 self._paramlist = paramlist 93 self.objlist = objlist.as_raw() 94 self.paramlist = paramlist.as_raw() 95 self.true_constant = true_constant 96 self.false_constant = false_constant 97 98 self.pc = pc or 0 99 self.debug = debug 100 101 # Stacks. 102 103 self.pc_stack = [] 104 self.frame_stack = [] 105 self.local_sp_stack = [0] 106 self.invocation_sp_stack = [] 107 self.handler_stack = [len(self.memory) - 1] # final handler is the end of the code 108 self.handler_local_sp_stack = [] 109 self.handler_pc_stack = [] 110 111 # Registers. 112 113 self.instruction = None 114 self.operand = None 115 self.value = None 116 self.status = None 117 self.source = None 118 self.callable = None 119 self.result = None 120 self.exception = None 121 122 # Constants. 123 124 cls = self._get_class("__builtins__", "AttributeError") 125 self.attr_error = cls.location 126 self.attr_error_instance = cls.instance_template_location 127 cls = self._get_class("__builtins__", "TypeError") 128 self.type_error = cls.location 129 self.type_error_instance = cls.instance_template_location 130 cls = self._get_class("__builtins__", "IndexError") 131 self.index_error = cls.location 132 self.index_error_instance = cls.instance_template_location 133 134 # Native class constants. 135 136 cls = self._get_class("__builtins__", "int") 137 self.int_class = cls.location 138 self.int_instance = cls.instance_template_location 139 cls = self._get_class("__builtins__", "list") 140 self.list_instance = cls.instance_template_location 141 142 # Debugging attributes. 143 144 self.breakpoints = set() 145 146 def _get_class(self, module, name): 147 return self._objlist.access(module, name).get_value() 148 149 # Debugging methods. 150 151 def dump(self): 152 print "PC", self.pc, "->", self.load(self.pc) 153 print "PC stack", self.pc_stack 154 print "Frame stack", self.frame_stack 155 print "Local stack pointers", self.local_sp_stack 156 print "Invocation stack pointers", self.invocation_sp_stack 157 print "Handler stack", self.handler_stack 158 print "Handler frame stack", self.handler_local_sp_stack 159 print "Handler PC stack", self.handler_pc_stack 160 print 161 print "Instruction", self.instruction 162 print "Operand", self.operand 163 print "Value", self.value 164 print "Status", self.status 165 print "Source", self.source 166 print "Callable", self.callable 167 print "Result", self.result 168 print "Exception", self.exception 169 170 def show(self): 171 self.show_memory(self.memory, 0) 172 173 def show_pc(self, run_in=10): 174 start = max(0, self.pc - run_in) 175 end = self.pc + run_in 176 memory = self.memory[start:end] 177 self.show_memory(memory, start) 178 179 def show_memory(self, memory, start): 180 for i, x in enumerate(memory): 181 location = start + i 182 if location == self.pc: 183 print "->", 184 else: 185 print " ", 186 print "%5d %r" % (location, x) 187 188 def step(self, dump=0): 189 self.execute() 190 self.show_pc() 191 if dump: 192 self.dump() 193 194 def set_break(self, location): 195 self.breakpoints.add(location) 196 197 # Internal operations. 198 199 def load(self, address): 200 201 "Return the value at the given 'address'." 202 203 try: 204 return self.memory[address] 205 except IndexError: 206 raise IllegalAddress(address) 207 except TypeError: 208 raise IllegalAddress(address) 209 210 def save(self, address, value): 211 212 "Save to the given 'address' the specified 'value'." 213 214 try: 215 self.memory[address] = value 216 except IndexError: 217 raise IllegalAddress(address) 218 except TypeError: 219 raise IllegalAddress(address) 220 221 def new(self, size): 222 223 """ 224 Allocate space of the given 'size', returning the address of the space. 225 """ 226 227 addr = len(self.memory) 228 for i in range(0, size): 229 self.memory.append(None) 230 return addr 231 232 def push_pc(self, data): 233 234 "Push 'data' onto the PC stack." 235 236 self.pc_stack.append(data) 237 238 def pull_pc(self): 239 240 "Pull a value from the PC stack and return it." 241 242 try: 243 return self.pc_stack.pop() 244 except IndexError: 245 raise EmptyPCStack 246 247 def run(self): 248 249 "Execute code in the memory, starting from the current PC address." 250 251 breakpoint = 0 252 253 try: 254 while 1: 255 self.execute() 256 except EmptyPCStack: 257 pass 258 except BreakpointReached: 259 breakpoint = 1 260 261 print "Execution terminated", 262 if self.exception is not None: 263 ref = self.exception 264 addr = self.load(ref + 1) 265 print "with exception:", self.load(ref) 266 print "At address %d: %r" % (addr, self.load(addr)) 267 elif breakpoint: 268 print "with breakpoint." 269 print "At address", self.pc 270 else: 271 print "successfully." 272 273 def test(self, module): 274 275 """ 276 Test the code in the memory by running the code and investigating the 277 contents of variables. Use 'module' to identify result variables. 278 """ 279 280 self.run() 281 success = 1 282 283 for name in module.keys(): 284 if name.startswith("result"): 285 label, expected = name.split("_") 286 attr = module[name] 287 288 # NOTE: Assumptions about headers and content made. 289 290 attr_location = module.location + 1 + attr.position 291 context, ref = self.load(attr_location) 292 content = self.load(ref + 1) 293 print label, expected, content 294 295 success = success and (int(expected) == content) 296 297 return success 298 299 def execute(self): 300 301 "Execute code in the memory at the current PC address." 302 303 if self.pc in self.breakpoints: 304 self.breakpoints.remove(self.pc) 305 raise BreakpointReached 306 307 self.instruction = self.load(self.pc) 308 309 # Process any inputs of the instruction. 310 311 self.process_inputs() 312 313 # Perform the instruction itself. 314 315 next_pc = self.perform(self.instruction) 316 317 # Update the program counter. 318 319 if next_pc is None: 320 self.pc += 1 321 else: 322 self.pc = next_pc 323 324 def get_method(self, instruction): 325 326 "Return the handler method for the given 'instruction'." 327 328 instruction_name = instruction.__class__.__name__ 329 if self.debug: 330 print "%8d %s" % (self.pc, instruction_name) 331 method = getattr(self, instruction_name, None) 332 if method is None: 333 raise IllegalInstruction, (self.pc, instruction_name) 334 return method 335 336 def perform(self, instruction): 337 338 "Perform the 'instruction', returning the next PC value or None." 339 340 self.operand = instruction.get_operand() 341 method = self.get_method(instruction) 342 return method() 343 344 def process_inputs(self): 345 346 """ 347 Process any inputs of the current instruction. This permits any directly 348 connected sub-instructions to produce the effects that separate 349 instructions would otherwise have. 350 """ 351 352 value = self.value 353 if self.instruction.source is not None: 354 self.perform(self.instruction.source) 355 self.source = self.value 356 self.value = value 357 if self.instruction.input is not None: 358 self.perform(self.instruction.input) 359 360 def jump(self, addr, next): 361 362 """ 363 Jump to the subroutine at (or identified by) 'addr'. If 'addr' 364 identifies a library function then invoke the library function and set 365 PC to 'next' afterwards; otherwise, set PC to 'addr'. 366 """ 367 368 # Trap library functions introduced through the use of strings instead 369 # of proper locations. 370 371 if isinstance(addr, str): 372 handler = self.native_functions[addr](self) 373 if handler is None: 374 return next 375 else: 376 return handler 377 else: 378 self.push_pc(self.pc + 1) 379 return addr 380 381 # Instructions. 382 383 def LoadConst(self): 384 self.value = self.operand, self.operand 385 386 def LoadFunction(self): 387 self.value = None, self.operand # context of constant is not interesting 388 389 def LoadName(self): 390 frame = self.local_sp_stack[-1] 391 self.value = self.frame_stack[frame + self.operand] 392 393 def StoreName(self): 394 frame = self.local_sp_stack[-1] 395 self.frame_stack[frame + self.operand] = self.source 396 397 LoadTemp = LoadName 398 399 def StoreTemp(self): 400 frame = self.local_sp_stack[-1] 401 self.frame_stack[frame + self.operand] = self.value 402 403 def LoadAddress(self): 404 # Preserve context (potentially null). 405 self.value = self.load(self.operand) 406 407 def LoadAddressContext(self): 408 context, ref = self.load(self.operand) 409 inst_context, inst_ref = self.value 410 self.value = inst_ref, ref 411 412 def LoadAddressContextCond(self): 413 context, ref = self.load(self.operand) 414 inst_context, inst_ref = self.value 415 self.value = self._LoadAddressContextCond(context, ref, inst_ref) 416 417 def StoreAddress(self): 418 # Preserve context. 419 self.save(self.operand, self.source) 420 421 def StoreAddressContext(self): 422 # Overwrite context if null. 423 context_context, context_ref = self.value 424 source_context, source_ref = self.source 425 if source_context is None: 426 context = context_ref 427 else: 428 context = source_context 429 self.save(self.operand, (context, source_ref)) 430 431 def MakeObject(self): 432 size = self.operand 433 context, ref = self.value 434 # NOTE: Referencing the instance template. 435 addr = self._MakeObject(size, ref - 1) 436 # Introduce object as context for the new object. 437 self.value = addr, addr 438 439 def LoadAttr(self): 440 context, ref = self.value 441 # Retrieved context should already be appropriate for the instance. 442 # NOTE: Adding 1 to skip any header. 443 self.value = self.load(ref + self.operand + 1) 444 445 def StoreAttr(self): 446 context, ref = self.value 447 # Target should already be an instance. 448 # NOTE: Adding 1 to skip any header. 449 self.save(ref + self.operand + 1, self.source) 450 451 def LoadAttrIndex(self): 452 context, ref = self.value 453 data = self.load(ref) 454 element = self.objlist[data.classcode + self.operand] 455 attr_index, class_attr, offset = element 456 if attr_index == self.operand: 457 if class_attr: 458 self.value = self.load(offset) # offset is address of class attribute 459 else: 460 self.value = self.load(ref + offset) 461 else: 462 self.exception = self._MakeObject(2, self.attr_error_instance) 463 return self.RaiseException() 464 465 # LoadAttrIndexContext not defined. 466 467 def LoadAttrIndexContextCond(self): 468 context, ref = self.value 469 data = self.load(ref) 470 element = self.objlist[data.classcode + self.operand] 471 attr_index, class_attr, offset = element 472 if attr_index == self.operand: 473 if class_attr: 474 loaded_context, loaded_ref = self.load(offset) # offset is address of class attribute 475 if data.attrcode is None: # absent attrcode == class 476 self.value = loaded_context, loaded_ref 477 else: 478 self.value = self._LoadAddressContextCond(loaded_context, loaded_ref, ref) 479 else: 480 self.value = self.load(ref + offset) 481 else: 482 self.exception = self._MakeObject(2, self.attr_error_instance) 483 return self.RaiseException() 484 485 def StoreAttrIndex(self): 486 context, ref = self.value 487 data = self.load(ref) 488 element = self.objlist[data.classcode + self.operand] 489 attr_index, class_attr, offset = element 490 if attr_index == self.operand: 491 if class_attr: 492 self.exception = self._MakeObject(2, self.type_error_instance) 493 return self.RaiseException() 494 else: 495 self.save(ref + offset, self.source) 496 else: 497 self.exception = self._MakeObject(2, self.attr_error_instance) 498 return self.RaiseException() 499 500 # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden. 501 502 def MakeFrame(self): 503 self.invocation_sp_stack.append(len(self.frame_stack)) 504 self.frame_stack.extend([None] * self.operand) 505 506 def DropFrame(self): 507 self.local_sp_stack.pop() 508 frame = self.invocation_sp_stack.pop() 509 self.frame_stack = self.frame_stack[:frame] # reset stack before call 510 511 def RecoverFrame(self): 512 self.local_sp_stack.pop() 513 514 def StoreFrame(self): 515 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame 516 self.frame_stack[frame + self.operand] = self.value 517 518 def StoreFrameIndex(self): 519 context, ref = self.value 520 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame 521 data = self.load(ref) 522 element = self.paramlist[data.funccode + self.operand] 523 # NOTE: Need to ensure correct positioning where a context has been generated. 524 param_index, offset = element 525 if param_index == self.operand: 526 self.frame_stack[frame + offset + 1] = self.source # add 1 to skip the context always generated 527 else: 528 self.exception = self._MakeObject(2, self.type_error_instance) 529 return self.RaiseException() 530 531 def LoadCallable(self): 532 context, ref = self.value 533 data = self.load(ref) 534 self.callable = data.codeaddr 535 536 def StoreCallable(self): 537 context, ref = self.value 538 # NOTE: Should improve the representation and permit direct saving. 539 data = self.load(ref) 540 self.save(ref, (data.classcode, data.attrcode) + self.callable) 541 542 def LoadContext(self): 543 context, ref = self.value 544 # NOTE: Omission of the context of the context would make things like 545 # NOTE: self() inside methods impossible. 546 self.value = context, context 547 548 def CheckContext(self): 549 self.status = self.value[1] is not None 550 551 def CheckClassContext(self): 552 context_context, context_ref = self.value 553 context_data = self.load(context_ref) 554 555 # Classes are not themselves usable as the self argument. 556 # NOTE: This may change at some point. 557 # However, where classes appear as the context, instance 558 # compatibility is required in the first argument. 559 560 self.status = context_data.attrcode is None # absent attrcode == class 561 562 def CheckFrame(self): 563 (nargs, ndefaults, has_star) = self.operand 564 565 # The frame is actually installed as the locals. 566 # Retrieve the context from the first local. 567 568 frame = self.local_sp_stack[-1] 569 nlocals = len(self.frame_stack[frame:]) 570 571 if not ((nargs - ndefaults) <= nlocals and (nlocals <= nargs or has_star)): 572 #raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs) 573 self.exception = self._MakeObject(2, self.type_error_instance) 574 return self.RaiseException() 575 576 def FillDefaults(self): 577 # NOTE: Make the get_operand method of the instruction provide the 578 # NOTE: function location. 579 (nargs, ndefaults, fn) = self.operand 580 581 # The frame is actually installed as the locals. 582 583 frame = self.local_sp_stack[-1] 584 nlocals = len(self.frame_stack[frame:]) 585 586 # Support population of defaults. 587 # This involves copying the "attributes" of a function into the frame. 588 589 default = nlocals - (nargs - ndefaults) 590 self.frame_stack.extend([None] * (nargs - nlocals)) 591 pos = nlocals 592 ref = fn.location 593 594 while pos < nargs: 595 self.frame_stack[frame + pos] = self.load(ref + default + 1) # skip header 596 default += 1 597 pos += 1 598 599 def CheckSelf(self): 600 context, ref = self.value 601 target_context, target_ref = self.source 602 603 # Check the details of the proposed context and the target's context. 604 605 self.status = self._CheckInstance(ref, target_context) 606 607 def JumpWithFrame(self): 608 codeaddr = self.callable 609 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame 610 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one 611 612 def JumpWithFrameDirect(self): 613 operand = self.operand 614 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame 615 return self.jump(operand, self.pc + 1) # return to the instruction after this one 616 617 def ExtendFrame(self): 618 self.frame_stack.extend([None] * self.operand) 619 620 def AdjustFrame(self): 621 self.invocation_sp_stack[-1] += self.operand 622 623 def Return(self): 624 return self.pull_pc() 625 626 def LoadResult(self): 627 self.value = self.result 628 629 def StoreResult(self): 630 self.result = self.value 631 632 def Jump(self): 633 return self.operand 634 635 def JumpIfTrue(self): 636 if self.status: 637 return self.operand 638 639 def JumpIfFalse(self): 640 if not self.status: 641 return self.operand 642 643 def LoadException(self): 644 self.value = self.exception, self.exception 645 646 def StoreException(self): 647 self.exception = self.value[1] 648 649 def RaiseException(self): 650 # NOTE: Adding the program counter as the first attribute. 651 self.save(self.exception + 1, self.pc) 652 # Jumping to the current handler. 653 return self.handler_stack[-1] 654 655 def PushHandler(self): 656 self.handler_stack.append(self.operand) 657 self.handler_local_sp_stack.append(len(self.local_sp_stack)) 658 self.handler_pc_stack.append(len(self.pc_stack)) 659 660 def PopHandler(self): 661 # Reduce the local frame pointer stack to refer to the handler's frame. 662 self.local_sp_stack = self.local_sp_stack[:self.handler_local_sp_stack.pop()] 663 # Reduce the PC stack to discard all superfluous return addresses. 664 self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()] 665 self.handler_stack.pop() 666 667 def CheckException(self): 668 self.status = self.exception is not None and self._CheckInstance(self.exception, self.value[1]) 669 670 def TestIdentity(self): 671 self.status = self.value[1] == self.source[1] 672 673 def TestIdentityAddress(self): 674 self.status = self.value[1] == self.operand 675 676 # LoadBoolean is implemented in the generated code. 677 # StoreBoolean is implemented by testing against the True value. 678 679 def InvertBoolean(self): 680 self.status = not self.status 681 682 # Common implementation details. 683 684 def _CheckInstance(self, ref, cls): 685 data = self.load(ref) 686 target_data = self.load(cls) 687 688 # Insist on instance vs. class. 689 690 if data.attrcode is None: # absent attrcode == class 691 return 0 692 693 if target_data.attrcode is not None: # present attrcode == instance 694 return 0 695 696 # Find the table entry for the descendant. 697 698 element = self.objlist[target_data.classcode + data.attrcode] 699 if element is not None: 700 attr_index, class_attr, offset = element 701 return attr_index == data.attrcode 702 else: 703 return 0 704 705 def _MakeObject(self, size, ref): 706 # Load the template. 707 data = self.load(ref) 708 addr = self.new(size) 709 # Save the header, overriding the size. 710 self.save(addr, data.with_size(size)) 711 return addr 712 713 def _LoadAddressContextCond(self, context, ref, inst_ref): 714 715 # Check the instance context against the target's context. 716 717 if self._CheckInstance(inst_ref, context): 718 # Replace the context with the instance. 719 return inst_ref, ref 720 else: 721 return context, ref 722 723 # Native function implementations. 724 725 def builtins_int_add(self): 726 frame = self.local_sp_stack[-1] 727 728 # Get operands addresses. 729 730 left_context, left = self.frame_stack[frame] 731 right_context, right = self.frame_stack[frame + 1] 732 733 # Test operand suitability. 734 735 if not self._CheckInstance(left, self.int_class) and self._CheckInstance(right, self.int_class): 736 self.exception = self._MakeObject(2, self.type_error_instance) 737 return self.RaiseException() 738 739 # NOTE: Assume single location for data. 740 741 left_data = left + 1 742 right_data = right + 1 743 744 # Make a new object. 745 746 addr = self._MakeObject(2, self.int_instance) 747 748 # Store the result. 749 # NOTE: The data is considered ready to use. 750 751 self.save(addr + 1, self.load(left_data) + self.load(right_data)) 752 753 # Return the new object. 754 # Introduce object as context for the new object. 755 756 self.result = addr, addr 757 758 def builtins_int_bool(self): 759 frame = self.local_sp_stack[-1] 760 761 # Get operands addresses. 762 763 left_context, left = self.frame_stack[frame] 764 765 # Test operand suitability. 766 767 if not self._CheckInstance(left, self.int_class): 768 self.exception = self._MakeObject(2, self.type_error_instance) 769 return self.RaiseException() 770 771 # NOTE: Assume single location for data. 772 773 left_data = left + 1 774 775 # Test the data. 776 # NOTE: The data is considered ready to use. 777 778 if self.load(left_data) != 0: 779 self.result = self.true_constant, self.true_constant 780 else: 781 self.result = self.false_constant, self.false_constant 782 783 def builtins_int_neg(self): 784 frame = self.local_sp_stack[-1] 785 786 # Get operands addresses. 787 788 left_context, left = self.frame_stack[frame] 789 790 # Test operand suitability. 791 792 if not self._CheckInstance(left, self.int_class): 793 self.exception = self._MakeObject(2, self.type_error_instance) 794 return self.RaiseException() 795 796 # NOTE: Assume single location for data. 797 798 left_data = left + 1 799 800 # Make a new object. 801 802 addr = self._MakeObject(2, self.int_instance) 803 804 # Store the result. 805 # NOTE: The data is considered ready to use. 806 807 self.save(addr + 1, -self.load(left_data)) 808 809 # Return the new object. 810 # Introduce object as context for the new object. 811 812 self.result = addr, addr 813 814 def builtins_bool_bool(self): 815 frame = self.local_sp_stack[-1] 816 817 # Get operands addresses. 818 819 left_context, left = self.frame_stack[frame] 820 self.result = left, left 821 822 def builtins_list_new(self): 823 frame = self.local_sp_stack[-1] 824 825 # NOTE: Specific copying of tuples/lists. 826 827 args_context, args = self.frame_stack[frame] 828 header = self.load(args) 829 830 list = self._MakeObject(header.size, self.list_instance) 831 for i in range(1, header.size): 832 self.save(list + i, self.load(args + i)) 833 834 self.result = list, list 835 836 def builtins_list_getitem(self): 837 frame = self.local_sp_stack[-1] 838 839 # Get operands addresses. 840 841 obj_context, obj = self.frame_stack[frame] 842 item_context, item = self.frame_stack[frame + 1] 843 844 header = self.load(obj) 845 nelements = header.size - 1 846 847 # NOTE: Assume single location for data. 848 849 item_pos = self.load(item + 1) 850 if item_pos >= 0 and item_pos < nelements: 851 pass 852 elif item_pos < 0 and item_pos >= -nelements: 853 item_pos = nelements + item_pos 854 else: 855 self.exception = self._MakeObject(2, self.index_error_instance) 856 return self.RaiseException() 857 858 self.result = self.load(obj + 1 + item_pos) 859 860 def builtins_object_init(self): 861 pass 862 863 native_functions = { 864 "__builtins__.int.__add__" : builtins_int_add, 865 "__builtins__.int.__bool__" : builtins_int_bool, 866 "__builtins__.int.__neg__" : builtins_int_neg, 867 "__builtins__.bool.__bool__" : builtins_bool_bool, 868 "__builtins__.list" : builtins_list_new, 869 "__builtins__.list.__getitem__" : builtins_list_getitem, 870 "__builtins__.object.__init__" : builtins_object_init, 871 } 872 873 # Convenience functions. 874 875 def machine(program, with_builtins=0, debug=0): 876 print "Making the image..." 877 code = program.get_image(with_builtins) 878 print "Getting raw structures..." 879 ot = program.get_object_table() 880 pt = program.get_parameter_table() 881 objlist = ot.as_list() 882 paramlist = pt.as_list() 883 print "Getting raw image..." 884 rc = program.get_raw_image() 885 print "Initialising the machine..." 886 importer = program.get_importer() 887 true_constant = importer.get_constant(True).location 888 false_constant = importer.get_constant(False).location 889 rm = RSVPMachine(rc, objlist, paramlist, true_constant, false_constant, debug=debug) 890 rm.pc = program.code_location 891 return rm 892 893 # vim: tabstop=4 expandtab shiftwidth=4