Преглед изворни кода

Optimize a lot of additional parts in the compiler to use the marshal module for trees

Yentl Van Tendeloo пре 7 година
родитељ
комит
0b3cd9ee6c

+ 0 - 8
bootstrap/modelling.alc

@@ -502,9 +502,6 @@ Element function construct_model_list(model : Element, list : Element):
 	String command
 
 	list = list_reverse(list)
-	Float start
-	Element timings
-	timings = dict_create()
 
 	while (list_len(list) > 0):
 		command = list_pop_final(list)
@@ -530,9 +527,4 @@ Element function construct_model_list(model : Element, list : Element):
 		else:
 			log("Modelling error: did not understand command " + command)
 
-		if bool_not(dict_in(timings, command)):
-			dict_add(timings, command, 0.0)
-		dict_overwrite(timings, command, cast_float(timings[command]) + time() - start)
-
-	log("Timings: " + dict_to_string(timings))
 	return model!

+ 16 - 12
interface/HUTN/hutn_compiler/compiler.py

@@ -2,6 +2,7 @@ try:
     import cPickle as pickle
 except ImportError:
     import pickle as pickle
+import marshal
 
 import os
 import sys
@@ -34,29 +35,32 @@ def md5digest(data):
     hasher.update(data)
     return hasher.hexdigest()
 
-def fetch_cached(data):
+def fetch_cached(data, use_pickle):
     try:
         md5 = md5digest(data)
         cache_folder = os.path.abspath("%s/../caches/" % (os.path.dirname(os.path.abspath(__file__))))
         picklefile = cache_folder + "/%s.pickle" % md5
         with open(picklefile, "rb") as f:
-            return pickle.load(f)
+            if use_pickle:
+                return pickle.load(f)
+            else:
+                return marshal.load(f)
     except:
         return None
 
-def make_cached(original_data, data, mode=None):
+def make_cached(original_data, data, use_pickle):
     md5 = md5digest(original_data)
     cache_folder = os.path.abspath("%s/../caches/" % (os.path.dirname(os.path.abspath(__file__))))
-    if mode is None:
-        picklefile = cache_folder + "/%s.pickle" % md5
-    else:
-        picklefile = cache_folder + "/%s_%s.pickle" % (mode, md5)
+    picklefile = cache_folder + "/%s.pickle" % md5
     with open(picklefile, "wb") as f:
-        pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
+        if use_pickle:
+            pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
+        else:
+            marshal.dump(data, f)
 
 def do_parse(inputfile, grammarfile):
     if grammarfile not in parsers:
-        grammar = fetch_cached(read(grammarfile))
+        grammar = fetch_cached(read(grammarfile), True)
         if grammar is None:
             result = parser = Parser(Grammar(), hide_implicit = True).parse(read(grammarfile))
             if result['status'] != Parser.Constants.Success:
@@ -69,12 +73,12 @@ def do_parse(inputfile, grammarfile):
             grammar = Grammar()          
             grammar.rules = structure['rules']
             grammar.tokens = structure['tokens']        
-            make_cached(read(grammarfile), grammar)
+            make_cached(read(grammarfile), grammar, True)
         parsers[grammarfile] = grammar
     else:
         grammar = parsers[grammarfile]
 
-    result = fetch_cached(read(inputfile))
+    result = fetch_cached(read(inputfile), False)
     if result is None:
         result = Parser(grammar, line_position = True).parse(read(inputfile))
         if result['status'] != Parser.Constants.Success:
@@ -86,7 +90,7 @@ def do_parse(inputfile, grammarfile):
             lines = "".join(lines)
             msg = "%s:%s:%s: %s\nContext:\n%s" % (inputfile, result["line"], result["column"], result["text"], lines)
             raise Exception(msg)
-        make_cached(read(inputfile), result)
+        make_cached(read(inputfile), result, False)
 
     return result
 

+ 4 - 4
interface/HUTN/hutn_compiler/constructors_visitor.py

@@ -127,8 +127,8 @@ class ConstructorsVisitor(Visitor):
     def visit_func_call(self, tree):
         symbol = self.get_symbol(Tree.get_tail(tree)[0])
         self.add_constructors("call")
-        if hasattr(symbol, "pathmv"):
-            self.add_constructors("deref", symbol.pathmv)
+        if "pathmv" in symbol:
+            self.add_constructors("deref", symbol['pathmv'])
         else:
             self.visit(Tree.get_tail(tree)[0])
         expressions = Tree.get_children(tree, "expression")
@@ -233,9 +233,9 @@ class ConstructorsVisitor(Visitor):
             # Note: replicates "Element x; x = ?primiteves/a" behavior
             # Dangerous: SemanticsVisitor handles it as a function
             # pathmv is needed in visit_func_call(self, tree)
-            symbol.pathmv = Tree.get_text(Tree.get_child(tree, "ANYTHING"))
+            symbol['pathmv'] = Tree.get_text(Tree.get_child(tree, "ANYTHING"))
 
-            self.add_constructors("global", symbol['node'], "deref", symbol.pathmv)
+            self.add_constructors("global", symbol['node'], "deref", symbol['pathmv'])
 
             # reason: "X function f(Y) = Z" adds no constructors
             return True

+ 2 - 3
interface/HUTN/hutn_compiler/declare_functions_visitor.py

@@ -1,5 +1,4 @@
 import hutn_compiler.symbol_table as st
-import hutn_compiler.types_mv as types_mv
 from hutn_compiler.visitor import Visitor
 from hutn_compiler.hutnparser import Tree
 
@@ -14,7 +13,7 @@ class DeclareFunctionsVisitor(Visitor):
         parameter_types = []
         for parameter in Tree.get_children(tree, 'parameter'):
             type_specifier = Tree.get_text(Tree.get_children(parameter, "type_specifier")[0])
-            parameter_types.append(types_mv.string_to_type(type_specifier))
+            parameter_types.append(type_specifier)
         return parameter_types
 
     def compute_func_type(self, tree):
@@ -41,4 +40,4 @@ class DeclareFunctionsVisitor(Visitor):
         self.set_symbol(tree, s)
 
     def visit_func_type(self, tree):
-        self.set_type(tree, types_mv.string_to_type(Tree.get_text(tree)))
+        self.set_type(tree, Tree.get_text(tree))

+ 3 - 5
interface/HUTN/hutn_compiler/hutnparser.py

@@ -27,8 +27,6 @@ import sys
 
 from copy import deepcopy 
 
-from hutn_compiler.position import Position
-
 line_cache = {}
 
 def get_buffer(base, start):
@@ -116,7 +114,7 @@ class Tree(object):
 
     @staticmethod
     def get_reference_line(tree):
-        return "%s:%s:%s-%s" % (tree['inputfile'], tree['startpos']["line"], tree['startpos']["column"], tree['endpos']["column"])
+        return "%s:%s:%s-%s" % (tree['inputfile'], tree['startpos'][0], tree['startpos'][1], tree['endpos'][1])
 
     @staticmethod
     def fix_tracability(tree, inputfile):
@@ -903,8 +901,8 @@ class Parser(object):
         def inner_visit(self,tree):
             startDic = self.calcPosMethod(tree['startpos'])
             endDic = self.calcPosMethod(tree['endpos'])
-            tree['startpos'] = Position(startDic["line"], startDic["column"])
-            tree['endpos'] =  Position(endDic["line"], endDic["column"])
+            tree['startpos'] = (startDic["line"], startDic["column"])
+            tree['endpos'] =  (endDic["line"], endDic["column"])
             for item in tree['tail']:
                 if (isinstance(item, dict)):
                     self.inner_visit(item)

+ 0 - 73
interface/HUTN/hutn_compiler/position.py

@@ -1,73 +0,0 @@
-"""
-Author Daniel Riegelhaupt
-November 2014
-
-A simple position object.
-Needed to be able to search in trees using line and column
-"""
-
-class Position(object):
-    """
-    a position object with the comparison operators implemented so that we can use the position to search
-    for backwards compatibility the operator [] has also been overridden
-    ["line"] or ["row"] will get/set self.line and ["column"] or ["col"] will get or set self.column
-    This is not needed and self.line or column can be accesed directly as well
-    """
-    def __init__(self, line, col):
-        self.line = line
-        self.column = col
-
-    def toDictionary(self):
-        return { 'line': self.line, 'column': self.column}
-
-    def __repr__(self):
-        return  "{'line': " + str(self.line)  +", 'column': " + str(self.column) +"}"
-
-    def __str__(self):
-        #return str({ 'line' : self.line , 'column' : self.column })
-        return "{'line': " + str(self.line)  +", 'column': " + str(self.column) +"}"
-
-    def __eq__(self, other):
-        # ==
-        return ((self.line == other.line) and (self.column == other.column))
-
-    def __lt__(self, other):
-        # <
-        return ((self.line < other.line) or ((self.line == other.line) and (self.column < other.column)))
-
-    def __le__(self, other):
-        # <=
-        return ((self.line < other.line) or ((self.line == other.line) and (self.column <= other.column)))
-
-    def __ne__(self, other):
-        # !=
-        return ((self.line != other.line) or (self.column != other.column))
-
-    def __gt__(self, other):
-        # >
-        return ((self.line > other.line) or ((self.line == other.line) and (self.column > other.column)))
-
-    def __ge__(self, other):
-        # <=
-        return ((self.line > other.line) or ((self.line == other.line) and (self.column >= other.column)))
-
-    def __getitem__(self, item):
-        # varname = position['line']
-        if item == 'line' or item == 'row':
-            return self.line
-        elif item == 'column' or item == 'col':
-            return self.column
-        else:
-            raise AttributeError("'Position' object has no attribute '"+str(item)+"'")
-
-    def __setitem__(self, item, value):
-        # position['line'] = 5
-        if item == 'line' or item == 'row':
-            self.line = value
-        elif item == 'column' or item == 'col':
-            self.column =value
-        else:
-            raise AttributeError("'Position' object has no attribute '"+str(item)+"'")
-
-    def deepcopy(self):
-        pass

+ 47 - 35
interface/HUTN/hutn_compiler/semantics_visitor.py

@@ -1,7 +1,6 @@
 import hutn_compiler.hutnparser as hp
 import hutn_compiler.symbol_table as st
 import sys
-import hutn_compiler.types_mv as types_mv
 from hutn_compiler.declare_functions_visitor import DeclareFunctionsVisitor
 from hutn_compiler.hutnparser import Tree
 from hutn_compiler.visitor import Visitor
@@ -26,11 +25,11 @@ class SemanticsVisitor(Visitor):
     @staticmethod
     def incompatible_types(l_type, r_type):
         if type(l_type) != type(r_type):
-            if types_mv.Void in (type(l_type), type(r_type)):
+            if "Void" in (type(l_type), type(r_type)):
                 return True
-            if types_mv.Element in (type(l_type), type(r_type)):
+            if "Element" in (type(l_type), type(r_type)):
                 return False
-            if l_type.isNotNumber() or r_type.isNotNumber():
+            if l_type not in ["Integer", "Float", "Boolean"] or r_type not in ["Integer", "Float", "Boolean"]:
                 return True
         return False
 
@@ -52,12 +51,17 @@ class SemanticsVisitor(Visitor):
     def generalize_binary_ops_arithmetic(self, tree):
         l, r = Tree.get_tail(tree)[0], Tree.get_tail(tree)[2]
         l_type, r_type = self.get_type(l), self.get_type(r)
-        return types_mv.generalize_arithmetic(l_type, r_type)
+        if l_type == "Float" or r_type == "Float":
+            return "Float"
+        elif l_type == "Integer" or r_type == "Integer":
+            return "Integer"
+        else:
+            return "Boolean"
 
     def check_unary_ops_arithmetic(self, tree, operator_name):
         l = Tree.get_tail(tree)[1]
         l_type = self.get_type(l)
-        if l_type.isNotNumber():
+        if l_type not in ["Boolean", "Integer", "Float"]:
             raise RuntimeError(
                 "{}:{}:{}: error: wrong type argument to unary {} "
                 "({})".format(self.inputfiles[0],
@@ -70,7 +74,12 @@ class SemanticsVisitor(Visitor):
         l = Tree.get_tail(tree)[1]
         l_type = self.get_type(l)
         try:
-            return types_mv.promote_arithmetic(l_type)
+            if l_type == "Boolean":
+                return "Integer"
+            elif l_type == "Integer" or l_type == "Float":
+                return l_type
+            else:
+                raise RuntimeError("You cannot promote {} to a numeric type".format(str(l_type)))
         except RuntimeError:
             raise RuntimeError(
                 "Pathological situation in promote_unary_ops_arithmetic: "
@@ -103,7 +112,7 @@ class SemanticsVisitor(Visitor):
             r_type = None
         else:
             r = None
-            r_type = types_mv.Void()
+            r_type = "Void"
 
         if l:
             self.do_check_assignment(l, r, r_type)
@@ -115,9 +124,9 @@ class SemanticsVisitor(Visitor):
                         tree['startpos']['column']))
 
     def check_predicate(self, tree):
-        if isinstance(self.get_type(tree), types_mv.Element):
+        if self.get_type(tree) == "Element":
             return
-        if self.get_type(tree).isNotNumber():
+        if self.get_type(tree) not in ["Boolean", "Integer", "Float"]:
             raise RuntimeError(
                 "{}:{}:{}: error: predicates of type '{}' are not allowed"
                 .format(self.inputfiles[0],
@@ -150,8 +159,7 @@ class SemanticsVisitor(Visitor):
             try:
                 self.visit(call_tree)
             except RuntimeError:
-                call_signature = "{0} function {1}({2}, {2})".format(
-                    str(types_mv.Boolean()), call_name, l_type)
+                call_signature = "Boolean function {1}({2}, {2})".format(call_name, l_type)
                 raise RuntimeError(
                     "{}:{}:{}: error: cannot perform {}: function '{}' is "
                     "not found".format(
@@ -180,8 +188,7 @@ class SemanticsVisitor(Visitor):
             try:
                 self.visit(call_tree)
             except RuntimeError:
-                call_signature = "{0} function {1}({2})".format(
-                    str(types_mv.Boolean()), call_name, l_type)
+                call_signature = "Boolean function {1}({2})".format(call_name, l_type)
                 raise RuntimeError(
                     "{}:{}:{}: error: cannot perform {}: function '{}' is "
                     "not found".format(
@@ -197,15 +204,20 @@ class SemanticsVisitor(Visitor):
         l, op, r = Tree.get_tail(tree)
         l_type, r_type = self.get_type(l), self.get_type(r)
         if type(l_type) != type(r_type):  # if two different numeric types
-            g_type = types_mv.generalize_arithmetic(l_type, r_type)
+            if l_type == "Float" or r_type == "Float":
+                g_type = "Float"
+            elif l_type == "Integer" or r_type == "Integer":
+                g_type = "Integer"
+            else:
+                g_type = "Boolean"
             self.perform_implicit_cast(tree, l, l_type, g_type)
             self.perform_implicit_cast(tree, r, r_type, g_type)
 
     def cast_binary_ops_logical(self, tree):
         l, op, r = Tree.get_tail(tree)
         l_type, r_type = self.get_type(l), self.get_type(r)
-        self.perform_implicit_cast(tree, l, l_type, types_mv.Boolean())
-        self.perform_implicit_cast(tree, r, r_type, types_mv.Boolean())
+        self.perform_implicit_cast(tree, l, l_type, "Boolean")
+        self.perform_implicit_cast(tree, r, r_type, "Boolean")
 
     def cast_unary_ops_arithmetic(self, tree):
         l = Tree.get_tail(tree)[1]
@@ -263,9 +275,9 @@ class SemanticsVisitor(Visitor):
                 cast_signature))
 
     def perform_implicit_cast(self, tree, child, from_type, to_type):
-        if types_mv.Element in (type(from_type), type(to_type)):
+        if "Element" in (from_type, to_type):
             return
-        if type(from_type) == type(to_type):
+        if from_type == to_type:
             return
         cast_name = SemanticsVisitor.cast_name(from_type, to_type)
         cast_tree = self.func_call(cast_name, [child], tree)
@@ -356,7 +368,7 @@ class SemanticsVisitor(Visitor):
         type_spec = Tree.get_child(tree, "type_specifier")
         var_id = Tree.get_child(tree, "ID")
 
-        var_type = types_mv.string_to_type(Tree.get_text(type_spec))
+        var_type = Tree.get_text(type_spec)
         var_name = Tree.get_text(var_id)
 
         symbol = {"name": var_name, "type": var_type, "is_global": self.current_funcdecl is None, "node": None, "params": None}
@@ -390,7 +402,7 @@ class SemanticsVisitor(Visitor):
         else:
             self.replace_child_binary_op_with_call(tree, 2)
             self.cast_binary_ops_logical(tree)
-            self.set_type(tree, types_mv.Boolean())
+            self.set_type(tree, "Boolean")
 
     def visit_conjunction(self, tree):
         self.visit_children(tree)
@@ -399,7 +411,7 @@ class SemanticsVisitor(Visitor):
         else:
             self.replace_child_binary_op_with_call(tree, 2)
             self.cast_binary_ops_logical(tree)
-            self.set_type(tree, types_mv.Boolean())
+            self.set_type(tree, "Boolean")
 
     def visit_comparison(self, tree):
         self.visit_children(tree)
@@ -409,7 +421,7 @@ class SemanticsVisitor(Visitor):
             self.replace_child_binary_op_with_call(tree, 2)
             self.check_binary_ops_arithmetic(tree)
             self.cast_binary_ops_arithmetic(tree)
-            self.set_type(tree, types_mv.Boolean())
+            self.set_type(tree, "Boolean")
 
     def visit_relation(self, tree):
         self.visit_children(tree)
@@ -419,7 +431,7 @@ class SemanticsVisitor(Visitor):
             self.replace_child_binary_op_with_call(tree, 2)
             self.check_binary_ops_arithmetic(tree)
             self.cast_binary_ops_arithmetic(tree)
-            self.set_type(tree, types_mv.Boolean())
+            self.set_type(tree, "Boolean")
 
     def visit_sum(self, tree):
         self.visit_children(tree)
@@ -454,7 +466,7 @@ class SemanticsVisitor(Visitor):
 
         l = Tree.get_tail(tree)[1]
         l_type = self.get_type(l)
-        self.perform_implicit_cast(tree, l, l_type, types_mv.Boolean())
+        self.perform_implicit_cast(tree, l, l_type, "Boolean")
 
         self.set_type(tree, self.get_type(Tree.get_tail(tree)[1]))
 
@@ -487,19 +499,19 @@ class SemanticsVisitor(Visitor):
         self.set_type(tree, self.get_type(Tree.get_tail(tree)[0]))
 
     def visit_type_specifier(self, tree):
-        self.set_type(tree, types_mv.Type())
+        self.set_type(tree, "Type")
 
     def visit_actionname(self, tree):
-        self.set_type(tree, types_mv.Action())
+        self.set_type(tree, "Action")
 
     def visit_string(self, tree):
-        self.set_type(tree, types_mv.String())
+        self.set_type(tree, "String")
 
     def visit_integer(self, tree):
-        self.set_type(tree, types_mv.Integer())
+        self.set_type(tree, "Integer")
 
     def visit_float(self, tree):
-        self.set_type(tree, types_mv.Float())
+        self.set_type(tree, "Float")
 
     # there is no such rule in the grammar, we just avoid code duplicates
     def visit_id(self, tree):
@@ -541,7 +553,7 @@ class SemanticsVisitor(Visitor):
         self.set_type(tree, symbol['type'])
 
         if not st.Symbol.is_func(symbol):
-            if isinstance(symbol['type'], types_mv.Element):
+            if symbol['type'] == "Element":
                 #sys.stderr.write("{}:{}:{}: warning: calling a variable of type "
                 #                 "'Element'\n".format(self.inputfiles[0],
                 #                                      tree.startpos['line'],
@@ -597,10 +609,10 @@ class SemanticsVisitor(Visitor):
         pass  # no need to visit it again
 
     def visit_dictionary(self, tree):
-        self.set_type(tree, types_mv.Element)
+        self.set_type(tree, "Element")
 
     def visit_list(self, tree):
-        self.set_type(tree, types_mv.Element)
+        self.set_type(tree, "Element")
 
     def visit_dict_item(self, tree):
         pass
@@ -642,7 +654,7 @@ class SemanticsVisitor(Visitor):
         param_id = Tree.get_child(tree, "ID")
         type_spec = Tree.get_child(tree, "type_specifier")
 
-        param_type = types_mv.string_to_type(Tree.get_text(type_spec))
+        param_type = Tree.get_text(type_spec)
         param_name = Tree.get_text(param_id)
 
         symbol = {"name": param_name, "type": param_type, "is_global": False, "node": None, "params": None}
@@ -662,7 +674,7 @@ class SemanticsVisitor(Visitor):
         self.check_return(tree)
 
     def visit_bool(self, tree):
-        self.set_type(tree, types_mv.Boolean())
+        self.set_type(tree, "Boolean")
 
     def visit_break(self, tree):
         if self.while_counter == 0:

+ 1 - 4
interface/HUTN/hutn_compiler/symbol_table.py

@@ -1,8 +1,5 @@
-import hutn_compiler.types_mv as types_mv
-
-
 class Symbol(object):
-    def __init__(self, name, type=types_mv.Element(), is_global=False, node=None, params=None):
+    def __init__(self, name, type="Element", is_global=False, node=None, params=None):
         self.name = name
         self.type = type
         self.is_global = is_global

+ 0 - 142
interface/HUTN/hutn_compiler/types_mv.py

@@ -1,142 +0,0 @@
-import ast
-
-
-class ModelverseType(object):
-    def __init__(self):
-        pass
-
-    def isNumber(self):
-        return False
-
-    def isNotNumber(self):
-        return not self.isNumber()
-
-    def isInteger(self):
-        return False
-
-    def isFloat(self):
-        return False
-
-    def isBoolean(self):
-        return False
-
-    def __str__(self):
-        return self.__class__.__name__
-
-
-class Type(ModelverseType):
-    pass
-
-
-class Integer(ModelverseType):
-    def isNumber(self):
-        return True
-
-    def isInteger(self):
-        return True
-
-
-class Float(ModelverseType):
-    def isNumber(self):
-        return True
-
-    def isFloat(self):
-        return True
-
-
-class Boolean(ModelverseType):
-    def isNumber(self):
-        return True
-
-    def isBoolean(self):
-        return True
-
-
-class Action(ModelverseType):
-    pass
-
-
-class Element(ModelverseType):
-    pass
-
-
-class String(ModelverseType):
-    pass
-
-
-class Void(ModelverseType):
-    pass
-
-
-def generalize_arithmetic(l_type, r_type):
-    if l_type.isFloat() or r_type.isFloat():
-        return Float()
-    if l_type.isInteger() or r_type.isInteger():
-        return Integer()
-    return Boolean()
-
-
-def promote_arithmetic(l_type):
-    if l_type.isBoolean():
-        return Integer()
-    elif l_type.isNumber():
-        return l_type  # Warning: no copy or new instance is created here
-    else:
-        raise RuntimeError(
-            "You cannot promote {} to a numeric type".format(str(l_type)))
-
-
-def allow_assign(target, value):
-    if target is None or type(target) == Void:
-        return False
-    if value is None or type(value) == Void:
-        return False
-    if type(target) == Element:
-        return True
-    if type(value) == Element:
-        #print("Warning: implicit type upcast from Element to " + str(target))
-        return True
-    return type(target) == type(value)
-
-
-def string_to_type(t):
-    if t == "Integer":
-        return Integer()
-    elif t == "Boolean":
-        return Boolean()
-    elif t == "Float":
-        return Float()
-    elif t == "Action":
-        return Action()
-    elif t == "String":
-        return String()
-    elif t == "Type":
-        return Type()
-    elif t == "Element":
-        return Element()
-    elif t == "Void":
-        return Void()
-    else:
-        raise Exception("Unknown type used: " + str(t))
-
-
-def get_type(string):
-    if string in ["if", "while", "assign", "call", "break", "continue", "return","resolve","access", "constant", "input", "output", "declare", "global"]:
-        return Action()
-    elif string in ["Integer", "Float", "String", "Boolean", "Action", "Type"]:
-        return Type()
-    elif string == "Void":
-        return Void()
-    try:
-        value = ast.literal_eval(string)
-        t = type(value)
-        if t == bool:
-            return Boolean()
-        elif t == int:
-            return Integer()
-        elif t == float:
-            return Float()
-        elif t == str:
-            return String()
-    except:
-        raise Exception("Value with unknown type: " + str(string))