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 try: 252 while 1: 253 self.execute() 254 except EmptyPCStack: 255 pass 256 257 print "Execution terminated", 258 if self.exception is not None: 259 context, ref = self.exception 260 print "with exception:", self.load(ref) 261 print "at address:", self.load(ref + 1) 262 else: 263 print "successfully." 264 265 def execute(self): 266 267 "Execute code in the memory at the current PC address." 268 269 if self.pc in self.breakpoints: 270 self.breakpoints.remove(self.pc) 271 raise BreakpointReached 272 273 self.instruction = self.load(self.pc) 274 275 # Process any inputs of the instruction. 276 277 self.process_inputs() 278 279 # Perform the instruction itself. 280 281 next_pc = self.perform(self.instruction) 282 283 # Update the program counter. 284 285 if next_pc is None: 286 self.pc += 1 287 else: 288 self.pc = next_pc 289 290 def get_method(self, instruction): 291 292 "Return the handler method for the given 'instruction'." 293 294 instruction_name = instruction.__class__.__name__ 295 if self.debug: 296 print "%8d %s" % (self.pc, instruction_name) 297 method = getattr(self, instruction_name, None) 298 if method is None: 299 raise IllegalInstruction, (self.pc, instruction_name) 300 return method 301 302 def perform(self, instruction): 303 304 "Perform the 'instruction', returning the next PC value or None." 305 306 self.operand = instruction.get_operand() 307 method = self.get_method(instruction) 308 return method() 309 310 def process_inputs(self): 311 312 """ 313 Process any inputs of the current instruction. This permits any directly 314 connected sub-instructions to produce the effects that separate 315 instructions would otherwise have. 316 """ 317 318 value = self.value 319 if self.instruction.source is not None: 320 self.perform(self.instruction.source) 321 self.source = self.value 322 self.value = value 323 if self.instruction.input is not None: 324 self.perform(self.instruction.input) 325 326 def jump(self, addr, next): 327 328 """ 329 Jump to the subroutine at (or identified by) 'addr'. If 'addr' 330 identifies a library function then invoke the library function and set 331 PC to 'next' afterwards; otherwise, set PC to 'addr'. 332 """ 333 334 # Trap library functions introduced through the use of strings instead 335 # of proper locations. 336 337 if isinstance(addr, str): 338 handler = self.native_functions[addr](self) 339 if handler is None: 340 return next 341 else: 342 return handler 343 else: 344 self.push_pc(self.pc + 1) 345 return addr 346 347 # Instructions. 348 349 def LoadConst(self): 350 self.value = None, self.operand # context of constant is not interesting 351 352 def LoadName(self): 353 frame = self.local_sp_stack[-1] 354 self.value = self.frame_stack[frame + self.operand] 355 356 def StoreName(self): 357 frame = self.local_sp_stack[-1] 358 self.frame_stack[frame + self.operand] = self.source 359 360 LoadTemp = LoadName 361 362 def StoreTemp(self): 363 frame = self.local_sp_stack[-1] 364 self.frame_stack[frame + self.operand] = self.value 365 366 def LoadAddress(self): 367 # Preserve context (potentially null). 368 self.value = self.load(self.operand) 369 370 def LoadAddressContext(self): 371 context, ref = self.load(self.operand) 372 inst_context, inst_ref = self.value 373 self.value = inst_ref, ref 374 375 def LoadAddressContextCond(self): 376 context, ref = self.load(self.operand) 377 inst_context, inst_ref = self.value 378 self.value = self._LoadAddressContextCond(context, ref, inst_context, inst_ref) 379 380 def StoreAddress(self): 381 # Preserve context. 382 self.save(self.operand, self.source) 383 384 def MakeObject(self): 385 size = self.operand 386 context, ref = self.value 387 # NOTE: Referencing the instance template. 388 addr = self._MakeObject(size, ref - 1) 389 # Introduce object as context for the new object. 390 self.value = addr, addr 391 392 def LoadAttr(self): 393 context, ref = self.value 394 # Retrieved context should already be appropriate for the instance. 395 # NOTE: Adding 1 to skip any header. 396 self.value = self.load(ref + self.operand + 1) 397 398 def StoreAttr(self): 399 context, ref = self.value 400 # Target should already be an instance. 401 # NOTE: Adding 1 to skip any header. 402 self.save(ref + self.operand + 1, self.source) 403 404 def LoadAttrIndex(self): 405 context, ref = self.value 406 data = self.load(ref) 407 element = self.objlist[data.classcode + self.operand] 408 attr_index, class_attr, offset = element 409 if attr_index == self.operand: 410 if class_attr: 411 self.value = self.load(offset) # offset is address of class attribute 412 else: 413 self.value = self.load(ref + offset) 414 else: 415 exc = self._MakeObject(2, self.attr_error_instance) 416 self.exception = exc, exc 417 return self.RaiseException() 418 419 def LoadAttrIndexContext(self): 420 context, ref = self.value 421 data = self.load(ref) 422 element = self.objlist[data.classcode + self.operand] 423 attr_index, class_attr, offset = element 424 if attr_index == self.operand: 425 loaded_context, loaded_ref = self.load(offset) # offset is address of class attribute 426 self.value = ref, loaded_ref 427 else: 428 exc = self._MakeObject(2, self.attr_error_instance) 429 self.exception = exc, exc 430 return self.RaiseException() 431 432 def LoadAttrIndexContextCond(self): 433 context, ref = self.value 434 data = self.load(ref) 435 element = self.objlist[data.classcode + self.operand] 436 attr_index, class_attr, offset = element 437 if attr_index == self.operand: 438 if class_attr: 439 loaded_context, loaded_ref = self.load(offset) # offset is address of class attribute 440 self.value = self._LoadAddressContextCond(loaded_context, loaded_ref, context, ref) 441 else: 442 self.value = self.load(ref + offset) 443 else: 444 exc = self._MakeObject(2, self.attr_error_instance) 445 self.exception = exc, exc 446 return self.RaiseException() 447 448 def StoreAttrIndex(self): 449 context, ref = self.value 450 data = self.load(ref) 451 element = self.objlist[data.classcode + self.operand] 452 attr_index, class_attr, offset = element 453 if attr_index == self.operand: 454 if class_attr: 455 exc = self._MakeObject(2, self.type_error_instance) 456 self.exception = exc, exc 457 return self.RaiseException() 458 else: 459 self.save(ref + offset, self.source) 460 else: 461 exc = self._MakeObject(2, self.attr_error_instance) 462 self.exception = exc, exc 463 return self.RaiseException() 464 465 # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden. 466 467 def MakeFrame(self): 468 self.invocation_sp_stack.append(len(self.frame_stack)) 469 self.frame_stack.extend([None] * self.operand) 470 471 def DropFrame(self): 472 self.local_sp_stack.pop() 473 frame = self.invocation_sp_stack.pop() 474 self.frame_stack = self.frame_stack[:frame] # reset stack before call 475 476 def RecoverFrame(self): 477 self.local_sp_stack.pop() 478 479 def StoreFrame(self): 480 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame 481 self.frame_stack[frame + self.operand] = self.value 482 483 def StoreFrameIndex(self): 484 context, ref = self.value 485 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame 486 data = self.load(ref) 487 element = self.paramlist[data.funccode + self.operand] 488 # NOTE: Need to ensure correct positioning where a context has been generated. 489 param_index, offset = element 490 if param_index == self.operand: 491 self.frame_stack[frame + offset + 1] = self.source # add 1 to skip the context always generated 492 else: 493 exc = self._MakeObject(2, self.type_error_instance) 494 self.exception = exc, exc 495 return self.RaiseException() 496 497 def LoadCallable(self): 498 context, ref = self.value 499 data = self.load(ref) 500 self.callable = data.codeaddr 501 502 def StoreCallable(self): 503 context, ref = self.value 504 # NOTE: Should improve the representation and permit direct saving. 505 data = self.load(ref) 506 self.save(ref, (data.classcode, data.attrcode) + self.callable) 507 508 def LoadContext(self): 509 context, ref = self.value 510 # NOTE: Omission of the context of the context would make things like 511 # NOTE: self() inside methods impossible. 512 self.value = context, context 513 514 def CheckFrame(self): 515 (nargs, ndefaults, has_star) = self.operand 516 517 # The frame is actually installed as the locals. 518 # Retrieve the context from the first local. 519 520 frame = self.local_sp_stack[-1] 521 context_context, context_ref = self.frame_stack[frame] # + 0 522 nlocals = len(self.frame_stack[frame:]) 523 524 # Support sliding of the frame to exclude any inappropriate context. 525 # Since a context will always be present when this instruction is being 526 # used (whether or not it is desired), we can always test the nature of 527 # the context. 528 529 if context_ref is None: 530 self.local_sp_stack[-1] += 1 531 nlocals -= 1 532 else: 533 context_data = self.load(context_ref) 534 535 # Classes are not themselves usable as the self argument. 536 # NOTE: This may change at some point. 537 # However, where classes appear as the context, instance 538 # compatibility is required in the first argument. 539 540 if context_data.attrcode is None: # absent attrcode == class 541 542 # Slide the frame to exclude the context. 543 544 self.local_sp_stack[-1] += 1 545 nlocals -= 1 546 547 # Check the context against the first argument. 548 # NOTE: Raise a proper exception here. 549 550 if nlocals > 0: 551 self_context, self_ref = self.frame_stack[frame + 1] 552 if not self._CheckInstance(self_ref, context_context): 553 #raise Exception, "CheckFrame %r (%r vs. %r)" % (self.operand, self.load(self_ref), self.load(context_context)) 554 exc = self._MakeObject(2, self.type_error_instance) 555 self.exception = exc, exc 556 return self.RaiseException() 557 else: 558 #raise Exception, "CheckFrame %r (no self argument)" % self.operand 559 exc = self._MakeObject(2, self.type_error_instance) 560 self.exception = exc, exc 561 return self.RaiseException() 562 563 # Test the frame size. 564 # NOTE: Raise a proper exception here. 565 566 if not ((nargs - ndefaults) <= nlocals and (nlocals <= nargs or has_star)): 567 #raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs) 568 exc = self._MakeObject(2, self.type_error_instance) 569 self.exception = exc, exc 570 return self.RaiseException() 571 572 def FillDefaults(self): 573 # NOTE: Make the get_operand method of the instruction provide the 574 # NOTE: function location. 575 (nargs, ndefaults, fn) = self.operand 576 577 # The frame is actually installed as the locals. 578 579 frame = self.local_sp_stack[-1] 580 nlocals = len(self.frame_stack[frame:]) 581 582 # Support population of defaults. 583 # This involves copying the "attributes" of a function into the frame. 584 585 default = nlocals - (nargs - ndefaults) 586 self.frame_stack.extend([None] * (nargs - nlocals)) 587 pos = nlocals 588 ref = fn.location 589 590 while pos < nargs: 591 self.frame_stack[frame + pos] = self.load(ref + default + 1) # skip header 592 default += 1 593 pos += 1 594 595 def CheckSelf(self): 596 context, ref = self.value 597 target_context, target_ref = self.source 598 599 # Check the details of the proposed context and the target's context. 600 601 self.status = self._CheckInstance(ref, target_context) 602 603 def JumpWithFrame(self): 604 codeaddr = self.callable 605 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame 606 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one 607 608 def JumpWithFrameDirect(self): 609 operand = self.operand 610 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame 611 return self.jump(operand, self.pc + 1) # return to the instruction after this one 612 613 def ExtendFrame(self): 614 self.frame_stack.extend([None] * self.operand) 615 616 def AdjustFrame(self): 617 self.invocation_sp_stack[-1] += self.operand 618 619 def Return(self): 620 return self.pull_pc() 621 622 def LoadResult(self): 623 self.value = self.result 624 625 def StoreResult(self): 626 self.result = self.value 627 628 def Jump(self): 629 return self.operand 630 631 def JumpIfTrue(self): 632 if self.status: 633 return self.operand 634 635 def JumpIfFalse(self): 636 if not self.status: 637 return self.operand 638 639 def LoadException(self): 640 self.value = self.exception, self.exception 641 642 def StoreException(self): 643 self.exception = self.value[1] 644 645 def RaiseException(self): 646 # NOTE: Adding the program counter as the first attribute. 647 self.save(self.exception[1] + 1, self.pc) 648 # Jumping to the current handler. 649 return self.handler_stack[-1] 650 651 def PushHandler(self): 652 self.handler_stack.append(self.operand) 653 self.handler_local_sp_stack.append(len(self.local_sp_stack)) 654 self.handler_pc_stack.append(len(self.pc_stack)) 655 656 def PopHandler(self): 657 # Reduce the local frame pointer stack to refer to the handler's frame. 658 self.local_sp_stack = self.local_sp_stack[:self.handler_local_sp_stack.pop()] 659 # Reduce the PC stack to discard all superfluous return addresses. 660 self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()] 661 self.handler_stack.pop() 662 663 def CheckException(self): 664 self.status = self.exception is not None and self._CheckInstance(self.exception, self.value[1]) 665 666 def TestIdentity(self): 667 self.status = self.value[1] == self.source[1] 668 669 def TestIdentityAddress(self): 670 self.status = self.value[1] == self.operand 671 672 # LoadBoolean is implemented in the generated code. 673 # StoreBoolean is implemented by testing against the True value. 674 675 def InvertBoolean(self): 676 self.status = not self.status 677 678 # Common implementation details. 679 680 def _CheckInstance(self, ref, cls): 681 data = self.load(ref) 682 target_data = self.load(cls) 683 684 # Insist on a class. 685 686 if target_data.attrcode is not None: # present attrcode == instance 687 return 0 688 689 # Find the table entry for the descendant. 690 691 element = self.objlist[target_data.classcode + data.attrcode] 692 if element is not None: 693 attr_index, class_attr, offset = element 694 return attr_index == data.attrcode 695 else: 696 return 0 697 698 def _MakeObject(self, size, ref): 699 # Load the template. 700 data = self.load(ref) 701 addr = self.new(size) 702 # Save the header, overriding the size. 703 self.save(addr, data.with_size(size)) 704 return addr 705 706 def _LoadAddressContextCond(self, context, ref, inst_context, inst_ref): 707 708 # Check the instance context against the target's context. 709 710 if self._CheckInstance(inst_ref, context): 711 # Replace the context with the instance. 712 return inst_ref, ref 713 else: 714 return context, ref 715 716 # Native function implementations. 717 718 def builtins_int_add(self): 719 frame = self.local_sp_stack[-1] 720 721 # Get operands addresses. 722 723 left_context, left = self.frame_stack[frame] 724 right_context, right = self.frame_stack[frame + 1] 725 726 # Test operand suitability. 727 728 if not self._CheckInstance(left, self.int_class) and self._CheckInstance(right, self.int_class): 729 exc = self._MakeObject(2, self.type_error_instance) 730 self.exception = exc, exc 731 return self.RaiseException() 732 733 # NOTE: Assume single location for data. 734 735 left_data = left + 1 736 right_data = right + 1 737 738 # Make a new object. 739 740 addr = self._MakeObject(2, self.int_instance) 741 742 # Store the result. 743 # NOTE: The data is considered ready to use. 744 745 self.save(addr + 1, self.load(left_data) + self.load(right_data)) 746 747 # Return the new object. 748 # Introduce object as context for the new object. 749 750 self.result = addr, addr 751 752 def builtins_int_bool(self): 753 frame = self.local_sp_stack[-1] 754 755 # Get operands addresses. 756 757 left_context, left = self.frame_stack[frame] 758 759 # Test operand suitability. 760 761 if not self._CheckInstance(left, self.int_class): 762 exc = self._MakeObject(2, self.type_error_instance) 763 self.exception = exc, exc 764 return self.RaiseException() 765 766 # NOTE: Assume single location for data. 767 768 left_data = left + 1 769 770 # Test the data. 771 # NOTE: The data is considered ready to use. 772 773 if self.load(left_data) != 0: 774 self.result = self.true_constant, self.true_constant 775 else: 776 self.result = self.false_constant, self.false_constant 777 778 def builtins_int_neg(self): 779 frame = self.local_sp_stack[-1] 780 781 # Get operands addresses. 782 783 left_context, left = self.frame_stack[frame] 784 785 # Test operand suitability. 786 787 if not self._CheckInstance(left, self.int_class): 788 exc = self._MakeObject(2, self.type_error_instance) 789 self.exception = exc, exc 790 return self.RaiseException() 791 792 # NOTE: Assume single location for data. 793 794 left_data = left + 1 795 796 # Make a new object. 797 798 addr = self._MakeObject(2, self.int_instance) 799 800 # Store the result. 801 # NOTE: The data is considered ready to use. 802 803 self.save(addr + 1, -self.load(left_data)) 804 805 # Return the new object. 806 # Introduce object as context for the new object. 807 808 self.result = addr, addr 809 810 def builtins_bool_bool(self): 811 frame = self.local_sp_stack[-1] 812 813 # Get operands addresses. 814 815 left_context, left = self.frame_stack[frame] 816 self.result = left, left 817 818 def builtins_list_new(self): 819 frame = self.local_sp_stack[-1] 820 821 # NOTE: Specific copying of tuples/lists. 822 823 args_context, args = self.frame_stack[frame] 824 header = self.load(args) 825 826 list = self._MakeObject(header.size, self.list_instance) 827 for i in range(1, header.size): 828 self.save(list + i, self.load(args + i)) 829 830 self.result = list, list 831 832 def builtins_list_getitem(self): 833 frame = self.local_sp_stack[-1] 834 835 # Get operands addresses. 836 837 obj_context, obj = self.frame_stack[frame] 838 item_context, item = self.frame_stack[frame + 1] 839 840 header = self.load(obj) 841 nelements = header.size - 1 842 843 # NOTE: Assume single location for data. 844 845 item_pos = self.load(item + 1) 846 if item_pos >= 0 and item_pos < nelements: 847 pass 848 elif item_pos < 0 and item_pos >= -nelements: 849 item_pos = nelements + item_pos 850 else: 851 exc = self._MakeObject(2, self.index_error_instance) 852 self.exception = exc, exc 853 return self.RaiseException() 854 855 self.result = self.load(obj + 1 + item_pos) 856 857 def builtins_object_init(self): 858 pass 859 860 native_functions = { 861 "__builtins__.int.__add__" : builtins_int_add, 862 "__builtins__.int.__bool__" : builtins_int_bool, 863 "__builtins__.int.__neg__" : builtins_int_neg, 864 "__builtins__.bool.__bool__" : builtins_bool_bool, 865 "__builtins__.list" : builtins_list_new, 866 "__builtins__.list.__getitem__" : builtins_list_getitem, 867 "__builtins__.object.__init__" : builtins_object_init, 868 } 869 870 # vim: tabstop=4 expandtab shiftwidth=4