bool ASTNode::check_arglist (const char *funcname, ASTNode::ref arg, const char *formals, bool coerce) { // std::cerr << "ca " << funcname << " formals='" << formals << "\n"; for ( ; arg; arg = arg->next()) { if (! *formals) // More formal args, but no more actual args return false; if (*formals == '*') // Will match anything left return true; if (*formals == '.') { // Special case for token/value pairs // FIXME -- require that the tokens be string literals if (arg->typespec().is_string() && arg->next() != NULL) { arg = arg->next(); continue; } return false; } if (*formals == '?') { if (formals[1] == '[' && formals[2] == ']') { // Any array formals += 3; if (arg->typespec().is_array()) continue; // match else return false; // wanted an array, didn't get one } if (arg->typespec().is_array()) return false; // wanted any scalar, got an array formals += 1; continue; // match anything } TypeSpec argtype = arg->typespec(); int advance; TypeSpec formaltype = m_compiler->type_from_code (formals, &advance); formals += advance; // std::cerr << "\targ is " << argtype.string() // << ", formal is " << formaltype.string() << "\n"; if (argtype == formaltype) continue; // ok, move on to next arg if (coerce && assignable (formaltype, argtype)) continue; // Allow a fixed-length array match to a formal array with // unspecified length, if the element types are the same. if (formaltype.arraylength() < 0 && argtype.arraylength() && formaltype.elementtype() == argtype.elementtype()) continue; // anything that gets this far we don't consider a match return false; } if (*formals && *formals != '*' && *formals != '.') return false; // Non-*, non-... formals expected, no more actuals return true; // Is this safe? }
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); } }
ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp, const TypeSpec &type, ustring name, ASTNode *init, bool isparam, bool ismeta, bool isoutput, bool initlist) : ASTNode (variable_declaration_node, comp, 0, init, NULL /* meta */), m_name(name), m_sym(NULL), m_isparam(isparam), m_isoutput(isoutput), m_ismetadata(ismeta), m_initlist(initlist) { m_typespec = type; Symbol *f = comp->symtab().clash (name); if (f && ! m_ismetadata) { std::string e = Strutil::format ("\"%s\" already declared in this scope", name.c_str()); if (f->node()) { std::string filename = OIIO::Filesystem::filename(f->node()->sourcefile().string()); e += Strutil::format ("\n\t\tprevious declaration was at %s:%d", filename, f->node()->sourceline()); } if (f->scope() == 0 && f->symtype() == SymTypeFunction && isparam) { // special case: only a warning for param to mask global function warning ("%s", e.c_str()); } else { error ("%s", e.c_str()); } } if (name[0] == '_' && name[1] == '_' && name[2] == '_') { error ("\"%s\" : sorry, can't start with three underscores", name.c_str()); } SymType symtype = isparam ? (isoutput ? SymTypeOutputParam : SymTypeParam) : SymTypeLocal; // Sneaky debugging aid: a local that starts with "__debug_tmp__" // gets declared as a temp. Don't do this on purpose!!! if (symtype == SymTypeLocal && Strutil::starts_with (name, "__debug_tmp__")) symtype = SymTypeTemp; m_sym = new Symbol (name, type, symtype, this); if (! m_ismetadata) oslcompiler->symtab().insert (m_sym); // A struct really makes several subvariables if (type.is_structure() || type.is_structure_array()) { ASSERT (! m_ismetadata); // Add the fields as individual declarations m_compiler->add_struct_fields (type.structspec(), m_sym->name(), symtype, type.is_unsized_array() ? -1 : type.arraylength(), this, init); } }
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; } }
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; }