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