view sema/Operation.d @ 129:ed815b31479b

Added a Symbol
author Anders Halager <halager@gmail.com>
date Sat, 21 Jun 2008 20:41:18 +0200
parents 189c049cbfcc
children
line wrap: on
line source

module sema.Operation;

/// Operators
public enum Operator
{
    Add, Sub, Mul, Div, Rem,
    Shl, LShr, AShr,
    And, Or, Xor,

    Eq, Ne,
    Lt, Le,
    Gt, Ge,
}

/**
  Enum for the basic builtin operations.

  S for signed, U for unsigned and F for floating point.
 **/
public enum BuiltinOperation
{
    Add, Sub, Mul, SDiv, UDiv, FDiv, SRem, URem, FRem,

    // FShr is a dummy element to avoid special case for signed >> unsigned
    Shl, LShr, AShr, FShr,
    And, Or, Xor,

    Eq, Ne,
    SLt, ULt, FLt, SLe, ULe, FLe,
    SGt, UGt, FGt, SGe, UGe, FGe,

    None
}

/**
  Returns true if the operation has an unsigned variant.

  Will only be true for the S version, so SDiv gives true, UDiv or FDiv dont.
 **/
private bool hasUnsignedVariant(BuiltinOperation op)
{
    alias BuiltinOperation O;
    return op is O.SDiv
        || op is O.SRem
        || op is O.SLt
        || op is O.SLe
        || op is O.SGt
        || op is O.SGe;
}

/// Same as hasUnsignedVariant, but for float variants
private bool hasFloatVariant(BuiltinOperation op)
{
    alias BuiltinOperation O;
    return op is O.SDiv
        || op is O.SRem
        || op is O.SLt
        || op is O.SLe
        || op is O.SGt
        || op is O.SGe;
}

private BuiltinOperation OpToBI(Operator op)
{
    // This is dependent on the definition of Operator
    // Maps from an Operator to the first appropiate BuiltinOperation
    static const BuiltinOperation[] map =
        [
            BuiltinOperation.Add,
            BuiltinOperation.Sub,
            BuiltinOperation.Mul,
            BuiltinOperation.SDiv,
            BuiltinOperation.SRem,

            BuiltinOperation.Shl,
            BuiltinOperation.LShr,
            BuiltinOperation.AShr,
            BuiltinOperation.And,
            BuiltinOperation.Or,
            BuiltinOperation.Xor,

            BuiltinOperation.Eq,
            BuiltinOperation.Ne,
            BuiltinOperation.SLt,
            BuiltinOperation.SLe,
            BuiltinOperation.SGt,
            BuiltinOperation.SGe,

        ];
    if (op >= Operator.Add && op <= Operator.Ge)
        return map[op];

    return BuiltinOperation.None;
}

/**
    Represents an operation on to values of (potentionally) different types.

    Can be either some built-in thing (addition of floats, int etc) or a user
    defined operation (a method in a struct/class).
 **/
struct Operation
{
    /// Returns true if the operation is legal
    bool isPossible() { return is_valid; }

    /// True for <, <=, ==, !=, >, >=
    bool isComparison() { return false; }

    /// Built in operations like adding ints or floats
    bool isBuiltin() { return is_bi; }

    /// Get the builtin operation - only valid if isBuiltin() returns true
    BuiltinOperation builtinOp() { return bi_op; };

    /// Create builtin operation
    static Operation builtin(Operator op, bool unsigned, bool fp)
    {
        assert(!(unsigned && fp), "Can't be both unsigned and a float");
        Operation res;
        res.is_valid = true;
        res.is_bi = true;
        res.bi_op = OpToBI(op);

        if (unsigned && hasUnsignedVariant(res.bi_op))
            res.bi_op += 1;
        if (fp && hasFloatVariant(res.bi_op))
            res.bi_op += 2;
        return res;
    }

private:
    bool is_valid = false;
    bool is_bi;
    BuiltinOperation bi_op;
}