TypeSpec
ASTvariable_declaration::typecheck (TypeSpec expected)
{
    typecheck_children (m_typespec);

    if (! init())
        return m_typespec;

    if (m_typespec.is_structure() && ! m_initlist &&
        init()->typespec().structure() != m_typespec.structure()) {
        // Can't do:  struct foo = 1
        error ("Cannot initialize structure '%s' with a scalar value",
               name().c_str());
    }

    // If it's a compound initializer, look at the individual pieces
    ref init = this->init();
    if (init->nodetype() == compound_initializer_node) {
        ASSERT (! init->nextptr() &&
                "compound_initializer should be the only initializer");
        init = ((ASTcompound_initializer *)init.get())->initlist();
    }

    if (m_typespec.is_structure()) {
        // struct initialization handled separately
        return typecheck_struct_initializers (init);
    }

    typecheck_initlist (init, m_typespec, m_name.c_str());

    return m_typespec;
}
TypeSpec
ASTunary_expression::typecheck (TypeSpec expected)
{
    // FIXME - closures
    typecheck_children (expected);
    TypeSpec t = expr()->typespec();
    if (t.is_structure()) {
        error ("Can't do '%s' to a %s.", opname(), type_c_str(t));
        return TypeSpec ();
    }
    switch (m_op) {
    case Sub :
    case Add :
        if (t.is_string()) {
            error ("Can't do '%s' to a %s.", opname(), type_c_str(t));
            return TypeSpec ();
        }
        m_typespec = t;
        break;
    case Not :
        m_typespec = TypeDesc::TypeInt;  // ! is always an int
        break;
    case Compl :
        if (! t.is_int()) {
            error ("Operator '~' can only be done to an int");
            return TypeSpec ();
        }
        m_typespec = t;
        break;
    default:
        error ("unknown unary operator");
    }
    return m_typespec;
}
TypeSpec
ASTpreincdec::typecheck (TypeSpec expected)
{
    typecheck_children ();
    m_is_lvalue = var()->is_lvalue();
    m_typespec = var()->typespec();
    return m_typespec;
}
Example #4
0
TypeSpec
ASTNode::typecheck (TypeSpec expected)
{
    typecheck_children (expected);
    if (m_typespec == TypeSpec())
        m_typespec = expected;
    return m_typespec;
}
TypeSpec
ASTindex::typecheck (TypeSpec expected)
{
    typecheck_children ();
    const char *indextype = "";
    TypeSpec t = lvalue()->typespec();
    if (t.is_structure()) {
        error ("Cannot use [] indexing on a struct");
        return TypeSpec();
    }
    if (t.is_closure()) {
        error ("Cannot use [] indexing on a closure");
        return TypeSpec();
    }
    if (index3()) {
        if (! t.is_array() && ! t.elementtype().is_matrix())
            error ("[][][] only valid for a matrix array");
        m_typespec = TypeDesc::FLOAT;
    } else if (t.is_array()) {
        indextype = "array";
        m_typespec = t.elementtype();
        if (index2()) {
            if (t.aggregate() == TypeDesc::SCALAR)
                error ("can't use [][] on a simple array");
            m_typespec = TypeDesc::FLOAT;
        }
    } else if (t.aggregate() == TypeDesc::VEC3) {
        indextype = "component";
        TypeDesc tnew = t.simpletype();
        tnew.aggregate = TypeDesc::SCALAR;
        tnew.vecsemantics = TypeDesc::NOXFORM;
        m_typespec = tnew;
        if (index2())
            error ("can't use [][] on a %s", type_c_str(t));
    } else if (t.aggregate() == TypeDesc::MATRIX44) {
        indextype = "component";
        TypeDesc tnew = t.simpletype();
        tnew.aggregate = TypeDesc::SCALAR;
        tnew.vecsemantics = TypeDesc::NOXFORM;
        m_typespec = tnew;
        if (! index2())
            error ("must use [][] on a matrix, not just []");
    } else {
        error ("can only use [] indexing for arrays or multi-component types");
        return TypeSpec();
    }

    // Make sure the indices (children 1+) are integers
    for (size_t c = 1;  c < nchildren();  ++c)
        if (! child(c)->typespec().is_int())
            error ("%s index must be an integer, not a %s", 
                   indextype, type_c_str(index()->typespec()));

    // If the thing we're indexing is an lvalue, so is the indexed element
    m_is_lvalue = lvalue()->is_lvalue();

    return m_typespec;
}
TypeSpec
ASTpostincdec::typecheck (TypeSpec expected)
{
    typecheck_children ();
    if (! var()->is_lvalue())
        error ("%s can only be applied to an lvalue", nodetypename());
    m_is_lvalue = false;
    m_typespec = var()->typespec();
    return m_typespec;
}
TypeSpec
ASTtype_constructor::typecheck (TypeSpec expected)
{
    // FIXME - closures
    typecheck_children ();

    // Hijack the usual function arg-checking routines.
    // So we have a set of valid patterns for each type constructor:
    static const char *float_patterns[] = { "ff", "fi", NULL };
    static const char *triple_patterns[] = { "cf", "cfff", "csfff",
                                             "cc", "cp", "cv", "cn", NULL };
    static const char *matrix_patterns[] = { "mf", "msf", "mss",
                                             "mffffffffffffffff",
                                             "msffffffffffffffff", "mm", NULL };
    static const char *int_patterns[] = { "if", "ii", NULL };
    // Select the pattern for the type of constructor we are...
    const char **patterns = NULL;
    if (typespec().is_float())
        patterns = float_patterns;
    else if (typespec().is_triple())
        patterns = triple_patterns;
    else if (typespec().is_matrix())
        patterns = matrix_patterns;
    else if (typespec().is_int())
        patterns = int_patterns;
    if (! patterns) {
        error ("Cannot construct type '%s'", type_c_str(typespec()));
        return m_typespec;
    }

    // Try to get a match, first without type coercion of the arguments,
    // then with coercion.
    for (int co = 0;  co < 2;  ++co) {
        bool coerce = co;
        for (const char **pat = patterns;  *pat;  ++pat) {
            const char *code = *pat;
            if (check_arglist (type_c_str(typespec()), args(), code + 1, coerce))
                return m_typespec;
        }
    }

    // If we made it this far, no match could be found.
    std::string err = Strutil::format ("Cannot construct %s (", 
                                       type_c_str(typespec()));
    for (ref a = args();  a;  a = a->next()) {
        err += a->typespec().string();
        if (a->next())
            err += ", ";
    }
    err += ")";
    error ("%s", err.c_str());
    // FIXME -- it might be nice here to enumerate for the user all the
    // valid combinations.
    return m_typespec;
}
TypeSpec
ASTfunction_declaration::typecheck (TypeSpec expected)
{
    // Typecheck the args, remember to push/pop the function so that the
    // typechecking for 'return' will know which function it belongs to.
    oslcompiler->push_function (func ());
    typecheck_children (expected);
    oslcompiler->pop_function ();

    if (m_typespec == TypeSpec())
        m_typespec = expected;
    return m_typespec;
}
TypeSpec
ASTtypecast_expression::typecheck (TypeSpec expected)
{
    // FIXME - closures
    typecheck_children (m_typespec);
    TypeSpec t = expr()->typespec();
    if (! assignable (m_typespec, t) &&
        ! (m_typespec.is_int() && t.is_float()) && // (int)float is ok
        ! (m_typespec.is_triple() && t.is_triple()))
        error ("Cannot cast '%s' to '%s'", type_c_str(t),
               type_c_str(m_typespec));
    return m_typespec;
}
Example #10
0
TypeSpec
ASTstructselect::typecheck (TypeSpec expected)
{
    // The ctr already figured out if this was a valid structure selection
    if (m_fieldid < 0 || m_mangledsym == NULL)
        return TypeSpec();

    typecheck_children ();
    StructSpec *structspec (TypeSpec::structspec (m_structid));
    m_typespec = structspec->field(m_fieldid).type;
    m_is_lvalue = lvalue()->is_lvalue();
    return m_typespec;
}
Example #11
0
TypeSpec
ASTfunction_call::typecheck (TypeSpec expected)
{
    typecheck_children ();

    bool match = false;

    // Look for an exact match, including expected return type
    m_typespec = typecheck_all_poly (expected, false);
    if (m_typespec != TypeSpec())
        match = true;

    // Now look for an exact match on args, but any assignable return type
    if (! match && expected != TypeSpec()) {
        m_typespec = typecheck_all_poly (TypeSpec(), false);
        if (m_typespec != TypeSpec())
            match = true;
    }

    // Now look for a coercible match of args, exact march on return type
    if (! match) {
        m_typespec = typecheck_all_poly (expected, true);
        if (m_typespec != TypeSpec())
            match = true;
    }

    // All that failed, try for a coercible match on everything
    if (! match && expected != TypeSpec()) {
        m_typespec = typecheck_all_poly (TypeSpec(), true);
        if (m_typespec != TypeSpec())
            match = true;
    }

    if (match) {
        if (! is_user_function ())
            typecheck_builtin_specialcase ();
        return m_typespec;
    }

    // Couldn't find any way to match any polymorphic version of the
    // function that we know about.  OK, at least try for helpful error
    // message.
    std::string choices ("");
    for (FunctionSymbol *poly = func();  poly;  poly = poly->nextpoly()) {
        const char *code = poly->argcodes().c_str();
        int advance;
        TypeSpec returntype = m_compiler->type_from_code (code, &advance);
        code += advance;
        if (choices.length())
            choices += "\n";
        choices += Strutil::format ("\t%s %s (%s)",
                              type_c_str(returntype), m_name.c_str(),
                              m_compiler->typelist_from_code(code).c_str());
    }

    std::string actualargs;
    for (ASTNode::ref arg = args();  arg;  arg = arg->next()) {
        if (actualargs.length())
            actualargs += ", ";
        actualargs += arg->typespec().string();
    }

    error ("No matching function call to '%s (%s)'\n    Candidates are:\n%s", 
           m_name.c_str(), actualargs.c_str(), choices.c_str());
    return TypeSpec();
}
Example #12
0
TypeSpec
ASTbinary_expression::typecheck (TypeSpec expected)
{
    typecheck_children (expected);
    TypeSpec l = left()->typespec();
    TypeSpec r = right()->typespec();

    // No binary ops work on structs or arrays
    if (l.is_structure() || r.is_structure() || l.is_array() || r.is_array()) {
        error ("Not allowed: '%s %s %s'",
               type_c_str(l), opname(), type_c_str(r));
        return TypeSpec ();
    }

    // Special for closures -- just a few cases to worry about
    if (l.is_color_closure() || r.is_color_closure()) {
        if (m_op == Add) {
            if (l.is_color_closure() && r.is_color_closure())
                return m_typespec = l;
        }
        if (m_op == Mul) {
            if (l.is_color_closure() && (r.is_color() || r.is_int_or_float()))
                return m_typespec = l;
            if (r.is_color_closure() && (l.is_color() || l.is_int_or_float())) {
                // N.B. Reorder so that it's always r = closure * k,
                // not r = k * closure.  See codegen for why this helps.
                std::swap (m_children[0], m_children[1]);
                return m_typespec = r;
            }
        }
        // If we got this far, it's an op that's not allowed
        error ("Not allowed: '%s %s %s'",
               type_c_str(l), opname(), type_c_str(r));
        return TypeSpec ();
    }

    switch (m_op) {
    case Sub :
    case Add :
    case Mul :
    case Div :
        // Add/Sub/Mul/Div work for any equivalent types, and
        // combination of int/float and other numeric types, but do not
        // work with strings.  Add/Sub don't work with matrices, but
        // Mul/Div do.
        // FIXME -- currently, equivalent types combine to make the
        // left type.  But maybe we should be more careful, for example
        // point-point -> vector, etc.
        if (l.is_string() || r.is_string())
            break;   // Dispense with strings trivially
        if ((m_op == Sub || m_op == Add) && (l.is_matrix() || r.is_matrix()))
            break;   // Matrices don't combine for + and -
        if (equivalent (l, r) ||
                (l.is_numeric() && r.is_int_or_float()) ||
                (l.is_int_or_float() && r.is_numeric()))
            return m_typespec = higherprecision (l.simpletype(), r.simpletype());
        break;

    case Mod :
        // Mod only works with ints, and return ints.
        if (l.is_int() && r.is_int())
            return m_typespec = TypeDesc::TypeInt;
        break;

    case Equal :
    case NotEqual :
        // Any equivalent types can be compared with == and !=, also a 
        // float or int can be compared to any other numeric type.
        // Result is always an int.
        if (equivalent (l, r) || 
              (l.is_numeric() && r.is_int_or_float()) ||
              (l.is_int_or_float() && r.is_numeric()))
            return m_typespec = TypeDesc::TypeInt;
        break;

    case Greater :
    case Less :
    case GreaterEqual :
    case LessEqual :
        // G/L comparisons only work with floats or ints, and always
        // return int.
        if (l.is_int_or_float() && r.is_int_or_float())
            return m_typespec = TypeDesc::TypeInt;
        break;

    case BitAnd :
    case BitOr :
    case Xor :
    case ShiftLeft :
    case ShiftRight :
        // Bitwise ops only work with ints, and return ints.
        if (l.is_int() && r.is_int())
            return m_typespec = TypeDesc::TypeInt;
        break;

    case And :
    case Or :
        // Logical ops work on any simple type (since they test for
        // nonzeroness), but always return int.
        return m_typespec = TypeDesc::TypeInt;

    default:
        error ("unknown binary operator");
    }

    // If we got this far, it's an op that's not allowed
    error ("Not allowed: '%s %s %s'",
           type_c_str(l), opname(), type_c_str(r));
    return TypeSpec ();
}
Example #13
0
data_type_t typecheck_expression(node_t* root)
{

	if(outputStage == 10)
		fprintf( stderr, "Type checking expression %s\n", root->expression_type.text);

    switch (root->expression_type.index) {
        case ADD_E:
        case SUB_E:
        case MUL_E:
        case DIV_E:
            {
                data_type_t type1 = root->children[0]->typecheck(root->children[0]);
                data_type_t type2 = root->children[1]->typecheck(root->children[1]);
                if (type1.base_type == INT_TYPE && type2.base_type == INT_TYPE) {
                    return wrap_base_type(INT_TYPE);
                }
                if (type1.base_type == FLOAT_TYPE && type2.base_type == FLOAT_TYPE) {
                    return wrap_base_type(FLOAT_TYPE);
                }
                type_error(root);
            }
            break;
        case LESS_E:
        case GREATER_E:
        case GEQUAL_E:
        case LEQUAL_E:
            {
                data_type_t type1 = root->children[0]->typecheck(root->children[0]);
                data_type_t type2 = root->children[1]->typecheck(root->children[1]);
                if (type1.base_type == INT_TYPE && type2.base_type == INT_TYPE) {
                    return wrap_base_type(BOOL_TYPE);
                }
                if (type1.base_type == FLOAT_TYPE && type2.base_type == FLOAT_TYPE) {
                    return wrap_base_type(BOOL_TYPE);
                }
                type_error(root);
            }
            break;
        case EQUAL_E:
        case NEQUAL_E:
            {
                data_type_t type1 = root->children[0]->typecheck(root->children[0]);
                data_type_t type2 = root->children[1]->typecheck(root->children[1]);
                if (type1.base_type == INT_TYPE && type2.base_type == INT_TYPE) {
                    return wrap_base_type(BOOL_TYPE);
                }
                if (type1.base_type == FLOAT_TYPE && type2.base_type == FLOAT_TYPE) {
                    return wrap_base_type(BOOL_TYPE);
                }
                if (type1.base_type == BOOL_TYPE && type2.base_type == BOOL_TYPE) {
                    return wrap_base_type(BOOL_TYPE);
                }
                type_error(root);
            }
            break;
        case UMINUS_E:
            {
                data_type_t type = root->children[0]->typecheck(root->children[0]);

                if (type.base_type == INT_TYPE || type.base_type == FLOAT_TYPE) {
                    return type;
                }
                type_error(root);
            }
            break;
        case NOT_E:
            {
                data_type_t type = root->children[0]->typecheck(root->children[0]);
                if (type.base_type == BOOL_TYPE) {
                    return type;
                }
                type_error(root);
            }
            break;
        case AND_E:
        case OR_E:
            {
                data_type_t type1 = root->children[0]->typecheck(root->children[0]);
                data_type_t type2 = root->children[1]->typecheck(root->children[1]);
                if (type1.base_type == BOOL_TYPE && type2.base_type == BOOL_TYPE) {
                    return wrap_base_type(BOOL_TYPE);
                }
                type_error(root);
            }
            break;
        default:
            typecheck_children(root);
            return root->data_type;
    }
}
Example #14
0
data_type_t typecheck_default(node_t* root)
{
    typecheck_children(root);
    return root->data_type;
}