TypeSpec ASTassign_expression::typecheck (TypeSpec expected) { TypeSpec vt = var()->typecheck (); TypeSpec et = expr()->typecheck (vt); if (! var()->is_lvalue()) { error ("Can't assign via %s to something that isn't an lvalue", opname()); return TypeSpec(); } ASSERT (m_op == Assign); // all else handled by binary_op // We don't currently support assignment of whole arrays if (vt.is_array() || et.is_array()) { error ("Can't assign entire arrays"); return TypeSpec(); } // Special case: ok to assign a literal 0 to a closure to // initialize it. if (vt.is_closure() && ! et.is_closure() && (et.is_float() || et.is_int()) && expr()->nodetype() == literal_node && ((ASTliteral *)&(*expr()))->floatval() == 0.0f) { return TypeSpec(); // it's ok } // If either argument is a structure, they better both be the same // exact kind of structure. if (vt.is_structure() || et.is_structure()) { int vts = vt.structure(), ets = et.structure(); if (vts == ets) return m_typespec = vt; // Otherwise, a structure mismatch error ("Cannot assign '%s' to '%s'", type_c_str(et), type_c_str(vt)); return TypeSpec(); } // Expression must be of a type assignable to the lvalue if (! assignable (vt, et)) { error ("Cannot assign '%s' to '%s'", type_c_str(et), type_c_str(vt)); // FIXME - can we print the variable in question? return TypeSpec(); } return m_typespec = vt; }
TypeSpec ASTternary_expression::typecheck (TypeSpec expected) { // FIXME - closures TypeSpec c = typecheck_list (cond(), TypeDesc::TypeInt); TypeSpec t = typecheck_list (trueexpr(), expected); TypeSpec f = typecheck_list (falseexpr(), expected); if (c.is_closure()) error ("Cannot use a closure as a condition"); if (c.is_structure()) error ("Cannot use a struct as a condition"); if (c.is_array()) error ("Cannot use an array as a condition"); // No arrays if (t.is_array() || t.is_array()) { error ("Not allowed: '%s ? %s : %s'", type_c_str(c), type_c_str(t), type_c_str(f)); return TypeSpec (); } // The true and false clauses need to be equivalent types, or one // needs to be assignable to the other (so one can be upcast). if (assignable (t, f) || assignable (f, t)) m_typespec = higherprecision (t.simpletype(), f.simpletype()); else error ("Not allowed: '%s ? %s : %s'", type_c_str(c), type_c_str(t), type_c_str(f)); return m_typespec; }
void ASTvariable_declaration::typecheck_initlist (ref init, TypeSpec type, const char *name) { // Loop over a list of initializers (it's just 1 if not an array)... for (int i = 0; init; init = init->next(), ++i) { // Check for too many initializers for an array if (type.is_array() && i > type.arraylength()) { error ("Too many initializers for a '%s'", type_c_str(type)); break; } // Special case: ok to assign a literal 0 to a closure to // initialize it. if (type.is_closure() && ! init->typespec().is_closure() && init->typespec().is_int_or_float() && init->nodetype() == literal_node && ((ASTliteral *)init.get())->floatval() == 0.0f) { continue; // it's ok } if (! type.is_array() && i > 0) error ("Can't assign array initializers to non-array %s %s", type_c_str(type), name); if (! assignable(type.elementtype(), init->typespec())) error ("Can't assign '%s' to %s %s", type_c_str(init->typespec()), type_c_str(type), name); } }
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; }
void OSOReaderQuery::symbol (SymType symtype, TypeSpec typespec, const char *name) { if (symtype == SymTypeParam || symtype == SymTypeOutputParam) { m_reading_param = true; OSLQuery::Parameter p; p.name = name; p.type = typespec.simpletype(); // FIXME -- struct & closure p.isoutput = (symtype == SymTypeOutputParam); p.varlenarray = (typespec.arraylength() < 0); p.isstruct = typespec.is_structure(); p.isclosure = typespec.is_closure(); m_query.m_params.push_back (p); } else { m_reading_param = false; } }
TypeSpec ASTconditional_statement::typecheck (TypeSpec expected) { typecheck_list (cond ()); oslcompiler->push_nesting (false); typecheck_list (truestmt ()); typecheck_list (falsestmt ()); oslcompiler->pop_nesting (false); TypeSpec c = cond()->typespec(); if (c.is_closure()) error ("Cannot use a closure as an 'if' condition"); if (c.is_structure()) error ("Cannot use a struct as an 'if' condition"); if (c.is_array()) error ("Cannot use an array as an 'if' condition"); return m_typespec = TypeDesc (TypeDesc::NONE); }
TypeSpec ASTloop_statement::typecheck (TypeSpec expected) { typecheck_list (init ()); oslcompiler->push_nesting (true); typecheck_list (cond ()); typecheck_list (iter ()); typecheck_list (stmt ()); oslcompiler->pop_nesting (true); TypeSpec c = cond()->typespec(); if (c.is_closure()) error ("Cannot use a closure as an '%s' condition", opname()); if (c.is_structure()) error ("Cannot use a struct as an '%s' condition", opname()); if (c.is_array()) error ("Cannot use an array as an '%s' condition", opname()); return m_typespec = TypeDesc (TypeDesc::NONE); }
std::string OSLCompilerImpl::code_from_type (TypeSpec type) const { std::string out; TypeDesc elem = type.elementtype().simpletype(); if (type.is_structure()) { out = Strutil::format ("S%d", type.structure()); } else if (type.is_closure()) { out = 'C'; } else { if (elem == TypeDesc::TypeInt) out = 'i'; else if (elem == TypeDesc::TypeFloat) out = 'f'; else if (elem == TypeDesc::TypeColor) out = 'c'; else if (elem == TypeDesc::TypePoint) out = 'p'; else if (elem == TypeDesc::TypeVector) out = 'v'; else if (elem == TypeDesc::TypeNormal) out = 'n'; else if (elem == TypeDesc::TypeMatrix) out = 'm'; else if (elem == TypeDesc::TypeString) out = 's'; else if (elem == TypeDesc::NONE) out = 'x'; else ASSERT (0); } if (type.is_array()) { int len = type.arraylength (); if (len > 0) out += Strutil::format ("[%d]", len); else out += "[]"; } return out; }