import logging as log

class BooleanOperator(object):
    def __init__(self, precedence_in, bool_func_in, *args):
        self.precedence = precedence_in
        self.bool_func = bool_func_in
        self.equivalent_symbols = list(args)

    def result(self, a, b):
        return self.bool_func(a, b)

def bool_not(a, b):
    # this should never be called;
    # not is implemented as xor w/ 1
    log.fatal("Boolean not function was explicitly called.\n"
              "This should not happen; not is implemented as xor with 1.\n"
              "Cannot continue program execution.\n")
    raise RuntimeError

def bool_and(a, b):
    return int(a and b)

def bool_nand(a, b):
    return int(not (a and b))

def bool_xor(a, b):
    return int(a != b)

def bool_xnor(a, b):
    return int(a == b)

def bool_or(a, b):
    return int(a or b)

def bool_nor(a, b):
    return int(not (a or b))

# Define schema information

precedence = {
    "ZERO" : 0,
    "LOW" : 1,
    "MEDIUM" : 2,
    "HIGH" : 3
}

SYM_NOT = "~"
SYM_XOR = "+"
SYM_XNOR = "@"
SYM_AND = "&"
SYM_NAND = "$"
SYM_OR = "|"
SYM_NOR = "%"

# TODO: possibly allow users to make their own precedence maps in the future
schema = {
    SYM_NOT : BooleanOperator(precedence["HIGH"], bool_not, "not", "NOT", "~", "!"),
    SYM_XOR : BooleanOperator(precedence["MEDIUM"], bool_xor, "xor", "XOR"),
    SYM_XNOR : BooleanOperator(precedence["MEDIUM"], bool_xnor, "xnor", "XNOR", "nxor", "NXOR"),
    SYM_AND : BooleanOperator(precedence["LOW"], bool_and, "and", "AND", "&", "&&", "/\\"),
    SYM_NAND : BooleanOperator(precedence["LOW"], bool_nand, "nand", "NAND"),
    SYM_OR : BooleanOperator(precedence["ZERO"], bool_or, "or", "OR", "|", "||", "\\/"),
    SYM_NOR : BooleanOperator(precedence["ZERO"], bool_nor, "nor", "NOR")
}

schema_search_ordered_list = [SYM_XNOR, SYM_XOR, SYM_NOR, SYM_NAND, SYM_AND, SYM_OR, SYM_NOT]
import logging as log

__all__ = ["BooleanOperator",
           "schema",
           "schema_search_ordered_list",
           "precedence",
           "SYM_NOT",
           "SYM_NAND",
           "SYM_AND",
           "SYM_OR",
           "SYM_NOR",
           "SYM_XNOR",
           "SYM_XOR"]

class BooleanOperator(object):
    def __init__(self, precedence_in, bool_func_in, *args):
        self.precedence = precedence_in
        self.bool_func = bool_func_in
        self.equivalent_symbols = list(args)

    def result(self, a, b):
        return self.bool_func(a, b)

# functions called in Boolean expression evaluation;
# a and b should always be passed as ints to these functions
tt_and = lambda a, b: int(a and b)
tt_nand = lambda a, b: int(not tt_and(a, b))
tt_or = lambda a, b: int(a or b)
tt_nor = lambda a, b: int(not tt_or(a, b))
tt_xor = lambda a, b: int((not a and b) or (a and not b))
tt_xnor = lambda a, b: int(not tt_xor(a, b))

def tt_not_uncallable(a, b):
    log.fatal("Boolean not function was explicitly called.\n" \
              "This should not happen; not is implemented as xor with 1.\n" \
              "Cannot continue program execution.\n")
    raise RuntimeError

# Define schema information

precedence = {
    "ZERO" : 0,
    "LOW" : 1,
    "MEDIUM" : 2,
    "HIGH" : 3
}

SYM_NOT = "~"
SYM_XOR = "+"
SYM_XNOR = "@"
SYM_AND = "&"
SYM_NAND = "$"
SYM_OR = "|"
SYM_NOR = "%"

# TODO: possibly allow users to make their own precedence maps in the future
schema = {
    SYM_NOT : BooleanOperator(precedence["HIGH"], tt_not_uncallable, "not", "NOT", "~", "!"),
    SYM_XOR : BooleanOperator(precedence["MEDIUM"], tt_xor, "xor", "XOR"),
    SYM_XNOR : BooleanOperator(precedence["MEDIUM"], tt_xnor, "xnor", "XNOR", "nxor", "NXOR"),
    SYM_AND : BooleanOperator(precedence["LOW"], tt_and, "and", "AND", "&", "&&", "/\\"),
    SYM_NAND : BooleanOperator(precedence["LOW"], tt_nand, "nand", "NAND"),
    SYM_OR : BooleanOperator(precedence["ZERO"], tt_or, "or", "OR", "|", "||", "\\/"),
    SYM_NOR : BooleanOperator(precedence["ZERO"], tt_nor, "nor", "NOR")
}

schema_search_ordered_list = [SYM_XNOR, SYM_XOR, SYM_NOR, SYM_NAND, SYM_AND, SYM_OR, SYM_NOT]
Refactor boolean function definitions in schema_provider.