import jit
import tree_ir

BINARY_INTRINSICS = {
    'value_eq' : '==',
    'value_neq' : '!=',

    'bool_and' : 'and',
    'bool_or' : 'or',

    'integer_addition' : '+',
    'integer_subtraction' : '-',
    'integer_multiplication' : '*',
    'integer_division' : '/',
    'integer_gt' : '>',
    'integer_gte' : '>=',
    'integer_lt' : '<',
    'integer_lte' : '<=',

    'float_addition' : '+',
    'float_subtraction' : '-',
    'float_multiplication' : '*',
    'float_division' : '/',
    'float_gt' : '>',
    'float_gte' : '>=',
    'float_lt' : '<',
    'float_lte' : '<='
}

UNARY_INTRINSICS = {
    'bool_not' : 'not',
    'integer_neg' : '-',
    'float_neg' : '-'
}

MISC_INTRINSICS = {
    # Reference equality
    'element_eq' :
        lambda a, b:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.BinaryInstruction(a, '==', b)),
    'element_neq' :
        lambda a, b:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.BinaryInstruction(a, '!=', b)),

    # Strings
    'string_get' :
        lambda a, b:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.LoadIndexInstruction(
                tree_ir.ReadValueInstruction(a),
                tree_ir.ReadValueInstruction(b))),
    'string_len' :
        lambda a:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.CallInstruction(
                tree_ir.LoadGlobalInstruction('len'),
                [tree_ir.ReadValueInstruction(a)])),
    'string_join' :
        lambda a, b:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.BinaryInstruction(
                tree_ir.CallInstruction(
                    tree_ir.LoadGlobalInstruction('str'),
                    [tree_ir.ReadValueInstruction(a)]),
                '+',
                tree_ir.CallInstruction(
                    tree_ir.LoadGlobalInstruction('str'),
                    [tree_ir.ReadValueInstruction(b)]))),
    'string_startswith' :
        lambda a, b:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.CallInstruction(
                tree_ir.LoadMemberInstruction(
                    tree_ir.ReadValueInstruction(a),
                    'startswith'),
                [tree_ir.ReadValueInstruction(b)])),

    # State creation
    'create_node' : tree_ir.CreateNodeInstruction,
    'create_edge' :
        # Lambda is totally necessary here, pylint.
        # You totally dropped the ball on this one.
        # pylint: disable=I0011,W0108
        lambda a, b:
        tree_ir.CreateEdgeInstruction(a, b),
    'create_value' :
        lambda a:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.ReadValueInstruction(a)),

    # State reads
    'read_edge_src' :
        lambda a:
        tree_ir.LoadIndexInstruction(
            tree_ir.ReadEdgeInstruction(a),
            tree_ir.LiteralInstruction(0)),
    'read_edge_dst' :
        lambda a:
        tree_ir.LoadIndexInstruction(
            tree_ir.ReadEdgeInstruction(a),
            tree_ir.LiteralInstruction(1)),
    'is_edge' :
        lambda a:
        tree_ir.CreateNodeWithValueInstruction(
            tree_ir.BinaryInstruction(
                tree_ir.LoadIndexInstruction(
                    tree_ir.ReadEdgeInstruction(a),
                    tree_ir.LiteralInstruction(0)),
                'is not',
                tree_ir.LiteralInstruction(None))),

    # Dictionary operations
    'dict_read' :
        lambda a, b:
        tree_ir.ReadDictionaryValueInstruction(
            a, tree_ir.ReadValueInstruction(b)),

    'dict_read_edge' :
        lambda a, b:
        tree_ir.ReadDictionaryEdgeInstruction(
            a, tree_ir.ReadValueInstruction(b))
}

def register_intrinsics(target_jit):
    """Registers all intrinsics in the module with the given JIT."""
    for (key, value) in BINARY_INTRINSICS.items():
        target_jit.register_binary_intrinsic(key, value)
    for (key, value) in UNARY_INTRINSICS.items():
        target_jit.register_unary_intrinsic(key, value)
    for (key, value) in MISC_INTRINSICS.items():
        target_jit.register_intrinsic(key, value)
