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 OSLCompilerImpl::write_oso_symbol (const Symbol *sym) { // symtype / datatype / name oso ("%s\t%s\t%s", sym->symtype_shortname(), type_c_str(sym->typespec()), sym->mangled().c_str()); ASTvariable_declaration *v = NULL; if (sym->node() && sym->node()->nodetype() == ASTNode::variable_declaration_node) v = static_cast<ASTvariable_declaration *>(sym->node()); // Print default values bool isparam = (sym->symtype() == SymTypeParam || sym->symtype() == SymTypeOutputParam); if (sym->symtype() == SymTypeConst) { oso ("\t"); write_oso_const_value (static_cast<const ConstantSymbol *>(sym)); oso ("\t"); } else if (v && isparam) { std::string out; v->param_default_literals (sym, out); oso ("\t%s\t", out.c_str()); } // // Now output all the hints, which is most of the work! // int hints = 0; // %meta{} encodes metadata (handled by write_oso_metadata) if (v) { ASSERT (v); for (ASTNode::ref m = v->meta(); m; m = m->next()) { if (hints++ == 0) oso ("\t"); write_oso_metadata (m.get()); } } // %read and %write give the range of ops over which a symbol is used. if (hints++ == 0) oso ("\t"); oso (" %%read{%d,%d} %%write{%d,%d}", sym->firstread(), sym->lastread(), sym->firstwrite(), sym->lastwrite()); // %struct, %structfields, and %structfieldtypes document the // definition of a structure and which other symbols comprise the // individual fields. if (sym->typespec().is_structure()) { if (hints++ == 0) oso ("\t"); const StructSpec *structspec (sym->typespec().structspec()); std::string fieldlist, signature; for (int i = 0; i < (int)structspec->numfields(); ++i) { if (i > 0) fieldlist += ","; fieldlist += structspec->field(i).name.string(); signature += code_from_type (structspec->field(i).type); } oso (" %%struct{\"%s\"} %%structfields{%s} %%structfieldtypes{\"%s\"} %%structnfields{%d}", structspec->mangled().c_str(), fieldlist.c_str(), signature.c_str(), structspec->numfields()); } // %mystruct and %mystructfield document the symbols holding structure // fields, linking them back to the structures they are part of. if (sym->fieldid() >= 0) { if (hints++ == 0) oso ("\t"); ASTvariable_declaration *vd = (ASTvariable_declaration *) sym->node(); oso (" %%mystruct{%s} %%mystructfield{%d}", vd->sym()->mangled().c_str(), sym->fieldid()); } // %derivs hint marks symbols that need to carry derivatives if (sym->has_derivs()) { if (hints++ == 0) oso ("\t"); oso (" %%derivs"); } #if 0 // this is recomputed by the runtime optimizer, no need to bloat the .oso with these // %depends marks, for potential OUTPUTs, which symbols they depend // upon. This is so that derivativeness, etc., may be // back-propagated as shader networks are linked together. if (isparam || sym->symtype() == SymTypeGlobal) { // FIXME const SymPtrSet &deps (m_symdeps[sym]); std::vector<const Symbol *> inputdeps; BOOST_FOREACH (const Symbol *d, deps) if (d->symtype() == SymTypeParam || d->symtype() == SymTypeOutputParam || d->symtype() == SymTypeGlobal || d->symtype() == SymTypeLocal || d->symtype() == SymTypeTemp) inputdeps.push_back (d); if (inputdeps.size()) { if (hints++ == 0) oso ("\t"); oso (" %%depends{"); int deps = 0; for (size_t i = 0; i < inputdeps.size(); ++i) { if (inputdeps[i]->symtype() == SymTypeTemp && inputdeps[i]->dealias() != inputdeps[i]) continue; // Skip aliased temporaries if (deps++) oso (","); oso ("%s", inputdeps[i]->mangled().c_str()); } oso ("}"); } } #endif oso ("\n"); }
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(); }
void OSLCompilerImpl::write_oso_file (const std::string &outfilename, string_view options) { ASSERT (m_osofile != NULL && m_osofile->good()); oso ("OpenShadingLanguage %d.%02d\n", OSO_FILE_VERSION_MAJOR, OSO_FILE_VERSION_MINOR); oso ("# Compiled by oslc %s\n", OSL_LIBRARY_VERSION_STRING); oso ("# options: %s\n", options); ASTshader_declaration *shaderdecl = shader_decl(); oso ("%s %s", shaderdecl->shadertypename(), shaderdecl->shadername().c_str()); // output global hints and metadata int hints = 0; for (ASTNode::ref m = shaderdecl->metadata(); m; m = m->next()) { if (hints++ == 0) oso ("\t"); write_oso_metadata (m.get()); } oso ("\n"); // Output params, so they are first BOOST_FOREACH (const Symbol *s, symtab()) { if (s->symtype() == SymTypeParam || s->symtype() == SymTypeOutputParam) write_oso_symbol (s); } // Output globals, locals, temps, const BOOST_FOREACH (const Symbol *s, symtab()) { if (s->symtype() == SymTypeLocal || s->symtype() == SymTypeTemp || s->symtype() == SymTypeGlobal || s->symtype() == SymTypeConst) { // Don't bother writing symbols that are never used if (s->lastuse() >= 0) { write_oso_symbol (s); } } } // Output all opcodes int lastline = -1; ustring lastfile; ustring lastmethod ("___uninitialized___"); for (OpcodeVec::iterator op = m_ircode.begin(); op != m_ircode.end(); ++op) { if (lastmethod != op->method()) { oso ("code %s\n", op->method().c_str()); lastmethod = op->method(); lastfile = ustring(); lastline = -1; } if (/*m_debug &&*/ op->sourcefile()) { ustring file = op->sourcefile(); int line = op->sourceline(); if (file != lastfile || line != lastline) oso ("# %s:%d\n# %s\n", file.c_str(), line, retrieve_source (file, line).c_str()); } // Op name oso ("\t%s", op->opname().c_str()); // Register arguments if (op->nargs()) oso (op->opname().length() < 8 ? "\t\t" : "\t"); for (int i = 0; i < op->nargs(); ++i) { int arg = op->firstarg() + i; oso ("%s ", m_opargs[arg]->dealias()->mangled().c_str()); } // Jump targets for (size_t i = 0; i < Opcode::max_jumps; ++i) if (op->jump(i) >= 0) oso ("%d ", op->jump(i)); // // Opcode Hints // bool firsthint = true; // %filename and %line document the source code file and line that // contained code that generated this op. To avoid clutter, we // only output these hints when they DIFFER from the previous op. if (op->sourcefile()) { if (op->sourcefile() != lastfile) { lastfile = op->sourcefile(); oso ("%c%%filename{\"%s\"}", firsthint ? '\t' : ' ', lastfile.c_str()); firsthint = false; } if (op->sourceline() != lastline) { lastline = op->sourceline(); oso ("%c%%line{%d}", firsthint ? '\t' : ' ', lastline); firsthint = false; } } // %argrw documents which arguments are read, written, or both (rwW). if (op->nargs()) { oso ("%c%%argrw{\"", firsthint ? '\t' : ' '); for (int i = 0; i < op->nargs(); ++i) { if (op->argwrite(i)) oso (op->argread(i) ? "W" : "w"); else oso (op->argread(i) ? "r" : "-"); } oso ("\"}"); firsthint = false; } // %argderivs documents which arguments have derivs taken of // them by the op. if (op->argtakesderivs_all()) { oso (" %%argderivs{"); int any = 0; for (int i = 0; i < op->nargs(); ++i) if (op->argtakesderivs(i)) { if (any++) oso (","); oso ("%d", i); } oso ("}"); firsthint = false; } oso ("\n"); } if (lastmethod != main_method_name()) // If no code, still need a code marker oso ("code %s\n", main_method_name().c_str()); oso ("\tend\n"); m_osofile = NULL; }