from __future__ import print_function from som.interpreter.interpreter import Interpreter from som.interpreter.bytecodes import Bytecodes from som.vm.symbol_table import SymbolTable from som.vmobjects.object import Object from som.vmobjects.clazz import Class from som.vmobjects.array import Array from som.vmobjects.symbol import Symbol from som.vmobjects.method import Method from som.vmobjects.integer import Integer from som.vmobjects.string import String import som.compiler.sourcecode_compiler as sourcecode_compiler import os import sys class Universe(object): def __init__(self): self._interpreter = Interpreter(self) self._symbol_table = SymbolTable() self._globals = {} self._nilObject = None self._trueObject = None self._falseObject = None self._objectClass = None self._classClass = None self._metaclassClass = None self._nilClass = None self._integerClass = None self._bigintegerClass= None self._arrayClass = None self._methodClass = None self._symbolClass = None self._frameClass = None self._primitiveClass = None self._systemClass = None self._blockClass = None self._doubleClass = None self._last_exit_code = 0 self._classpath = None self._dump_bytecodes = False @property def nilObject(self): return self._nilObject @property def primitiveClass(self): return self._primitiveClass def _create_bootstrap_method(self): # Create a fake bootstrap method to simplify later frame traversal bootstrap_method = self.new_method(self.symbol_for("bootstrap"), 1, 0) bootstrap_method.set_bytecode(0, Bytecodes.halt) bootstrap_method.set_number_of_locals(self.new_integer(0)) bootstrap_method.set_maximum_number_of_stack_elements(self.new_integer(2)) bootstrap_method.set_holder(self._systemClass) def interpret(self, arguments): # Check for command line switches arguments = self.handle_arguments(arguments) # Initialize the known universe self.initialize(arguments) self.start() def handle_arguments(self, arguments): got_classpath = False remaining_args = [] i = 0 while i < len(arguments): if arguments[i] == "-cp": if i + 1 >= len(arguments): self._print_usage_and_exit() self.setup_classpath(arguments[i + 1]) i += 1 # skip class path got_classpath = True elif arguments[i] == "-d": self._dump_bytecodes = True else: remaining_args.append(arguments[i]) i += 1 if not got_classpath: # Get the default class path of the appropriate size self._classpath = self._setup_default_classpath() # check remaining args for class paths, and strip file extension i = 0 while i < len(remaining_args): split = self._get_path_class_ext(remaining_args[i]) if split[0] != "": # there was a path self._classpath.insert(0, split[0]) remaining_args[i] = split[1] i += 1 return remaining_args def setup_classpath(self, cp): self._classpath = cp.split(os.pathsep) def _setup_default_classpath(self): return ['.'] # take argument of the form "../foo/Test.som" and return # "../foo", "Test", "som" def _get_path_class_ext(self, path): (path, file_name) = os.path.split(path) (file_name, ext) = os.path.splitext(file_name) return (path, file_name, ext[1:]) def _initialize_object_system(self): # Allocate the nil object self._nilObject = Object(None) # Allocate the Metaclass classes self._metaclassClass = self.new_metaclass_class() # Allocate the rest of the system classes self._objectClass = self.new_system_class() self._nilClass = self.new_system_class() self._classClass = self.new_system_class() self._arrayClass = self.new_system_class() self._symbolClass = self.new_system_class() self._methodClass = self.new_system_class() self._integerClass = self.new_system_class() self._bigintegerClass = self.new_system_class() self._frameClass = self.new_system_class() self._primitiveClass = self.new_system_class() self._stringClass = self.new_system_class() self._doubleClass = self.new_system_class() # Setup the class reference for the nil object self._nilObject.set_class(self._nilClass) # Initialize the system classes self._initialize_system_class(self._objectClass, None, "Object") self._initialize_system_class(self._classClass, self._objectClass, "Class") self._initialize_system_class(self._metaclassClass, self._classClass, "Metaclass") self._initialize_system_class(self._nilClass, self._objectClass, "Nil") self._initialize_system_class(self._arrayClass, self._objectClass, "Array") self._initialize_system_class(self._methodClass, self._arrayClass, "Method") self._initialize_system_class(self._symbolClass, self._objectClass, "Symbol") self._initialize_system_class(self._integerClass, self._objectClass, "Integer") self._initialize_system_class(self._bigintegerClass, self._objectClass, "BigInteger") self._initialize_system_class(self._frameClass, self._arrayClass, "Frame") self._initialize_system_class(self._primitiveClass, self._objectClass, "Primitive") self._initialize_system_class(self._stringClass, self._objectClass, "String") self._initialize_system_class(self._doubleClass, self._objectClass, "Double") # Load methods and fields into the system classes self._load_system_class(self._objectClass) self._load_system_class(self._classClass) self._load_system_class(self._metaclassClass) self._load_system_class(self._nilClass) self._load_system_class(self._arrayClass) self._load_system_class(self._methodClass) self._load_system_class(self._symbolClass) self._load_system_class(self._integerClass) self._load_system_class(self._bigintegerClass) self._load_system_class(self._frameClass) self._load_system_class(self._primitiveClass) self._load_system_class(self._stringClass) self._load_system_class(self._doubleClass) # Load the generic block class self._blockClass = self._load_class(self._symbol_for("Block")) # Setup the true and false objects self._trueObject = self._new_instance(self._load_class(self.symbol_for("True"))) self._falseObject = self._new_instance(self._load_class(self.symbol_for("False"))) # Load the system class and create an instance of it self._systemClass = self._load_class(self.symbol_for("System")) system_object = self._new_instance(self._systemClass) # Put special objects and classes into the dictionary of globals self.set_global(self.symbol_for("nil"), self._nilObject) self.set_global(self.symbol_for("true"), self._trueObject) self.set_global(self.symbol_for("false"), self._falseObject) self.set_global(self.symbol_for("system"), self._systemObject) self.set_global(self.symbol_for("System"), self._systemClass) self.set_global(self.symbol_for("Block"), self._blockClass) return system_object def symbol_for(self, string): # Lookup the symbol in the symbol table result = self._symbol_table.lookup(string) if result: return result # Create a new symbol and return it result = self.new_symbol(string) return result def new_array_with_length(self, length): # Allocate a new array and set its class to be the array class result = Array(self._nilObject) result.set_class(self._arrayClass) # Set the number of indexable fields to the given value (length) result.set_number_of_indexable_fields_and_clear(length, self._nilObject) # Return the freshly allocated array return result def new_array_from_list(self, values): # Allocate a new array with the same length as the list result = self.new_array_with_length(len(values)) # Copy all elements from the list into the array for i in range(len(values)): result.set_indexable_field(i, values[i]) # Return the allocated and initialized array return result def new_array_with_strings(self, strings): # Allocate a new array with the same length as the string array result = self.new_array_with_length(len(strings)) # Copy all elements from the string array into the array for i in range(len(strings)): result.set_indexable_field(i, self.new_string(strings[i])) # Return the allocated and initialized array return result def new_block(self, method, context_frame, arguments): # Allocate a new block and set its class to be the block class result = Block(self._nilObject) result.set_class(self._get_block_class(arguments)) # Set the method and context of block result.set_method(method) result.set_context(context_frame) # Return the freshly allocated block return result def new_class(self, class_class): # Allocate a new class and set its class to be the given class class result = Class(class_class.get_number_of_instance_fields(), self) result.set_class(class_class) # Return the freshly allocated class return result def new_frame(self, previous_frame, method): # Allocate a new frame and set its class to be the frame class result = Frame(self._nilObject) result.set_class(self._frameClass) # Compute the maximum number of stack locations (including arguments, # locals and extra buffer to support doesNotUnderstand) and set the # number of indexable fields accordingly length = (method.get_number_of_arguments() + method.get_number_of_locals().get_embedded_integer() + method.get_maximum_number_of_stack_elements().get_embedded_integer() + 2) result.set_number_of_indexable_fields_and_clear(length, self._nilObject) # Set the method of the frame and the previous frame result.set_method(method) if previous_frame: result.set_previous_frame(previous_frame) # Reset the stack pointer and the bytecode index result.reset_stack_pointer() result.set_bytecode_index(0) # Return the freshly allocated frame return result def new_method(self, signature, num_bytecodes, num_literals): # Allocate a new method and set its class to be the method class result = Method(self._nilObject) result.set_class(self._methodClass) # Set the signature and the number of bytecodes result.set_signature(signature) result.set_number_of_bytecodes(num_bytecodes) result.set_number_of_indexable_fields_and_clear(num_literals, self._nilObject) # Return the freshly allocated method return result def new_instance(self, instance_class): # Allocate a new instance and set its class to be the given class result = Object(instance_class.get_number_of_instance_fields(), self._nilObject) result.set_class(instance_class) # Return the freshly allocated instance return result def new_integer(self, value): # Allocate a new integer and set its class to be the integer class result = Integer(self._nilObject) result.set_class(self._integerClass) # Set the embedded integer of the newly allocated integer result.set_embedded_integer(value) # Return the freshly allocated integer return result def new_big_integer(self, value): # Allocate a new integer and set its class to be the integer class result = BigInteger(self._nilObject) result.set_class(self._bigintegerClass) # Set the embedded integer of the newly allocated integer result.set_embedded_biginteger(value) # Return the freshly allocated integer return result def new_double(self, value): # Allocate a new integer and set its class to be the double class result = Double(self._nilObject) result.set_class(self._doubleClass) # Set the embedded double of the newly allocated double result.set_embedded_double(value) # Return the freshly allocated double return result def new_metaclass_class(self): # Allocate the metaclass classes result = Class(self) result.set_class(Class(self)) # Setup the metaclass hierarchy result.get_class().set_class(result) # Return the freshly allocated metaclass class return result def new_string(self, embedded_string): # Allocate a new string and set its class to be the string class result = String(self._nilObject) result.set_class(self._stringClass) # Put the embedded string into the new string result.set_embedded_string(embedded_string) # Return the freshly allocated string return result def new_symbol(self, string): # Allocate a new symbol and set its class to be the symbol class result = Symbol(self._nilObject) result.set_class(self._symbolClass) # Put the string into the symbol result.set_string(string) # Insert the new symbol into the symbol table self._symbol_table.insert(result) # Return the freshly allocated symbol return result def new_system_class(self): # Allocate the new system class system_class = Class(self) # Setup the metaclass hierarchy system_class.set_class(Class(self)) system_class.get_class().set_class(self._metaclassClass) # Return the freshly allocated system class return system_class def _initialize_system_class(self, system_class, super_class, name): # Initialize the superclass hierarchy if super_class: system_class.set_super_class(super_class) system_class.get_class().set_super_class(super_class.get_class()) else: system_class.get_class().set_super_class(self._classClass) # Initialize the array of instance fields system_class.set_instance_fields(self.new_array_with_length(0)) system_class.get_class().set_instance_fields(self.new_array_with_length(0)) # Initialize the array of instance invokables system_class.set_instance_invokables(self.new_array_with_length(0)) system_class.get_class().set_instance_invokables(self.new_array_with_length(0)) # Initialize the name of the system class system_class.set_name(self.symbol_for(name)) system_class.get_class().set_name(self.symbol_for(name + " class")) # Insert the system class into the dictionary of globals self.set_global(system_class.get_name(), system_class) def get_global(self, name): # Return the global with the given name if it's in the dictionary of globals if self.has_global(name): return self._globals[name] # Global not found return None def set_global(self, name, value): # Insert the given value into the dictionary of globals self._globals[name] = value def has_global(self, name): # Returns if the universe has a value for the global of the given name return name in self._globals def _get_block_class(self, number_of_arguments = None): if not number_of_arguments: # Get the generic block class return self._blockClass # Compute the name of the block class with the given number of # arguments name = self.symbol_for("Block" + str(number_of_arguments)) # Lookup the specific block class in the dictionary of globals and # return it if self.has_global(name): return self.get_global(name) # Get the block class for blocks with the given number of arguments result = self._loadClass(name, None) # Add the appropriate value primitive to the block class result.add_instance_primitive(Block.get_evaluation_primitive(number_of_arguments, self)) # Insert the block class into the dictionary of globals self.set_global(name, result) # Return the loaded block class return result def load_class(self, name): # Check if the requested class is already in the dictionary of globals if self.has_global(name): return self.get_global(name) # Load the class result = self._load_class(name, None) # Load primitives (if necessary) and return the resulting class if result and result.has_primitives(): result.load_primitives() return result def _load_system_class(self, system_class): # Load the system class result = self._load_class(system_class.get_name(), system_class) # Load primitives if necessary if result.has_primitives(): result.load_primitives() def _load_class(self, name, system_class): # Try loading the class from all different paths for cpEntry in self._classpath: try: # Load the class from a file and return the loaded class result = sourcecode_compiler.compile_class_from_file(cpEntry, name.get_string(), system_class, self) if self._dump_bytecodes: Disassembler.dump(result.get_class()) Disassembler.dump(result) return result except IOError: # Continue trying different paths pass # The class could not be found. return None def load_shell_class(self, stmt): # Load the class from a stream and return the loaded class result = sourcecode_compiler.compile_class_from_string(stmt, None, self) if self._dumpBytecodes: Disassembler.dump(result) return result @classmethod def error_print(cls, msg): print(msg, file=sys.stderr, end="") @classmethod def error_println(cls, msg = ""): print(msg, file=sys.stderr) @classmethod def std_print(cls, msg): print(msg, end="") @classmethod def std_println(cls, msg=""): print(msg) def main(args): u = Universe() u.interpret(args[1:]) u.exit(0) if __name__ == '__main__': main(sys.argv)