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; }
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; }
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; }
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(); }
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 (); }
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; } }
data_type_t typecheck_default(node_t* root) { typecheck_children(root); return root->data_type; }