import hutn_compiler.symbol_table as st
from hutn_compiler.visitor import Visitor
from hutn_compiler.hutnparser import Tree

# 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(tree, 'parameter'):
            type_specifier = Tree.get_text(Tree.get_children(parameter, "type_specifier")[0])
            parameter_types.append(type_specifier)
        return parameter_types

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

    def visit_funcdecl(self, tree):
        func_name = Tree.get_text(Tree.get_children(tree, "func_name")[0])
        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 = {"name": func_name, "type": func_type, "is_global": True, "node": None, "params": parameter_types}
            self.symbol_table.add(s)
        except Exception:
            if "COLON" in Tree.get_tail(tree) or "ASSIGN" in Tree.get_tail(tree):
                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, Tree.get_text(tree))
