def g_forloop_iter(n): # 0: identifier; 1: list; 2: suite det_type(n[1], file_name) iterable = n[1].type # Determine the type of the iterative variable based on the container # it's iterating over if basetype(iterable) in (builtins["StringType"], builtins["FileType"]): id_type = builtins["string"] elif basetype(iterable) in containertypes: id_type = iterable.elem_type[0] else: # recovering from a type error # a type error will be thrown during type checking id_type = iterable # Add the iterative variable to the loop's environment if (n[2].label == "SUITE_BLOCK"): # 0: docstring; 1: block n[2][1].initiate_var(n[0], id_type) if (n[2].label == "SUITE_INLINE"): # 0: simple statement n[2].initiate_var(n[0], id_type)
def g_declaration(n): # 0: identifier; 1: type det_type(n[1], file_name) try: n.initiate_var(n[0], n[1].type) except DeclarationException: type_error("The variable '" + n[0] +"' has already been defined in " + "the current scope.\nOnly functions and procedures can " + "have multiple definitions.", file_name, n)
def g_argumentlist(n): # 0: identifier; 1: type det_type(n[1], file_name) identifier = n[0] t = n[1].type # Locate the function or procedure node while (n.label != "FUNCTION_DEFINITION" and \ n.label != "PROCEDURE_DEFINITION" and \ n.label != "LITERAL_FUNCTION" and \ n.label != "LITERAL_PROCEDURE"): n = n.parent # Function or procedure literal - lambda expression if n.label == "LITERAL_FUNCTION" or n.label == "LITERAL_PROCEDURE": try: n.initiate_var(identifier, t) except DeclarationException: type_error( "'" + n[0] + "' has already been declared in the " + "current scope, and is not a function or procedure.\n" + "Only function and procedure definitions are allowed to " + " have more than one value.", file_name, n) else: # Function or procedure defintion # Child node with an environment = n[3] if function, n[2] if procedure n = n[3] if (len(n.children) == 4) else n[2] if (n.label == "SUITE_BLOCK"): try: n[1].initiate_var(identifier, t) except DeclarationException: type_error( "'" + n[0] + "' has already been declared in the " " current scope, and is not a function or " + "procedure.\nOnly function and procedure " + " definitions are allowed to have more than one " + "value.", file_name, n) if (n.label == "SUITE_INLINE"): try: n.initiate_var(identifier, t) except DeclarationException: type_error( "'" + n[0] + "' has already been declared in the " " current scope, and is not a function or " + "procedure.\nOnly function and procedure " + " definitions are allowed to have more than one " + "value.", file_name, n)
def g_procedure_definition(n): # 0: identifier; 1: argument list; 2: suite det_type(n[1], file_name) sig = n[1].type try: n.parent.initiate_var(n[0],type_obj("proc",builtins["proc"], sig = sig)) except SignatureException: # Function overloading - duplicate signature type_error("The procedure '" + n[0] + "' with the signature '" + repr(sig) + "' has already been defined.", file_name, n[1]) except DeclarationException: type_error("'" + n[0] + "' has already been declared in the current" + "scope, and is not a function or procedure.\n" + "Only function and procedure definitions are allowed to " + " have more than one value.", file_name, n)
def importgenerate(cspyfile, _imports=[]): _imports.append(cspyfile) # LEX AND PARSE THE FILE filename = cspyfile if not os.path.isfile(filename): print >> sys.stderr, cspyfile + " could not be found. Did you mean" +\ " to use pyimport instead of import?" exit(1) cspy_file_match = re.match(r"(?P<path>.*)/[^/]+\.cspy", filename) if cspy_file_match: # path found - not being run in current directory cspy_file_path = cspy_file_match.group("path") else: cspy_file_path = "" cspyfile = open(cspyfile, 'rU').read() + "\n" lexer = lex.lex() lexer.indentwith = None lexer.indentedline = None lexer.indentstack = [0] lexer.input(cspyfile) parser = yacc.yacc() lexer.parser = parser parsetree = parser.parse(tracking = True) if parsetree: parsetree.set_column_num(cspyfile) else: print >> sys.stderr, 'Should something have been printed? cspy_master.py' remove_files() exit(1) # GET IMPORTED FILES imports = parsetree.flatten("IMPORTBLOCK_SINGLE") name = filename[:len(filename) - 5] tmp_path = "/tmp/" + getpass.getuser() try: os.stat(tmp_path) except: os.mkdir(tmp_path) # NO FILES IMPORTED if not imports: # SAVE FILE NAME F = open(tmp_path + "/__import_names.txt", "a") # see documentation F.write(name + "\n") F.close() # PROCESS SELF generate_environments(parsetree, filename) # add environments det_type(parsetree, file_name=filename) # type check overloads = translate(parsetree, filename, cspy_file_path) # translate to Python return parsetree, _imports, overloads # FILES IMPORTED else: for statement in imports: # SAVE FILE NAME F = open(tmp_path + "/__import_names.txt", "a") # see documentation F.write(name + "\n") F.close() # PROCESS IMPORTS statement = statement[0] importtype = statement.label # ADD IMPORTED CODE TO PARSE TREE # import simple : import module if importtype == "IMPORT_SIMPLE": importfile = statement[0] + ".cspy" importtree, _imports, import_overloads \ = importgenerate(path + importfile, _imports) importmodule = type_obj("import module", builtins["ImportModule"], methods = importtree.env) import_overloads = {'global' : {}, statement[0] : import_overloads} parsetree.initiate_var(statement[0], importmodule) # import alias : import module as id elif importtype == "IMPORT_ALIAS": importfile = statement[0] + ".cspy" importtree, _imports, import_overloads \ = importgenerate(path + importfile, _imports) alias = statement[1] importmodule = type_obj("import module", builtins["ImportModule"], methods = importtree.env) import_overloads = {'global' : {}, alias : import_overloads} parsetree.initiate_var(alias, importmodule) # import bulk : from module import * elif importtype == "IMPORT_BULK": importfile = statement[0] + ".cspy" importtree, _imports, import_overloads \ = importgenerate(path + importfile, _imports) for variable in importtree.env: parsetree.initiate_var(variable, importtree.env[variable]) # import discrete : from module import id1, id2, ... elif importtype == "IMPORT_DISCRETE": importfile = statement[0] + ".cspy" importtree, _imports, import_overloads \ = importgenerate(path + importfile, _imports) importids = statement.flatten("IMPORTLIST_SIMPLE") for identifier in importids: name = identifier[0] value = importtree.lookup_var(name) parsetree.initiate_var(name, value) # copy over overloaded names from imports tmp = {'global' : {}} for name in import_overloads['global']: # copy over the global functions and procedures if import_overloads['global'][name] in importids: tmp['global'][name] = import_overloads['global'][name] # copy over the imported classes for class_name in import_overloads: if class_name in importids: tmp[class_name] = import_overloads[class_name] import_overloads = tmp #--------------------------------# # PYIMPORT - imports from python # #--------------------------------# # pyimport simple : pyimport module elif importtype == "PYIMPORT_SIMPLE": importfile = statement[0] + ".cspyh" importtree = pyimportgenerate(importfile, path) importmodule = type_obj("import module", builtins["ImportModule"], methods = importtree.env) parsetree.initiate_py_var(statement[0], importmodule) import_overloads = {'global' : {}} # pyimport alias : pyimport module as id elif importtype == "PYIMPORT_ALIAS": importfile = statement[0] + ".cspyh" importtree = pyimportgenerate(importfile, path) alias = statement[1] importmodule = type_obj("import module", builtins["ImportModule"], methods = importtree.env) parsetree.initiate_py_var(alias, importmodule) import_overloads = {'global' : {}} # pyimport bulk : from module pyimport * elif importtype == "PYIMPORT_BULK": importfile = statement[0] + ".cspyh" importtree = pyimportgenerate(importfile, path) for variable in importtree.env: parsetree.initiate_py_var(variable, importtree.env[variable]) import_overloads = {'global' : {}} # pyimport discrete : from module pyimport id1, id2, ... elif importtype == "PYIMPORT_DISCRETE": importfile = statement[0] + ".cspyh" importtree = pyimportgenerate(importfile, path) importids = statement.flatten("IMPORTLIST_SIMPLE") for identifier in importids: name = identifier[0] value = importtree.lookup_var(name) parsetree.initiate_py_var(name, value) import_overloads = {'global' : {}} else: # Should never reach this point print >> sys.stderr, "\nCompiler error with imports in " + \ "cspy_master.py.\n" + \ "No import type matched" sys.exit(1) # PROCESS SELF generate_environments(parsetree, filename) # add environments det_type(parsetree, file_name=filename) # type check overloads = translate(parsetree, filename, cspy_file_path, import_overloads) # translate to Python return parsetree, _imports, overloads
def g_class_definition(n): # 0: identifier; 1: super class; 2: suite # Class extension if (n[1].label == "EMPTY"): sup = builtins["object"] n[1].label = "TYPE" n[1].children.append("object") else: det_type(n[1], file_name) sup = n[1].type # Temporarily initialize the class in the global environment # without any methods. This allows methods in the class to # have local variables whose type is the class try: n.parent.initiate_var(n[0], type_obj(n[0], builtins["type"], sup = sup)) except DeclarationException: type_error("'" + n[0] + "' has already been declared in the current" + "scope, and is not a function or procedure.\n" + "Only function and procedure definitions are allowed to " + " have more than one value.", file_name, n) # Get the class attributes det_type(n[2][1][0], file_name) attributes = n[2][1][0] if (attributes.label == "EMPTY"): # Empty variable declaration block - no class attributes attribute_nodes = [] else: # Nonempty variable declartion block - has class attributes attribute_nodes = attributes.flatten("DECLARATION_SIMPLE") + \ attributes.flatten("DECLARATION_INITIALIZE") # Add the attributes to the method dictionary methods = {} for a in attribute_nodes: methods[a[0]] = a[1].type # Get the class methods method_nodes = n[2].flatten("PROCEDURE_DEFINITION") + \ n[2].flatten("FUNCTION_DEFINITION") # Add each method to the method dictionary for m in method_nodes: name = m[0] det_type(m[1], file_name) sig = m[1].type if m.label == "PROCEDURE_DEFINITION": # procedure overloading if name in methods.keys(): if (isinstance(methods[name], list)): # Add the new procedure signature to the class methods[name].append(type_obj("proc", builtins["proc"], sig = sig)) # First overload else: methods[name] = [methods[name], type_obj("proc", builtins["proc"], sig = sig)] # Undeclared variable - add it to the class else: methods[name] = type_obj("proc", builtins["proc"], sig = sig) else: det_type(m[2], file_name) sig.return_type = m[2].type # function overloading if name in methods.keys(): if (isinstance(methods[name], list)): # Add the new function signature to the class methods[name].append(type_obj("fn", builtins["fn"], sig = sig)) # First overload else: methods[name] = [methods[name], type_obj("fn", builtins["fn"], sig = sig)] # Undeclared variable - add it to the class else: methods[name] = type_obj("fn", builtins["fn"], sig = sig) # Locate the global environment and update the class method dictionary current = n while current.parent: current = current.parent current.env[n[0]].methods = methods