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? }
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(); }