import symbol_table as st
import types_mv
from visitor import Visitor


# Declare the function but do not visit its body
class DeclareFunctionsVisitor(Visitor):
    def __init__(self, symbol_table, inputfiles):
        Visitor.__init__(self, [])
        self.symbol_table = symbol_table
        self.inputfiles = inputfiles

    def compute_parameter_types(self, tree):
        parameter_types = []
        for parameter in tree.get_children('parameter'):
            type_specifier = parameter.get_children("type_specifier")[0].get_text()
            parameter_types.append(types_mv.string_to_type(type_specifier))
        return parameter_types

    def compute_func_type(self, tree):
        self.visit(tree.get_tail()[0])
        func_type = self.get_type(tree.get_tail()[0])
        return func_type

    def visit_funcdecl(self, tree):
        func_name = tree.get_children("func_name")[0].get_text()
        func_type = self.compute_func_type(tree)
        parameter_types = self.compute_parameter_types(tree)
        self.set_type(tree, func_type)

        #TODO should check type compatibility if declared multiple times
        try:
            s = st.Symbol(func_name, func_type, is_global=True, params=parameter_types)
            self.symbol_table.add(s)
        except Exception:
            if "COLON" in tree.get_tail() or "ASSIGN" in tree.get_tail():
                raise RuntimeError(
                    "{}:{}:{}: error: redeclaration of '{}'".format(
                        self.inputfiles[0], tree.startpos['line'],
                        tree.startpos['column'], func_name))
        self.set_symbol(tree, s)

    def visit_func_type(self, tree):
        self.set_type(tree, types_mv.string_to_type(tree.get_text()))
