std::string tesla::BaseName(const Argument& A) { switch (A.type()) { case Argument::Any: case Argument::Constant: assert(false && "called BaseName() on a non-variable Argument"); case Argument::Variable: return A.name(); case Argument::Indirect: return BaseName(A.indirection()); case Argument::Field: return BaseName(A.field().base()); } }
void CheckDeclaration::checkFunctionArguments(Function *fun) { if (! _checkAnonymousArguments) return; if (_scope->isClassScope() && fun->isPublic()) { for (unsigned argc = 0; argc < fun->argumentCount(); ++argc) { Argument *arg = fun->argumentAt(argc)->asArgument(); assert(arg != 0); if (! arg->name()) { translationUnit()->warning(arg->sourceLocation(), "anonymous argument"); } } } }
void tst_Lookup::iface_impl_scoping() { const QByteArray source = "\n" "@interface Scooping{}-(int)method1:(int)arg;-(void)method2;@end\n" "@implementation Scooping-(int)method1:(int)arg{return arg;}@end\n"; Document::Ptr doc = Document::create("class_with_protocol_with_protocol"); doc->setUtf8Source(source); doc->parse(); doc->check(); QVERIFY(doc->diagnosticMessages().isEmpty()); QCOMPARE(doc->globalSymbolCount(), 2U); Snapshot snapshot; snapshot.insert(doc); ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass(); QVERIFY(iface); QVERIFY(iface->isInterface()); ObjCClass *impl = doc->globalSymbolAt(1)->asObjCClass(); QVERIFY(impl); QVERIFY(!impl->isInterface()); QCOMPARE(iface->memberCount(), 2U); QCOMPARE(impl->memberCount(), 1U); ObjCMethod *method1Impl = impl->memberAt(0)->asObjCMethod(); QVERIFY(method1Impl); QCOMPARE(method1Impl->identifier()->chars(), "method1"); // get the body of method1 QCOMPARE(method1Impl->memberCount(), 2U); Argument *method1Arg = method1Impl->memberAt(0)->asArgument(); QVERIFY(method1Arg); QCOMPARE(method1Arg->identifier()->chars(), "arg"); QVERIFY(method1Arg->type()->isIntegerType()); Block *method1Body = method1Impl->memberAt(1)->asBlock(); QVERIFY(method1Body); const LookupContext context(doc, snapshot); { // verify if we can resolve "arg" in the body QCOMPARE(method1Impl->argumentCount(), 1U); Argument *arg = method1Impl->argumentAt(0)->asArgument(); QVERIFY(arg); QVERIFY(arg->name()); QVERIFY(arg->name()->identifier()); QCOMPARE(arg->name()->identifier()->chars(), "arg"); QVERIFY(arg->type()->isIntegerType()); const QList<LookupItem> candidates = context.lookup(arg->name(), method1Body->enclosingScope()); QCOMPARE(candidates.size(), 1); QVERIFY(candidates.at(0).declaration()->type()->asIntegerType()); } Declaration *method2 = iface->memberAt(1)->asDeclaration(); QVERIFY(method2); QCOMPARE(method2->identifier()->chars(), "method2"); { // verify if we can resolve "method2" in the body const QList<LookupItem> candidates = context.lookup(method2->name(), method1Body->enclosingScope()); QCOMPARE(candidates.size(), 1); QCOMPARE(candidates.at(0).declaration(), method2); } }
void QalculateSyntaxHelpObject::fetchInformation() { std::string cmd = command().remove(QLatin1String("help")).simplified().toLatin1().data(); qDebug() << "HELP CALLED FOR:" << QLatin1String(cmd.c_str()); if (cmd == "plot") { setPlotInformation(); return; } if (cmd == "saveVariables") { setSaveVariablesInformation(); return; } if (cmd == "loadVariables") { setLoadVariablesInformation(); return; } ExpressionItem *item = CALCULATOR->getActiveExpressionItem(cmd); if (!item) { m_answer = i18n("No function, variable or unit with specified name exist."); return; } switch(item->type()) { case TYPE_FUNCTION: MathFunction *f = (MathFunction*) item; QString title = i18n("Function: %1", QLatin1String(item->title().c_str())); const ExpressionName *ename = &f->preferredName(false); int iargs = f->maxargs(); if(iargs < 0) { iargs = f->minargs() + 1; } QString str,str2,syntax; str += QLatin1String(ename->name.c_str()); str += QLatin1String("("); if(iargs != 0) { Argument *arg; Argument default_arg; for(int i2 = 1; i2 <= iargs; i2++) { if(i2 > f->minargs()) { str += QLatin1String("["); } if(i2 > 1) { str += QLatin1String(CALCULATOR->getComma().c_str()); str += QLatin1String(" "); } arg = f->getArgumentDefinition(i2); if(arg && !arg->name().empty()) { str2 = QLatin1String(arg->name().c_str()); } else { str2 = QLatin1String("argument"); str2 += QLatin1String(" "); str2 += QString::number(i2); } str += str2; if(i2 > f->minargs()) { str += QLatin1String("]"); } } if(f->maxargs() < 0) { str += QLatin1String(CALCULATOR->getComma().c_str()); str += QLatin1String(" ..."); } } str += QLatin1String(")"); syntax = QString::fromLatin1("<p>%1</p>").arg(str); QString arguments = QLatin1String(""); if(iargs != 0) { Argument *arg; Argument default_arg; for(int i2 = 1; i2 <= iargs; i2++) { arg = f->getArgumentDefinition(i2); if(arg && !arg->name().empty()) { str = QLatin1String(arg->name().c_str()); } else { str = QString::number(i2); } str += QLatin1String(": "); if(arg) { str2 = QLatin1String(arg->printlong().c_str()); } else { str2 = QLatin1String(default_arg.printlong().c_str()); } if(i2 > f->minargs()) { str2 += QLatin1String(" ("); //optional argument, in description str2 += QLatin1String("optional"); if(!f->getDefaultValue(i2).empty()) { str2 += QLatin1String(", "); //argument default, in description str2 += QLatin1String("default: "); str2 += QLatin1String(f->getDefaultValue(i2).c_str()); } str2 += QLatin1String(")"); } str += str2; arguments += QString::fromLatin1("<p>%1</p>").arg(str); } } QString desc = QString::fromLatin1("<p>%1</p>").arg(QLatin1String(item->description().c_str())); m_answer = title + desc + syntax + arguments; setHtml(QLatin1String("<p style='white-space:pre'>") + syntax + QLatin1String("</p>")); emit done(); } }
void bind(std::string type, std::string name, Parameters* ps, Arguments* as, Context* ctx, Env* env, Eval* eval) { std::string callee(type + " " + name); Listize listize(ctx->mem); std::map<std::string, Parameter*> param_map; for (size_t i = 0, L = as->length(); i < L; ++i) { if (auto str = dynamic_cast<String_Quoted*>((*as)[i]->value())) { // force optional quotes (only if needed) if (str->quote_mark()) { str->quote_mark('*'); str->is_delayed(true); } } } // Set up a map to ensure named arguments refer to actual parameters. Also // eval each default value left-to-right, wrt env, populating env as we go. for (size_t i = 0, L = ps->length(); i < L; ++i) { Parameter* p = (*ps)[i]; param_map[p->name()] = p; // if (p->default_value()) { // env->local_frame()[p->name()] = p->default_value()->perform(eval->with(env)); // } } // plug in all args; if we have leftover params, deal with it later size_t ip = 0, LP = ps->length(); size_t ia = 0, LA = as->length(); while (ia < LA) { Argument* a = (*as)[ia]; if (ip >= LP) { // skip empty rest arguments if (a->is_rest_argument()) { if (List* l = dynamic_cast<List*>(a->value())) { if (l->length() == 0) { ++ ia; continue; } } } std::stringstream msg; msg << "wrong number of arguments (" << LA << " for " << LP << ")"; msg << " for `" << name << "'"; return error(msg.str(), as->pstate()); } Parameter* p = (*ps)[ip]; // If the current parameter is the rest parameter, process and break the loop if (p->is_rest_parameter()) { // The next argument by coincidence provides a rest argument if (a->is_rest_argument()) { // We should always get a list for rest arguments if (List* rest = dynamic_cast<List*>(a->value())) { // create a new list object for wrapped items List* arglist = SASS_MEMORY_NEW(ctx->mem, List, p->pstate(), 0, rest->separator(), true); // wrap each item from list as an argument for (Expression* item : rest->elements()) { if (Argument* arg = dynamic_cast<Argument*>(item)) { (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, *arg); } else { (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, item->pstate(), item, "", false, false); } } // assign new arglist to environment env->local_frame()[p->name()] = arglist; } // invalid state else { throw std::runtime_error("invalid state"); } } else if (a->is_keyword_argument()) { // expand keyword arguments into their parameters List* arglist = SASS_MEMORY_NEW(ctx->mem, List, p->pstate(), 0, SASS_COMMA, true); env->local_frame()[p->name()] = arglist; Map* argmap = static_cast<Map*>(a->value()); for (auto key : argmap->keys()) { std::string name = unquote(static_cast<String_Constant*>(key)->value()); (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, key->pstate(), argmap->at(key), "$" + name, false, false); } } else { // create a new list object for wrapped items List* arglist = SASS_MEMORY_NEW(ctx->mem, List, p->pstate(), 0, SASS_COMMA, true); // consume the next args while (ia < LA) { // get and post inc a = (*as)[ia++]; // maybe we have another list as argument List* ls = dynamic_cast<List*>(a->value()); // skip any list completely if empty if (ls && ls->empty() && a->is_rest_argument()) continue; if (Argument* arg = dynamic_cast<Argument*>(a->value())) { (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, *arg); } // check if we have rest argument else if (a->is_rest_argument()) { // preserve the list separator from rest args if (List* rest = dynamic_cast<List*>(a->value())) { arglist->separator(rest->separator()); for (size_t i = 0, L = rest->size(); i < L; ++i) { (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, (*rest)[i]->pstate(), (*rest)[i], "", false, false); } } // no more arguments break; } // wrap all other value types into Argument else { (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, a->pstate(), a->value(), a->name(), false, false); } } // assign new arglist to environment env->local_frame()[p->name()] = arglist; } // consumed parameter ++ip; // no more paramaters break; } // If the current argument is the rest argument, extract a value for processing else if (a->is_rest_argument()) { // normal param and rest arg List* arglist = static_cast<List*>(a->value()); // empty rest arg - treat all args as default values if (!arglist->length()) { break; } else { if (arglist->length() > LP - ip && !ps->has_rest_parameter()) { size_t arg_count = (arglist->length() + LA - 1); std::stringstream msg; msg << callee << " takes " << LP; msg << (LP == 1 ? " argument" : " arguments"); msg << " but " << arg_count; msg << (arg_count == 1 ? " was passed" : " were passed."); deprecated_bind(msg.str(), as->pstate()); while (arglist->length() > LP - ip) { arglist->elements().erase(arglist->elements().end() - 1); } } } // otherwise move one of the rest args into the param, converting to argument if necessary if (!(a = dynamic_cast<Argument*>((*arglist)[0]))) { Expression* a_to_convert = (*arglist)[0]; a = SASS_MEMORY_NEW(ctx->mem, Argument, a_to_convert->pstate(), a_to_convert, "", false, false); } arglist->elements().erase(arglist->elements().begin()); if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) { ++ia; } } else if (a->is_keyword_argument()) { Map* argmap = static_cast<Map*>(a->value()); for (auto key : argmap->keys()) { std::string name = "$" + unquote(static_cast<String_Constant*>(key)->value()); if (!param_map.count(name)) { std::stringstream msg; msg << callee << " has no parameter named " << name; error(msg.str(), a->pstate()); } env->local_frame()[name] = argmap->at(key); } ++ia; continue; } else { ++ia; } if (a->name().empty()) { if (env->has_local(p->name())) { std::stringstream msg; msg << "parameter " << p->name() << " provided more than once in call to " << callee; error(msg.str(), a->pstate()); } // ordinal arg -- bind it to the next param env->local_frame()[p->name()] = a->value(); ++ip; } else { // named arg -- bind it to the appropriately named param if (!param_map.count(a->name())) { std::stringstream msg; msg << callee << " has no parameter named " << a->name(); error(msg.str(), a->pstate()); } if (param_map[a->name()]->is_rest_parameter()) { std::stringstream msg; msg << "argument " << a->name() << " of " << callee << "cannot be used as named argument"; error(msg.str(), a->pstate()); } if (env->has_local(a->name())) { std::stringstream msg; msg << "parameter " << p->name() << "provided more than once in call to " << callee; error(msg.str(), a->pstate()); } env->local_frame()[a->name()] = a->value(); } } // EO while ia // If we make it here, we're out of args but may have leftover params. // That's only okay if they have default values, or were already bound by // named arguments, or if it's a single rest-param. for (size_t i = ip; i < LP; ++i) { Parameter* leftover = (*ps)[i]; // cerr << "env for default params:" << endl; // env->print(); // cerr << "********" << endl; if (!env->has_local(leftover->name())) { if (leftover->is_rest_parameter()) { env->local_frame()[leftover->name()] = SASS_MEMORY_NEW(ctx->mem, List, leftover->pstate(), 0, SASS_COMMA, true); } else if (leftover->default_value()) { Expression* dv = leftover->default_value()->perform(eval); env->local_frame()[leftover->name()] = dv; } else { // param is unbound and has no default value -- error std::stringstream msg; msg << "required parameter " << leftover->name() << " is missing in call to " << callee; error(msg.str(), as->pstate()); } } } return; }
inline void debug_ast(AST_Node* node, std::string ind, Env* env) { if (node == 0) return; if (ind == "") std::cerr << "####################################################################\n"; if (dynamic_cast<Bubble*>(node)) { Bubble* bubble = dynamic_cast<Bubble*>(node); std::cerr << ind << "Bubble " << bubble; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << bubble->tabs(); std::cerr << std::endl; } else if (dynamic_cast<At_Root_Block*>(node)) { At_Root_Block* root_block = dynamic_cast<At_Root_Block*>(node); std::cerr << ind << "At_Root_Block " << root_block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << root_block->tabs(); std::cerr << std::endl; debug_ast(root_block->expression(), ind + ":", env); debug_ast(root_block->block(), ind + " ", env); } else if (dynamic_cast<Selector_List*>(node)) { Selector_List* selector = dynamic_cast<Selector_List*>(node); std::cerr << ind << "Selector_List " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " [@media:" << selector->media_block() << "]"; std::cerr << (selector->is_optional() ? " [is_optional]": " -"); std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -"); std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); } // } else if (dynamic_cast<Expression*>(node)) { // Expression* expression = dynamic_cast<Expression*>(node); // std::cerr << ind << "Expression " << expression << " " << expression->concrete_type() << std::endl; } else if (dynamic_cast<Parent_Selector*>(node)) { Parent_Selector* selector = dynamic_cast<Parent_Selector*>(node); std::cerr << ind << "Parent_Selector " << selector; // if (selector->not_selector()) cerr << " [in_declaration]"; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; // debug_ast(selector->selector(), ind + "->", env); } else if (dynamic_cast<Complex_Selector*>(node)) { Complex_Selector* selector = dynamic_cast<Complex_Selector*>(node); std::cerr << ind << "Complex_Selector " << selector << " (" << pstate_source_position(node) << ")" << " <" << selector->hash() << ">" << " [weight:" << longToHex(selector->specificity()) << "]" << " [@media:" << selector->media_block() << "]" << (selector->is_optional() ? " [is_optional]": " -") << (selector->has_parent_ref() ? " [has parent]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << (selector->has_line_break() ? " [line-break]": " -") << " -- "; std::string del; switch (selector->combinator()) { case Complex_Selector::PARENT_OF: del = ">"; break; case Complex_Selector::PRECEDES: del = "~"; break; case Complex_Selector::ADJACENT_TO: del = "+"; break; case Complex_Selector::ANCESTOR_OF: del = " "; break; case Complex_Selector::REFERENCE: del = "//"; break; } // if (del = "/") del += selector->reference()->perform(&to_string) + "/"; std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; debug_ast(selector->head(), ind + " " /* + "[" + del + "]" */, env); if (selector->tail()) { debug_ast(selector->tail(), ind + "{" + del + "}", env); } else if(del != " ") { std::cerr << ind << " |" << del << "| {trailing op}" << std::endl; } SourcesSet set = selector->sources(); // debug_sources_set(set, ind + " @--> "); } else if (dynamic_cast<Compound_Selector*>(node)) { Compound_Selector* selector = dynamic_cast<Compound_Selector*>(node); std::cerr << ind << "Compound_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " [weight:" << longToHex(selector->specificity()) << "]"; std::cerr << " [@media:" << selector->media_block() << "]"; std::cerr << (selector->extended() ? " [extended]": " -"); std::cerr << (selector->is_optional() ? " [is_optional]": " -"); std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -"); std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Propset*>(node)) { Propset* selector = dynamic_cast<Propset*>(node); std::cerr << ind << "Propset " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << selector->tabs() << std::endl; if (selector->block()) for(auto i : selector->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Wrapped_Selector*>(node)) { Wrapped_Selector* selector = dynamic_cast<Wrapped_Selector*>(node); std::cerr << ind << "Wrapped_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <<" << selector->ns_name() << ">>"; std::cerr << (selector->is_optional() ? " [is_optional]": " -"); std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -"); std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; debug_ast(selector->selector(), ind + " () ", env); } else if (dynamic_cast<Pseudo_Selector*>(node)) { Pseudo_Selector* selector = dynamic_cast<Pseudo_Selector*>(node); std::cerr << ind << "Pseudo_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <<" << selector->ns_name() << ">>"; std::cerr << (selector->is_optional() ? " [is_optional]": " -"); std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -"); std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; debug_ast(selector->expression(), ind + " <= ", env); } else if (dynamic_cast<Attribute_Selector*>(node)) { Attribute_Selector* selector = dynamic_cast<Attribute_Selector*>(node); std::cerr << ind << "Attribute_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <<" << selector->ns_name() << ">>"; std::cerr << (selector->is_optional() ? " [is_optional]": " -"); std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -"); std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env); } else if (dynamic_cast<Selector_Qualifier*>(node)) { Selector_Qualifier* selector = dynamic_cast<Selector_Qualifier*>(node); std::cerr << ind << "Selector_Qualifier " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <<" << selector->ns_name() << ">>"; std::cerr << (selector->is_optional() ? " [is_optional]": " -"); std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -"); std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << std::endl; } else if (dynamic_cast<Type_Selector*>(node)) { Type_Selector* selector = dynamic_cast<Type_Selector*>(node); std::cerr << ind << "Type_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <<" << selector->ns_name() << ">>"; std::cerr << (selector->is_optional() ? " [is_optional]": " -"); std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -"); std::cerr << (selector->has_line_break() ? " [line-break]": " -"); std::cerr << (selector->has_line_feed() ? " [line-feed]": " -"); std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">"; std::cerr << std::endl; } else if (dynamic_cast<Selector_Placeholder*>(node)) { Selector_Placeholder* selector = dynamic_cast<Selector_Placeholder*>(node); std::cerr << ind << "Selector_Placeholder [" << selector->ns_name() << "] " << selector << " <" << selector->hash() << ">" << " [@media:" << selector->media_block() << "]" << (selector->is_optional() ? " [is_optional]": " -") << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl; } else if (dynamic_cast<Simple_Selector*>(node)) { Simple_Selector* selector = dynamic_cast<Simple_Selector*>(node); std::cerr << ind << "Simple_Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl; } else if (dynamic_cast<Selector_Schema*>(node)) { Selector_Schema* selector = dynamic_cast<Selector_Schema*>(node); std::cerr << ind << "Selector_Schema " << selector; std::cerr << " (" << pstate_source_position(node) << ")" << (selector->at_root() && selector->at_root() ? " [@ROOT]" : "") << " [@media:" << selector->media_block() << "]" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl; debug_ast(selector->contents(), ind + " "); // for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Selector*>(node)) { Selector* selector = dynamic_cast<Selector*>(node); std::cerr << ind << "Selector " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl; } else if (dynamic_cast<Media_Query_Expression*>(node)) { Media_Query_Expression* block = dynamic_cast<Media_Query_Expression*>(node); std::cerr << ind << "Media_Query_Expression " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (block->is_interpolated() ? " [is_interpolated]": " -") << std::endl; debug_ast(block->feature(), ind + " feature) "); debug_ast(block->value(), ind + " value) "); } else if (dynamic_cast<Media_Query*>(node)) { Media_Query* block = dynamic_cast<Media_Query*>(node); std::cerr << ind << "Media_Query " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << (block->is_negated() ? " [is_negated]": " -") << (block->is_restricted() ? " [is_restricted]": " -") << std::endl; debug_ast(block->media_type(), ind + " "); for(auto i : block->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Media_Block*>(node)) { Media_Block* block = dynamic_cast<Media_Block*>(node); std::cerr << ind << "Media_Block " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; debug_ast(block->media_queries(), ind + " =@ "); if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Supports_Block*>(node)) { Supports_Block* block = dynamic_cast<Supports_Block*>(node); std::cerr << ind << "Supports_Block " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; debug_ast(block->condition(), ind + " =@ "); } else if (dynamic_cast<Supports_Operator*>(node)) { Supports_Operator* block = dynamic_cast<Supports_Operator*>(node); std::cerr << ind << "Supports_Operator " << block; std::cerr << " (" << pstate_source_position(node) << ")" << std::endl; debug_ast(block->left(), ind + " left) "); debug_ast(block->right(), ind + " right) "); } else if (dynamic_cast<Supports_Negation*>(node)) { Supports_Negation* block = dynamic_cast<Supports_Negation*>(node); std::cerr << ind << "Supports_Negation " << block; std::cerr << " (" << pstate_source_position(node) << ")" << std::endl; debug_ast(block->condition(), ind + " condition) "); } else if (dynamic_cast<Supports_Declaration*>(node)) { Supports_Declaration* block = dynamic_cast<Supports_Declaration*>(node); std::cerr << ind << "Supports_Declaration " << block; std::cerr << " (" << pstate_source_position(node) << ")" << std::endl; debug_ast(block->feature(), ind + " feature) "); debug_ast(block->value(), ind + " value) "); } else if (dynamic_cast<Block*>(node)) { Block* root_block = dynamic_cast<Block*>(node); std::cerr << ind << "Block " << root_block; std::cerr << " (" << pstate_source_position(node) << ")"; if (root_block->is_root()) std::cerr << " [root]"; std::cerr << " " << root_block->tabs() << std::endl; if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Warning*>(node)) { Warning* block = dynamic_cast<Warning*>(node); std::cerr << ind << "Warning " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; } else if (dynamic_cast<Error*>(node)) { Error* block = dynamic_cast<Error*>(node); std::cerr << ind << "Error " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; } else if (dynamic_cast<Debug*>(node)) { Debug* block = dynamic_cast<Debug*>(node); std::cerr << ind << "Debug " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; } else if (dynamic_cast<Comment*>(node)) { Comment* block = dynamic_cast<Comment*>(node); std::cerr << ind << "Comment " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << " <" << prettyprint(block->pstate().token.ws_before()) << ">" << std::endl; debug_ast(block->text(), ind + "// ", env); } else if (dynamic_cast<If*>(node)) { If* block = dynamic_cast<If*>(node); std::cerr << ind << "If " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; debug_ast(block->predicate(), ind + " = "); debug_ast(block->block(), ind + " <>"); debug_ast(block->alternative(), ind + " ><"); } else if (dynamic_cast<Return*>(node)) { Return* block = dynamic_cast<Return*>(node); std::cerr << ind << "Return " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; } else if (dynamic_cast<Extension*>(node)) { Extension* block = dynamic_cast<Extension*>(node); std::cerr << ind << "Extension " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; debug_ast(block->selector(), ind + "-> ", env); } else if (dynamic_cast<Content*>(node)) { Content* block = dynamic_cast<Content*>(node); std::cerr << ind << "Content " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; } else if (dynamic_cast<Import_Stub*>(node)) { Import_Stub* block = dynamic_cast<Import_Stub*>(node); std::cerr << ind << "Import_Stub " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; } else if (dynamic_cast<Import*>(node)) { Import* block = dynamic_cast<Import*>(node); std::cerr << ind << "Import " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; debug_ast(block->media_queries(), ind + " @ "); // std::vector<std::string> files_; for (auto imp : block->urls()) debug_ast(imp, "@ ", env); } else if (dynamic_cast<Assignment*>(node)) { Assignment* block = dynamic_cast<Assignment*>(node); std::cerr << ind << "Assignment " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <<" << block->variable() << ">> " << block->tabs() << std::endl; debug_ast(block->value(), ind + "=", env); } else if (dynamic_cast<Declaration*>(node)) { Declaration* block = dynamic_cast<Declaration*>(node); std::cerr << ind << "Declaration " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; debug_ast(block->property(), ind + " prop: ", env); debug_ast(block->value(), ind + " value: ", env); } else if (dynamic_cast<Keyframe_Rule*>(node)) { Keyframe_Rule* has_block = dynamic_cast<Keyframe_Rule*>(node); std::cerr << ind << "Keyframe_Rule " << has_block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << has_block->tabs() << std::endl; if (has_block->selector()) debug_ast(has_block->selector(), ind + "@"); if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<At_Rule*>(node)) { At_Rule* block = dynamic_cast<At_Rule*>(node); std::cerr << ind << "At_Rule " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << block->keyword() << "] " << block->tabs() << std::endl; debug_ast(block->selector(), ind + "~", env); debug_ast(block->value(), ind + "+", env); if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Each*>(node)) { Each* block = dynamic_cast<Each*>(node); std::cerr << ind << "Each " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<For*>(node)) { For* block = dynamic_cast<For*>(node); std::cerr << ind << "For " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<While*>(node)) { While* block = dynamic_cast<While*>(node); std::cerr << ind << "While " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << block->tabs() << std::endl; if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Definition*>(node)) { Definition* block = dynamic_cast<Definition*>(node); std::cerr << ind << "Definition " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [name: " << block->name() << "] "; std::cerr << " [type: " << (block->type() == Sass::Definition::Type::MIXIN ? "Mixin " : "Function ") << "] "; // this seems to lead to segfaults some times? // std::cerr << " [signature: " << block->signature() << "] "; std::cerr << " [native: " << block->native_function() << "] "; std::cerr << " " << block->tabs() << std::endl; debug_ast(block->parameters(), ind + " params: ", env); if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Mixin_Call*>(node)) { Mixin_Call* block = dynamic_cast<Mixin_Call*>(node); std::cerr << ind << "Mixin_Call " << block << " " << block->tabs(); std::cerr << " [" << block->name() << "]"; std::cerr << " [has_content: " << block->has_content() << "] " << std::endl; debug_ast(block->arguments(), ind + " args: "); if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (Ruleset* ruleset = dynamic_cast<Ruleset*>(node)) { std::cerr << ind << "Ruleset " << ruleset; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [indent: " << ruleset->tabs() << "]"; std::cerr << (ruleset->at_root() ? " [@ROOT]" : ""); std::cerr << (ruleset->is_root() ? " [root]" : ""); std::cerr << std::endl; debug_ast(ruleset->selector(), ind + ">"); debug_ast(ruleset->block(), ind + " "); } else if (dynamic_cast<Block*>(node)) { Block* block = dynamic_cast<Block*>(node); std::cerr << ind << "Block " << block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [indent: " << block->tabs() << "]" << std::endl; for(auto i : block->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Textual*>(node)) { Textual* expression = dynamic_cast<Textual*>(node); std::cerr << ind << "Textual "; if (expression->type() == Textual::NUMBER) std::cerr << " [NUMBER]"; else if (expression->type() == Textual::PERCENTAGE) std::cerr << " [PERCENTAGE]"; else if (expression->type() == Textual::DIMENSION) std::cerr << " [DIMENSION]"; else if (expression->type() == Textual::HEX) std::cerr << " [HEX]"; std::cerr << expression << " [" << expression->value() << "]"; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; if (expression->is_delayed()) std::cerr << " [delayed]"; std::cerr << std::endl; } else if (dynamic_cast<Variable*>(node)) { Variable* expression = dynamic_cast<Variable*>(node); std::cerr << ind << "Variable " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->name() << "]" << std::endl; std::string name(expression->name()); if (env && env->has(name)) debug_ast(static_cast<Expression*>((*env)[name]), ind + " -> ", env); } else if (dynamic_cast<Function_Call_Schema*>(node)) { Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node); std::cerr << ind << "Function_Call_Schema " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << "" << std::endl; debug_ast(expression->name(), ind + "name: ", env); debug_ast(expression->arguments(), ind + " args: ", env); } else if (dynamic_cast<Function_Call*>(node)) { Function_Call* expression = dynamic_cast<Function_Call*>(node); std::cerr << ind << "Function_Call " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->name() << "]"; if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; std::cerr << std::endl; debug_ast(expression->arguments(), ind + " args: ", env); } else if (dynamic_cast<Arguments*>(node)) { Arguments* expression = dynamic_cast<Arguments*>(node); std::cerr << ind << "Arguments " << expression; if (expression->is_delayed()) std::cerr << " [delayed]"; std::cerr << " (" << pstate_source_position(node) << ")"; if (expression->has_named_arguments()) std::cerr << " [has_named_arguments]"; if (expression->has_rest_argument()) std::cerr << " [has_rest_argument]"; if (expression->has_keyword_argument()) std::cerr << " [has_keyword_argument]"; std::cerr << std::endl; for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Argument*>(node)) { Argument* expression = dynamic_cast<Argument*>(node); std::cerr << ind << "Argument " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->value() << "]"; std::cerr << " [name: " << expression->name() << "] "; std::cerr << " [rest: " << expression->is_rest_argument() << "] "; std::cerr << " [keyword: " << expression->is_keyword_argument() << "] " << std::endl; debug_ast(expression->value(), ind + " value: ", env); } else if (dynamic_cast<Parameters*>(node)) { Parameters* expression = dynamic_cast<Parameters*>(node); std::cerr << ind << "Parameters " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [has_optional: " << expression->has_optional_parameters() << "] "; std::cerr << " [has_rest: " << expression->has_rest_parameter() << "] "; std::cerr << std::endl; for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Parameter*>(node)) { Parameter* expression = dynamic_cast<Parameter*>(node); std::cerr << ind << "Parameter " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [name: " << expression->name() << "] "; std::cerr << " [default: " << expression->default_value() << "] "; std::cerr << " [rest: " << expression->is_rest_parameter() << "] " << std::endl; } else if (dynamic_cast<Unary_Expression*>(node)) { Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node); std::cerr << ind << "Unary_Expression " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->type() << "]" << std::endl; debug_ast(expression->operand(), ind + " operand: ", env); } else if (dynamic_cast<Binary_Expression*>(node)) { Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node); std::cerr << ind << "Binary_Expression " << expression; if (expression->is_interpolant()) std::cerr << " [is interpolant] "; if (expression->is_left_interpolant()) std::cerr << " [left interpolant] "; if (expression->is_right_interpolant()) std::cerr << " [right interpolant] "; std::cerr << " [delayed: " << expression->is_delayed() << "] "; std::cerr << " [ws_before: " << expression->op().ws_before << "] "; std::cerr << " [ws_after: " << expression->op().ws_after << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << expression->type_name() << "]" << std::endl; debug_ast(expression->left(), ind + " left: ", env); debug_ast(expression->right(), ind + " right: ", env); } else if (dynamic_cast<Map*>(node)) { Map* expression = dynamic_cast<Map*>(node); std::cerr << ind << "Map " << expression; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [Hashed]" << std::endl; for (auto i : expression->elements()) { debug_ast(i.first, ind + " key: "); debug_ast(i.second, ind + " val: "); } } else if (dynamic_cast<List*>(node)) { List* expression = dynamic_cast<List*>(node); std::cerr << ind << "List " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " (" << expression->length() << ") " << (expression->separator() == SASS_COMMA ? "Comma " : expression->separator() == SASS_HASH ? "Map" : "Space ") << " [delayed: " << expression->is_delayed() << "] " << " [interpolant: " << expression->is_interpolant() << "] " << " [arglist: " << expression->is_arglist() << "] " << " [hash: " << expression->hash() << "] " << std::endl; for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Content*>(node)) { Content* expression = dynamic_cast<Content*>(node); std::cerr << ind << "Content " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [Statement]" << std::endl; } else if (dynamic_cast<Boolean*>(node)) { Boolean* expression = dynamic_cast<Boolean*>(node); std::cerr << ind << "Boolean " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [" << expression->value() << "]" << std::endl; } else if (dynamic_cast<Color*>(node)) { Color* expression = dynamic_cast<Color*>(node); std::cerr << ind << "Color " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [" << expression->r() << ":" << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << std::endl; } else if (dynamic_cast<Number*>(node)) { Number* expression = dynamic_cast<Number*>(node); std::cerr << ind << "Number " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [" << expression->value() << expression->unit() << "]" << " [hash: " << expression->hash() << "] " << std::endl; } else if (dynamic_cast<String_Quoted*>(node)) { String_Quoted* expression = dynamic_cast<String_Quoted*>(node); std::cerr << ind << "String_Quoted " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << prettyprint(expression->value()) << "]"; if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->sass_fix_1291()) std::cerr << " [sass_fix_1291]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; if (expression->quote_mark()) std::cerr << " [quote_mark: " << expression->quote_mark() << "]"; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; } else if (dynamic_cast<String_Constant*>(node)) { String_Constant* expression = dynamic_cast<String_Constant*>(node); std::cerr << ind << "String_Constant " << expression; if (expression->concrete_type()) { std::cerr << " " << expression->concrete_type(); } std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " [" << prettyprint(expression->value()) << "]"; if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->sass_fix_1291()) std::cerr << " [sass_fix_1291]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; } else if (dynamic_cast<String_Schema*>(node)) { String_Schema* expression = dynamic_cast<String_Schema*>(node); std::cerr << ind << "String_Schema " << expression; std::cerr << " " << expression->concrete_type(); if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->is_interpolant()) std::cerr << " [is interpolant]"; if (expression->has_interpolant()) std::cerr << " [has interpolant]"; if (expression->is_left_interpolant()) std::cerr << " [left interpolant] "; if (expression->is_right_interpolant()) std::cerr << " [right interpolant] "; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<String*>(node)) { String* expression = dynamic_cast<String*>(node); std::cerr << ind << "String " << expression; std::cerr << " " << expression->concrete_type(); std::cerr << " (" << pstate_source_position(node) << ")"; if (expression->sass_fix_1291()) std::cerr << " [sass_fix_1291]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; } else if (dynamic_cast<Expression*>(node)) { Expression* expression = dynamic_cast<Expression*>(node); std::cerr << ind << "Expression " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; switch (expression->concrete_type()) { case Expression::Concrete_Type::NONE: std::cerr << " [NONE]"; break; case Expression::Concrete_Type::BOOLEAN: std::cerr << " [BOOLEAN]"; break; case Expression::Concrete_Type::NUMBER: std::cerr << " [NUMBER]"; break; case Expression::Concrete_Type::COLOR: std::cerr << " [COLOR]"; break; case Expression::Concrete_Type::STRING: std::cerr << " [STRING]"; break; case Expression::Concrete_Type::LIST: std::cerr << " [LIST]"; break; case Expression::Concrete_Type::MAP: std::cerr << " [MAP]"; break; case Expression::Concrete_Type::SELECTOR: std::cerr << " [SELECTOR]"; break; case Expression::Concrete_Type::NULL_VAL: std::cerr << " [NULL_VAL]"; break; case Expression::Concrete_Type::C_WARNING: std::cerr << " [C_WARNING]"; break; case Expression::Concrete_Type::C_ERROR: std::cerr << " [C_ERROR]"; break; case Expression::Concrete_Type::NUM_TYPES: std::cerr << " [NUM_TYPES]"; break; } std::cerr << std::endl; } else if (dynamic_cast<Has_Block*>(node)) { Has_Block* has_block = dynamic_cast<Has_Block*>(node); std::cerr << ind << "Has_Block " << has_block; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << has_block->tabs() << std::endl; if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); } } else if (dynamic_cast<Statement*>(node)) { Statement* statement = dynamic_cast<Statement*>(node); std::cerr << ind << "Statement " << statement; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " " << statement->tabs() << std::endl; } if (ind == "") std::cerr << "####################################################################\n"; }
void bind(string callee, Parameters* ps, Arguments* as, Context& ctx, Env* env, Eval* eval) { map<string, Parameter*> param_map; // Set up a map to ensure named arguments refer to actual parameters. Also // eval each default value left-to-right, wrt env, populating env as we go. for (size_t i = 0, L = ps->length(); i < L; ++i) { Parameter* p = (*ps)[i]; param_map[p->name()] = p; // if (p->default_value()) { // env->current_frame()[p->name()] = p->default_value()->perform(eval->with(env)); // } } // plug in all args; if we have leftover params, deal with it later size_t ip = 0, LP = ps->length(); size_t ia = 0, LA = as->length(); while (ia < LA) { if (ip >= LP) { stringstream msg; msg << callee << " only takes " << LP << " arguments; " << "given " << LA; error(msg.str(), as->path(), as->position()); } Parameter* p = (*ps)[ip]; Argument* a = (*as)[ia]; // If the current parameter is the rest parameter, process and break the loop if (p->is_rest_parameter()) { if (a->is_rest_argument()) { // rest param and rest arg -- just add one to the other if (env->current_frame_has(p->name())) { *static_cast<List*>(env->current_frame()[p->name()]) += static_cast<List*>(a->value()); } else { env->current_frame()[p->name()] = a->value(); } } else { // copy all remaining arguments into the rest parameter, preserving names List* arglist = new (ctx.mem) List(p->path(), p->position(), 0, List::COMMA, true); env->current_frame()[p->name()] = arglist; while (ia < LA) { a = (*as)[ia]; (*arglist) << new (ctx.mem) Argument(a->path(), a->position(), a->value(), a->name(), false); ++ia; } } ++ip; break; } // If the current argument is the rest argument, extract a value for processing else if (a->is_rest_argument()) { // normal param and rest arg List* arglist = static_cast<List*>(a->value()); // empty rest arg - treat all args as default values if (!arglist->length()) { break; } // otherwise move one of the rest args into the param, converting to argument if necessary if (arglist->is_arglist()) { a = static_cast<Argument*>((*arglist)[0]); } else { Expression* a_to_convert = (*arglist)[0]; a = new (ctx.mem) Argument(a_to_convert->path(), a_to_convert->position(), a_to_convert, "", false); } arglist->elements().erase(arglist->elements().begin()); if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) { ++ia; } } else if (a->is_keyword_argument()) { Map* argmap = static_cast<Map*>(a->value()); for (auto key : argmap->keys()) { string name = "$" + unquote(static_cast<String_Constant*>(key)->value()); if (!param_map.count(name)) { stringstream msg; msg << callee << " has no parameter named " << name; error(msg.str(), a->path(), a->position()); } env->current_frame()[name] = argmap->at(key); } ++ia; continue; } else { ++ia; } if (a->name().empty()) { if (env->current_frame_has(p->name())) { stringstream msg; msg << "parameter " << p->name() << " provided more than once in call to " << callee; error(msg.str(), a->path(), a->position()); } // ordinal arg -- bind it to the next param env->current_frame()[p->name()] = a->value(); ++ip; } else { // named arg -- bind it to the appropriately named param if (!param_map.count(a->name())) { stringstream msg; msg << callee << " has no parameter named " << a->name(); error(msg.str(), a->path(), a->position()); } if (param_map[a->name()]->is_rest_parameter()) { stringstream msg; msg << "argument " << a->name() << " of " << callee << "cannot be used as named argument"; error(msg.str(), a->path(), a->position()); } if (env->current_frame_has(a->name())) { stringstream msg; msg << "parameter " << p->name() << "provided more than once in call to " << callee; error(msg.str(), a->path(), a->position()); } env->current_frame()[a->name()] = a->value(); } } // If we make it here, we're out of args but may have leftover params. // That's only okay if they have default values, or were already bound by // named arguments, or if it's a single rest-param. for (size_t i = ip; i < LP; ++i) { To_String to_string; Parameter* leftover = (*ps)[i]; // cerr << "env for default params:" << endl; // env->print(); // cerr << "********" << endl; if (!env->current_frame_has(leftover->name())) { if (leftover->is_rest_parameter()) { env->current_frame()[leftover->name()] = new (ctx.mem) List(leftover->path(), leftover->position(), 0, List::COMMA, true); } else if (leftover->default_value()) { // make sure to eval the default value in the env that we've been populating Env* old_env = eval->env; Backtrace* old_bt = eval->backtrace; Expression* dv = leftover->default_value()->perform(eval->with(env, eval->backtrace)); eval->env = old_env; eval->backtrace = old_bt; // dv->perform(&to_string); env->current_frame()[leftover->name()] = dv; } else { // param is unbound and has no default value -- error stringstream msg; msg << "required parameter " << leftover->name() << " is missing in call to " << callee; error(msg.str(), as->path(), as->position()); } } } return; }
void bind(string callee, Parameters* ps, Arguments* as, Context& ctx, Env* env, Eval* eval) { map<string, Parameter*> param_map; // Set up a map to ensure named arguments refer to actual parameters. Also // eval each default value left-to-right, wrt env, populating env as we go. for (size_t i = 0, L = ps->length(); i < L; ++i) { Parameter* p = (*ps)[i]; param_map[p->name()] = p; // if (p->default_value()) { // env->local_frame()[p->name()] = p->default_value()->perform(eval->with(env)); // } } // plug in all args; if we have leftover params, deal with it later size_t ip = 0, LP = ps->length(); size_t ia = 0, LA = as->length(); while (ia < LA) { Argument* a = (*as)[ia]; if (ip >= LP) { // skip empty rest arguments if (a->is_rest_argument()) { if (List* l = dynamic_cast<List*>(a->value())) { if (l->length() == 0) { ++ ia; continue; } } } stringstream msg; msg << callee << " only takes " << LP << " arguments; " << "given " << LA; error(msg.str(), as->pstate()); } Parameter* p = (*ps)[ip]; // If the current parameter is the rest parameter, process and break the loop if (p->is_rest_parameter()) { // The next argument by coincidence provides a rest argument if (a->is_rest_argument()) { // We should always get a list for rest arguments if (List* rest = dynamic_cast<List*>(a->value())) { // arg contains a list List* args = rest; // make sure it's an arglist if (rest->is_arglist()) { // can pass it through as it was env->local_frame()[p->name()] = args; } // create a new list and wrap each item as an argument // otherwise we will not be able to fetch it again else { // create a new list object for wrapped items List* arglist = new (ctx.mem) List(p->pstate(), 0, rest->separator(), true); // wrap each item from list as an argument for (Expression* item : rest->elements()) { (*arglist) << new (ctx.mem) Argument(item->pstate(), item, "", false, false); } // assign new arglist to environment env->local_frame()[p->name()] = arglist; } } // invalid state else { throw runtime_error("invalid state"); } } else if (a->is_keyword_argument()) { // expand keyword arguments into their parameters List* arglist = new (ctx.mem) List(p->pstate(), 0, List::COMMA, true); env->local_frame()[p->name()] = arglist; Map* argmap = static_cast<Map*>(a->value()); for (auto key : argmap->keys()) { string name = unquote(static_cast<String_Constant*>(key)->value()); (*arglist) << new (ctx.mem) Argument(key->pstate(), argmap->at(key), name, false, false); } } else { // create a new list object for wrapped items List* arglist = new (ctx.mem) List(p->pstate(), 0, List::COMMA, true); // consume the next args while (ia < LA) { // get and post inc a = (*as)[ia++]; // wrap current argument into new object (*arglist) << new (ctx.mem) Argument(a->pstate(), a->value(), a->name(), false, false); // check if we have rest argument if (a->is_rest_argument()) { // preserve the list separator from rest args if (List* rest = dynamic_cast<List*>(a->value())) { arglist->separator(rest->separator()); } // no more arguments break; } } // assign new arglist to environment env->local_frame()[p->name()] = arglist; } // consumed parameter ++ip; // no more paramaters break; } // If the current argument is the rest argument, extract a value for processing else if (a->is_rest_argument()) { // normal param and rest arg List* arglist = static_cast<List*>(a->value()); // empty rest arg - treat all args as default values if (!arglist->length()) { break; } // otherwise move one of the rest args into the param, converting to argument if necessary if (arglist->is_arglist()) { a = static_cast<Argument*>((*arglist)[0]); } else { Expression* a_to_convert = (*arglist)[0]; a = new (ctx.mem) Argument(a_to_convert->pstate(), a_to_convert, "", false, false); } arglist->elements().erase(arglist->elements().begin()); if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) { ++ia; } } else if (a->is_keyword_argument()) { Map* argmap = static_cast<Map*>(a->value()); for (auto key : argmap->keys()) { string name = "$" + unquote(static_cast<String_Constant*>(key)->value()); if (!param_map.count(name)) { stringstream msg; msg << callee << " has no parameter named " << name; error(msg.str(), a->pstate()); } env->local_frame()[name] = argmap->at(key); } ++ia; continue; } else { ++ia; } if (a->name().empty()) { if (env->has_local(p->name())) { stringstream msg; msg << "parameter " << p->name() << " provided more than once in call to " << callee; error(msg.str(), a->pstate()); } // ordinal arg -- bind it to the next param env->local_frame()[p->name()] = a->value(); ++ip; } else { // named arg -- bind it to the appropriately named param if (!param_map.count(a->name())) { stringstream msg; msg << callee << " has no parameter named " << a->name(); error(msg.str(), a->pstate()); } if (param_map[a->name()]->is_rest_parameter()) { stringstream msg; msg << "argument " << a->name() << " of " << callee << "cannot be used as named argument"; error(msg.str(), a->pstate()); } if (env->has_local(a->name())) { stringstream msg; msg << "parameter " << p->name() << "provided more than once in call to " << callee; error(msg.str(), a->pstate()); } env->local_frame()[a->name()] = a->value(); } } // EO while ia // If we make it here, we're out of args but may have leftover params. // That's only okay if they have default values, or were already bound by // named arguments, or if it's a single rest-param. for (size_t i = ip; i < LP; ++i) { To_String to_string(&ctx); Parameter* leftover = (*ps)[i]; // cerr << "env for default params:" << endl; // env->print(); // cerr << "********" << endl; if (!env->has_local(leftover->name())) { if (leftover->is_rest_parameter()) { env->local_frame()[leftover->name()] = new (ctx.mem) List(leftover->pstate(), 0, List::COMMA, true); } else if (leftover->default_value()) { // make sure to eval the default value in the env that we've been populating Env* old_env = eval->env; Backtrace* old_bt = eval->backtrace; Contextualize* old_context = eval->contextualize; Expression* dv = leftover->default_value()->perform(eval->with(env, eval->backtrace)); eval->env = old_env; eval->backtrace = old_bt; eval->contextualize = old_context; // dv->perform(&to_string); env->local_frame()[leftover->name()] = dv; } else { // param is unbound and has no default value -- error stringstream msg; msg << "required parameter " << leftover->name() << " is missing in call to " << callee; error(msg.str(), as->pstate()); } } } return; }
void bind(string callee, Parameters* ps, Arguments* as, Context& ctx, Env* env, Eval* eval) { map<string, Parameter*> param_map; // Set up a map to ensure named arguments refer to actual parameters. Also // eval each default value left-to-right, wrt env, populating env as we go. for (size_t i = 0, L = ps->length(); i < L; ++i) { Parameter* p = (*ps)[i]; param_map[p->name()] = p; // if (p->default_value()) { // env->current_frame()[p->name()] = p->default_value()->perform(eval->with(env)); // } } // plug in all args; if we have leftover params, deal with it later size_t ip = 0, LP = ps->length(); size_t ia = 0, LA = as->length(); while (ia < LA) { if (ip >= LP) { stringstream msg; msg << callee << " only takes " << LP << " arguments; " << "given " << LA; error(msg.str(), as->path(), as->line()); } Parameter* p = (*ps)[ip]; Argument* a = (*as)[ia]; if (a->is_rest_argument() && p->is_rest_parameter()) { // rest param and rest arg -- just add one to the other if (env->current_frame_has(p->name())) { *static_cast<List*>(env->current_frame()[p->name()]) += static_cast<List*>(a->value()); } else { env->current_frame()[p->name()] = a->value(); } ++ia; ++ip; } else if (p->is_rest_parameter()) { List* arglist = 0; if (!env->current_frame_has(p->name())) { arglist = new (ctx.mem) List(p->path(), p->line(), 0, List::COMMA, true); env->current_frame()[p->name()] = arglist; } else { arglist = static_cast<List*>(env->current_frame()[p->name()]); } *arglist << a->value(); // TODO: named args going into rest-param? ++ia; } else if (a->is_rest_argument()) { // normal param and rest arg if (env->current_frame_has(p->name())) { stringstream msg; msg << "parameter " << p->name() << " provided more than once in call to " << callee; error(msg.str(), a->path(), a->line()); } List* arglist = static_cast<List*>(a->value()); // if it's the last param, move the whole arglist into it if (ip == LP-1) { env->current_frame()[p->name()] = arglist; ++ia; } // otherwise move one of the rest args into the param and loop else { env->current_frame()[p->name()] = (*arglist)[0]; arglist->elements().erase(arglist->elements().begin()); } ++ip; } else if (a->name().empty()) { // ordinal arg -- bind it to the next param env->current_frame()[p->name()] = a->value(); ++ip; ++ia; } else { // named arg -- bind it to the appropriately named param if (!param_map.count(a->name())) { stringstream msg; msg << callee << " has no parameter named " << a->name(); error(msg.str(), a->path(), a->line()); } if (param_map[a->name()]->is_rest_parameter()) { stringstream msg; msg << "argument " << a->name() << " of " << callee << "cannot be used as named argument"; error(msg.str(), a->path(), a->line()); } if (env->current_frame_has(a->name())) { stringstream msg; msg << "parameter " << p->name() << "provided more than once in call to " << callee; error(msg.str(), a->path(), a->line()); } env->current_frame()[a->name()] = a->value(); ++ia; } } // If we make it here, we're out of args but may have leftover params. // That's only okay if they have default values, or were already bound by // named arguments, or if it's a single rest-param. for (size_t i = ip; i < LP; ++i) { To_String to_string; Parameter* leftover = (*ps)[i]; // cerr << "env for default params:" << endl; // env->print(); // cerr << "********" << endl; if (!env->current_frame_has(leftover->name())) { if (leftover->is_rest_parameter()) { env->current_frame()[leftover->name()] = new (ctx.mem) List(leftover->path(), leftover->line(), 0, List::COMMA, true); } else if (leftover->default_value()) { // make sure to eval the default value in the env that we've been populating Env* old_env = eval->env; Backtrace* old_bt = eval->backtrace; Expression* dv = leftover->default_value()->perform(eval->with(env, eval->backtrace)); eval->env = old_env; eval->backtrace = old_bt; // dv->perform(&to_string); env->current_frame()[leftover->name()] = dv; } else { // param is unbound and has no default value -- error stringstream msg; msg << "required parameter " << leftover->name() << " is missing in call to " << callee; error(msg.str(), as->path(), as->line()); } } } return; }