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