micropython

rsvp.py

397:7cc5058cbfb6
2011-02-20 Paul Boddie Fixed __class__ to always be at instance attribute position 0, thus matching its class attribute position. Added notes about the __class__ attribute, its definition in the object table, and the copying of the attribute from instance templates upon instantiation.
     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, 2010, 2011 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 DataValue, ReplaceableContext, PlaceholderContext, FragmentObject    56 from rsvplib import Library    57     58 class IllegalInstruction(Exception):    59     pass    60     61 class IllegalAddress(Exception):    62     def __init__(self, address):    63         self.address = address    64     def __repr__(self):    65         return "IllegalAddress(%r)" % self.address    66     def __str__(self):    67         return repr(self)    68     69 class EmptyPCStack(Exception):    70     pass    71     72 class EmptyFrameStack(Exception):    73     pass    74     75 class BreakpointReached(Exception):    76     pass    77     78 class RSVPMachine:    79     80     "A really simple virtual processor."    81     82     def __init__(self, memory, objlist, paramlist, pc=None, debug=0, abort_upon_exception=0):    83     84         """    85         Initialise the processor with a 'memory' (a list of values containing    86         instructions and data), the object and parameter lists 'objlist' and    87         'paramlist', and the 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.library = None    96     97         self.pc = pc or 0    98         self.debug = debug    99         self.abort_upon_exception = abort_upon_exception   100    101         # Profiling.   102    103         self.coverage = [0] * len(self.memory)   104         self.counter = 0   105         self.cost = 0   106    107         # Stacks.   108    109         self.pc_stack = []   110         self.frame_stack = []   111         self.local_sp_stack = [0]   112         self.invocation_sp_stack = []   113         self.handler_stack = [len(self.memory) - 1] # final handler is the end of the code   114         self.handler_local_sp_stack = []   115         self.handler_pc_stack = []   116    117         # Registers.   118    119         self.instruction = None   120         self.operand = None   121         self.value = None   122         self.status = None   123         self.source = None   124         self.callable = None   125         self.result = None   126         self.exception = None   127    128         # Constants.   129    130         cls = self._get_class("__builtins__", "AttributeError")   131         self.attr_error = cls.location   132         self.attr_error_instance = cls.instance_template_location   133         cls = self._get_class("__builtins__", "TypeError")   134         self.type_error = cls.location   135         self.type_error_instance = cls.instance_template_location   136         cls = self._get_class("__builtins__", "tuple")   137         self.tuple_class = cls.location   138         self.tuple_instance = cls.instance_template_location   139    140         # Debugging attributes.   141    142         self.breakpoints = set()   143    144     def _get_class(self, module, name):   145         attr = self._objlist.access(module, name)   146         if attr is not None:   147             return attr.get_value()   148         else:   149             return None   150    151     # Debugging methods.   152    153     def dump(self):   154         print "PC", self.pc, "->", self.load(self.pc)   155         print "PC stack", self.pc_stack   156         print "Frame stack", self.frame_stack   157         print "Local stack pointers", self.local_sp_stack   158         print "Invocation stack pointers", self.invocation_sp_stack   159         print "Handler stack", self.handler_stack   160         print "Handler frame stack", self.handler_local_sp_stack   161         print "Handler PC stack", self.handler_pc_stack   162         print   163         print "Instruction", self.instruction   164         print "Operand", self.operand   165         print "Value", self.value   166         print "Status", self.status   167         print "Source", self.source   168         print "Callable", self.callable   169         print "Result", self.result   170         print "Exception", self.exception   171    172     def show(self):   173         self.show_memory(self.memory, self.coverage, 0)   174    175     def show_pc(self, run_in=10):   176         start = max(0, self.pc - run_in)   177         end = self.pc + run_in   178         memory = self.memory[start:end]   179         coverage = self.coverage[start:end]   180         self.show_memory(memory, coverage, start)   181    182     def show_memory(self, memory, coverage, start):   183         for i, (c, x) in enumerate(map(None, coverage, memory)):   184             location = start + i   185             if location == self.pc:   186                 print "->",   187             elif location in self.pc_stack:   188                 print "..",   189             else:   190                 print "  ",   191             print "%-5s %5d %r" % (c or "", location, x)   192    193     def step(self, dump=0):   194         self.execute()   195         self.show_pc()   196         if dump:   197             self.dump()   198    199     def set_break(self, location):   200         self.breakpoints.add(location)   201    202     # Internal operations.   203    204     def load(self, address):   205    206         "Return the value at the given 'address'."   207    208         try:   209             return self.memory[address]   210         except IndexError:   211             raise IllegalAddress(address)   212         except TypeError:   213             raise IllegalAddress(address)   214    215     def save(self, address, value):   216    217         "Save to the given 'address' the specified 'value'."   218    219         try:   220             self.memory[address] = value   221         except IndexError:   222             raise IllegalAddress(address)   223         except TypeError:   224             raise IllegalAddress(address)   225    226     def new(self, size):   227    228         """   229         Allocate space of the given 'size', returning the address of the space.   230         """   231    232         addr = len(self.memory)   233         for i in range(0, size):   234             self.memory.append(None)   235         return addr   236    237     def push_pc(self, data):   238    239         "Push 'data' onto the PC stack."   240    241         self.pc_stack.append(data)   242    243     def pull_pc(self):   244    245         "Pull a value from the PC stack and return it."   246    247         try:   248             return self.pc_stack.pop()   249         except IndexError:   250             raise EmptyPCStack   251    252     def run(self):   253    254         "Execute code in the memory, starting from the current PC address."   255    256         breakpoint = 0   257    258         try:   259             while 1:   260                 self.execute()   261         except EmptyPCStack:   262             pass   263         except BreakpointReached:   264             breakpoint = 1   265    266         print "Execution terminated",   267         if self.exception is not None:   268             ref = self.exception   269             addr = self.load(ref + 1)   270             print "with exception:", self.load(ref)   271             print "At address %d: %r" % (addr, self.load(addr))   272         elif breakpoint:   273             print "with breakpoint."   274             print "At address", self.pc   275         else:   276             print "successfully."   277         print "After", self.counter, "instructions at cost", self.cost, "units."   278    279     def test(self, module):   280    281         """   282         Test the code in the memory by running the code and investigating the   283         contents of variables. Use 'module' to identify result variables.   284         """   285    286         self.run()   287         success = 1   288    289         if self.exception is None:   290             for name in module.keys():   291                 if name.startswith("result"):   292                     label, expected = name.split("_")   293                     attr = module[name]   294    295                     # NOTE: Assumptions about headers and content made.   296    297                     attr_location = module.location + 1 + attr.position   298                     value = self.load(attr_location)   299    300                     if value is not None:   301                         content = self.load(value.ref + Library.instance_data_offset)   302                         print label, expected, content   303                         success = success and (int(expected) == content)   304                     else:   305                         print label, expected, "missing"   306                         success = 0   307    308             return success   309         else:   310             return 0   311    312     def execute(self):   313    314         "Execute code in the memory at the current PC address."   315    316         if self.pc in self.breakpoints:   317             self.breakpoints.remove(self.pc)   318             raise BreakpointReached   319    320         self.instruction = self.load(self.pc)   321    322         # Process any inputs of the instruction.   323    324         self.process_inputs()   325    326         # Perform the instruction itself.   327    328         next_pc = self.perform(self.instruction)   329    330         # Update the coverage.   331    332         self.coverage[self.pc] += 1   333    334         # Update the program counter.   335    336         if next_pc is None:   337             self.pc += 1   338         else:   339             self.pc = next_pc   340    341     def get_method(self, instruction):   342    343         "Return the handler method for the given 'instruction'."   344    345         instruction_name = instruction.__class__.__name__   346         if self.debug:   347             print "%8d %s" % (self.pc, instruction_name)   348         method = getattr(self, instruction_name, None)   349         if method is None:   350             raise IllegalInstruction, (self.pc, instruction_name)   351         return method   352    353     def perform(self, instruction, is_input=0):   354    355         "Perform the 'instruction', returning the next PC value or None."   356    357         if not is_input:   358             self.counter += 1   359             self.cost += instruction.cost   360         self.operand = instruction.get_operand()   361         method = self.get_method(instruction)   362         return method()   363    364     def process_inputs(self):   365    366         """   367         Process any inputs of the current instruction. This permits any directly   368         connected sub-instructions to produce the effects that separate   369         instructions would otherwise have.   370         """   371    372         value = self.value   373         if self.instruction.source is not None:   374             self.perform(self.instruction.source, 1)   375             self.source = self.value   376         self.value = value   377         if self.instruction.input is not None:   378             self.perform(self.instruction.input, 1)   379    380     def jump(self, addr, next):   381    382         """   383         Jump to the subroutine at (or identified by) 'addr'. If 'addr'   384         identifies a library function then invoke the library function and set   385         PC to 'next' afterwards; otherwise, set PC to 'addr'.   386         """   387    388         # Trap library functions introduced through the use of strings instead   389         # of proper locations.   390    391         if isinstance(addr, str):   392             handler = self.library and self.library.native_functions[addr](self.library)   393             if handler is None:   394                 return next   395             else:   396                 return handler   397         else:   398             self.push_pc(self.pc + 1)   399             return addr   400    401     # Instructions.   402    403     def LoadConst(self):   404         self.value = DataValue(self.operand, self.operand)   405    406     def LoadClass(self):   407         self.value = DataValue(PlaceholderContext, self.operand)   408    409     def LoadFunction(self):   410         self.value = DataValue(ReplaceableContext, self.operand)   411    412     def LoadName(self):   413         frame = self.local_sp_stack[-1]   414         self.value = self.frame_stack[frame + self.operand]   415    416     def StoreName(self):   417         frame = self.local_sp_stack[-1]   418         self.frame_stack[frame + self.operand] = self.source # uses the source value   419    420     LoadTemp = LoadName   421    422     def StoreTemp(self):   423         frame = self.local_sp_stack[-1]   424         self.frame_stack[frame + self.operand] = self.value   425    426     def LoadAddress(self):   427         # Preserve context (potentially null).   428         self.value = self.load(self.operand)   429    430     def LoadAddressContext(self):   431         value = self.load(self.operand)   432         inst_value = self.value   433         self.value = DataValue(inst_value.ref, value.ref)   434    435     def LoadAddressContextCond(self):   436         value = self.load(self.operand)   437         inst_value = self.value   438         self.value = self._LoadAddressContextCond(value.context, value.ref, inst_value.ref)   439    440     def StoreAddress(self):   441         # Preserve context.   442         self.save(self.operand, self.source)   443    444     def StoreAddressContext(self):   445         # Overwrite context if null.   446         context_value = self.value   447         source_value = self.source   448         if source_value.context is ReplaceableContext:   449             context = context_value.ref   450         else:   451             context = source_value.context   452         self.save(self.operand, DataValue(context, source_value.ref))   453    454     def MakeInstance(self):   455         size = self.operand   456         value = self.value   457         # NOTE: Referencing the instance template.   458         addr = self._MakeObject(size, value.ref - 2)   459         # Introduce object as context for the new object.   460         self.value = DataValue(addr, addr)   461    462     def MakeFragment(self):   463         size = self.operand   464         # Reserve twice the amount of space.   465         addr = self._MakeFragment(size, size * 2)   466         # NOTE: Context is not relevant for fragments.   467         self.value = DataValue(None, addr)   468    469     def LoadAttr(self):   470         value = self.value   471         # Retrieved context should already be appropriate for the instance.   472         # NOTE: Adding 1 to skip any header.   473         self.value = self.load(value.ref + self.operand + 1)   474    475     def StoreAttr(self):   476         value = self.value   477         # Target should already be an instance.   478         # NOTE: Adding 1 to skip any header.   479         self.save(value.ref + self.operand + 1, self.source)   480    481     def LoadAttrIndex(self):   482         value = self.value   483         data = self.load(value.ref)   484         element = self.objlist[data.classcode + self.operand]   485    486         if element is not None:   487             attr_index, static_attr, offset = element   488             if attr_index == self.operand:   489                 if static_attr:   490                     self.value = self.load(offset) # offset is address of class/module attribute   491                 else:   492                     self.value = self.load(value.ref + offset)   493                 return   494    495         self.exception = self._MakeObject(2, self.attr_error_instance)   496         return self.RaiseException()   497    498     # LoadAttrIndexContext not defined.   499    500     def LoadAttrIndexContextCond(self):   501         inst_value = self.value   502         data = self.load(inst_value.ref)   503         element = self.objlist[data.classcode + self.operand]   504    505         if element is not None:   506             attr_index, static_attr, offset = element   507             if attr_index == self.operand:   508                 if static_attr:   509                     loaded_value = self.load(offset) # offset is address of class/module attribute   510                     if data.attrcode is None: # absent attrcode == class/module   511                         self.value = loaded_value   512                     else:   513                         self.value = self._LoadAddressContextCond(loaded_value.context, loaded_value.ref, inst_value.ref)   514                 else:   515                     self.value = self.load(inst_value.ref + offset)   516                 return   517    518         self.exception = self._MakeObject(2, self.attr_error_instance)   519         return self.RaiseException()   520    521     def StoreAttrIndex(self):   522         value = self.value   523         data = self.load(value.ref)   524         element = self.objlist[data.classcode + self.operand]   525    526         if element is not None:   527             attr_index, static_attr, offset = element   528             if attr_index == self.operand:   529                 if static_attr:   530                     self.exception = self._MakeObject(2, self.type_error_instance)   531                     return self.RaiseException()   532                 else:   533                     self.save(value.ref + offset, self.source)   534                     return   535    536         self.exception = self._MakeObject(2, self.attr_error_instance)   537         return self.RaiseException()   538    539     # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden.   540    541     def MakeFrame(self):   542         self.invocation_sp_stack.append(len(self.frame_stack))   543         self.frame_stack.extend([None] * self.operand)   544    545     def DropFrame(self):   546         self.local_sp_stack.pop()   547         frame = self.invocation_sp_stack.pop()   548         del self.frame_stack[frame:] # reset stack before call   549    550     def StoreFrame(self):   551         frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame   552         self.frame_stack[frame + self.operand] = self.value   553    554     def StoreFrameIndex(self):   555         value = self.value   556         frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame   557         data = self.load(value.ref)   558         element = self.paramlist[data.funccode + self.operand]   559    560         if element is not None:   561             # NOTE: Need to ensure correct positioning where a context has been generated.   562             param_index, offset = element   563             if param_index == self.operand:   564                 self.frame_stack[frame + offset] = self.source   565                 return   566    567         self.exception = self._MakeObject(2, self.type_error_instance)   568         return self.RaiseException()   569    570     def LoadCallable(self):   571         value = self.value   572         data = self.load(value.ref)   573         self.callable = data.codeaddr   574    575     def StoreCallable(self):   576         value = self.value   577         # NOTE: Should improve the representation and permit direct saving.   578         data = self.load(value.ref)   579         self.save(value.ref, data.with_callable(self.callable))   580    581     def LoadContext(self):   582         value = self.value   583         # NOTE: Omission of the context of the context would make things like   584         # NOTE: self() inside methods impossible.   585         self.value = DataValue(value.context, value.context)   586    587     def CheckContext(self):   588         self.status = self.value.ref is not ReplaceableContext   589    590     def CheckClass(self):   591         value = self.value   592         if value.ref in (ReplaceableContext, PlaceholderContext):   593             self.status = 0   594             return   595    596         data = self.load(value.ref)   597    598         # Classes are not themselves usable as the self argument.   599         # NOTE: This may change at some point.   600         # However, where classes appear as the context, instance   601         # compatibility is required in the first argument.   602    603         self.status = data.attrcode is None # absent attrcode == class   604    605     def CheckFrame(self):   606         (nargs, ndefaults) = self.operand   607    608         # The frame is actually installed as the locals.   609         # Retrieve the context from the first local.   610    611         frame = self.local_sp_stack[-1]   612         nlocals = len(self.frame_stack[frame:])   613    614         if not ((nargs - ndefaults) <= nlocals):   615             raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs)   616             self.exception = self._MakeObject(2, self.type_error_instance)   617             return self.RaiseException()   618    619     def CheckExtra(self):   620         nargs = self.operand   621    622         # The frame is actually installed as the locals.   623         # Retrieve the context from the first local.   624    625         frame = self.local_sp_stack[-1]   626         nlocals = len(self.frame_stack[frame:])   627    628         # Provide the extra star parameter if necessary.   629    630         if nlocals == nargs:   631             self.frame_stack.extend([None]) # ExtendFrame(1)   632    633     def FillDefaults(self):   634         value = self.value   635         (nargs, ndefaults) = self.operand   636    637         # The frame is actually installed as the locals.   638    639         frame = self.local_sp_stack[-1]   640         nlocals = len(self.frame_stack[frame:])   641    642         # Support population of defaults.   643         # This involves copying the "attributes" of a function into the frame.   644    645         default = nlocals - (nargs - ndefaults)   646         self.frame_stack.extend([None] * (nargs - nlocals))   647         pos = nlocals   648    649         while pos < nargs:   650             self.frame_stack[frame + pos] = self.load(value.ref + default + 1) # skip header   651             default += 1   652             pos += 1   653    654     def CopyExtra(self):   655         start = self.operand   656    657         # The frame is the source of the extra arguments.   658    659         frame = self.local_sp_stack[-1]   660         nlocals = len(self.frame_stack[frame:])   661    662         # Make a tuple to hold the arguments.   663    664         ref = self._MakeObject(nlocals - start + 1, self.tuple_instance)   665    666         extra = 0   667         pos = start   668    669         while pos < nlocals:   670             self.save(ref + extra + 1, self.frame_stack[frame + pos]) # skip header when storing   671             extra += 1   672             pos += 1   673    674         self.value = DataValue(ref, ref)   675    676     def CheckInstance(self):   677         value = self.value   678         target_value = self.source   679    680         # For the 'self' parameter in an invoked function, the proposed context   681         # ('self') is checked against the target's context.   682    683         self.status = self._CheckInstance(value.ref, target_value.ref)   684    685     def CheckType(self):   686         value = self.value   687         target_value = self.operand   688         self.status = self._CheckType(value.ref, target_value.ref)   689    690     def JumpInFrame(self):   691         codeaddr = self.callable   692         return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one   693    694     def JumpWithFrame(self):   695         codeaddr = self.callable   696         self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame   697         return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one   698    699     def JumpWithFrameDirect(self):   700         operand = self.operand   701         self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame   702         return self.jump(operand, self.pc + 1) # return to the instruction after this one   703    704     def ExtendFrame(self):   705         self.frame_stack.extend([None] * self.operand)   706    707     def AdjustFrame(self):   708         self.invocation_sp_stack[-1] += self.operand   709    710     def Return(self):   711         return self.pull_pc()   712    713     def LoadResult(self):   714         self.value = self.result   715    716     def StoreResult(self):   717         self.result = self.value   718    719     def Jump(self):   720         return self.operand   721    722     def JumpIfTrue(self):   723         if self.status:   724             return self.operand   725    726     def JumpIfFalse(self):   727         if not self.status:   728             return self.operand   729    730     def LoadException(self):   731         self.value = DataValue(self.exception, self.exception)   732    733     def StoreException(self):   734         self.exception = self.value.ref   735    736     def ClearException(self):   737         self.exception = None   738    739     def RaiseException(self):   740         # NOTE: Adding the program counter as the first attribute.   741         self.save(self.exception + 1, self.pc)   742         # Jumping to the current handler.   743         if self.abort_upon_exception:   744             raise Exception   745         return self.handler_stack[-1]   746    747     def PushHandler(self):   748         self.handler_stack.append(self.operand)   749         self.handler_local_sp_stack.append(len(self.local_sp_stack))   750         self.handler_pc_stack.append(len(self.pc_stack))   751    752     def PopHandler(self):   753         # Reduce the local frame pointer stack to refer to the handler's frame.   754         del self.local_sp_stack[self.handler_local_sp_stack.pop():]   755         # Reduce the PC stack to discard all superfluous return addresses.   756         self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()]   757         self.handler_stack.pop()   758    759     def CheckException(self):   760         self.status = self.exception is not None and self._CheckInstance(self.exception, self.value.ref)   761    762     def TestIdentity(self):   763         self.status = self.value.ref == self.source.ref   764    765     def TestIdentityAddress(self):   766         self.status = self.value.ref == self.operand   767    768     # LoadBoolean is implemented in the generated code.   769     # StoreBoolean is implemented by testing against the True value.   770    771     def InvertBoolean(self):   772         self.status = not self.status   773    774     # Common implementation details.   775    776     def _CheckInstance(self, ref, cls):   777         data = self.load(ref)   778         target_data = self.load(cls)   779    780         # Insist on instance vs. class.   781    782         if data.attrcode is None: # absent attrcode == class/module   783             return 0   784    785         if target_data.attrcode is not None: # present attrcode == instance   786             return 0   787    788         # Find the table entry for the descendant.   789    790         element = self.objlist[target_data.classcode + data.attrcode]   791    792         if element is not None:   793             attr_index, static_attr, offset = element   794             return attr_index == data.attrcode   795         else:   796             return 0   797    798     def _CheckType(self, ref, cls):   799         data = self.load(ref)   800         target_data = self.load(cls)   801    802         # Insist on instance vs. class.   803    804         if data.attrcode is None: # absent attrcode == class/module   805             return 0   806    807         if target_data.attrcode is not None: # present attrcode == instance   808             return 0   809    810         # Return whether the types match.   811    812         return data.classcode == target_data.classcode   813    814     def _MakeObject(self, size, ref):   815         # Load the template.   816         data = self.load(ref)   817         addr = self.new(size)   818         # Save the header, overriding the size.   819         self.save(addr, data.with_size(size))   820         # Copy the __class__ attribute.   821         cls_attr = self.load(ref + 1)   822         self.save(addr + 1, cls_attr)   823         return addr   824    825     def _MakeFragment(self, occupied, size):   826         addr = self.new(size)   827         # Save the header, overriding the size.   828         self.save(addr, FragmentObject(occupied, size))   829         return addr   830    831     def _LoadAddressContextCond(self, context, ref, inst_ref):   832         # Check the instance context against the target's context.   833         # This provides the context overriding for methods.   834         if context is ReplaceableContext or context is not PlaceholderContext and self._CheckInstance(inst_ref, context):   835             # Replace the context with the instance.   836             return DataValue(inst_ref, ref)   837         else:   838             return DataValue(context, ref)   839    840 # Convenience functions.   841    842 def machine(program, with_builtins=0, debug=0, abort_upon_exception=0):   843     print "Making the image..."   844     code = program.get_image(with_builtins)   845     print "Getting raw structures..."   846     ot = program.get_object_table()   847     pt = program.get_parameter_table()   848     objlist = ot.as_list()   849     paramlist = pt.as_list()   850     print "Getting raw image..."   851     rc = program.get_raw_image()   852     print "Initialising the machine..."   853     importer = program.get_importer()   854     constants = {}   855     for x in (True, False, NotImplemented):   856         constants[x] = importer.get_constant(x).location   857     rm = RSVPMachine(rc, objlist, paramlist, debug=debug, abort_upon_exception=abort_upon_exception)   858     library = Library(rm, constants)   859     rm.library = library   860     rm.pc = program.code_location   861     print "Returning program occupying %d locations." % len(rm.memory)   862     return rm   863    864 # vim: tabstop=4 expandtab shiftwidth=4