Variant EvalCreateFunction::InvokeImpl(VariableEnvironment &env, CArrRef params) { int size = params.size(); if (size != 2) return invalid_function_call("create_function"); Variant var = params.rvalAt(0); Variant body = params.rvalAt(1); vector<StaticStatementPtr> statics; Block::VariableIndices variableIndices; ostringstream fnStream; string id(RequestEvalState::unique()); fnStream << "<?php function lambda_" << id << "(" << var.toString().data() << ") {" << body.toString().data() << "}\n"; StatementPtr bodyAst = Parser::ParseString(fnStream.str().c_str(), statics, variableIndices); if (!bodyAst) return false; ostringstream nameStream; nameStream << "$lambda_" << id; StatementListStatement *sl = bodyAst->cast<StatementListStatement>(); FunctionStatement *f = sl->stmts()[0]->cast<FunctionStatement>(); ASSERT(f); f->changeName(nameStream.str()); SmartPtr<CodeContainer> cc(new StringCodeContainer(bodyAst)); RequestEvalState::addCodeContainer(cc); f->eval(env); return f->name(); }
void SemanticAnalysis::analyzeShadowedFunctions(FunctionSymbol *sym) { // We do not yet support overloading, so two functions with the same name // and a body are illegal. We consider natives to be implemented. FunctionStatement *impl = nullptr; // We support non-native implementations of a forwarded function. FunctionStatement *forward = nullptr; for (size_t i = 0; i < sym->shadows()->length(); i++) { FunctionStatement *stmt = sym->shadows()->at(i); switch (stmt->token()) { case TOK_FORWARD: if (forward) { cc_.report(stmt->loc(), rmsg::function_redeclared) << stmt->name() << (cc_.note(forward->loc(), rmsg::previous_location)); continue; } forward = stmt; break; case TOK_NATIVE: case TOK_FUNCTION: if (impl) { cc_.report(stmt->loc(), rmsg::function_redeclared) << stmt->name() << (cc_.note(impl->loc(), rmsg::previous_location)); continue; } impl = stmt; break; default: assert(false); break; } } // If we have both an impl and a forward, make sure they match. if (impl && forward) checkForwardedFunction(forward, impl); }
void SemanticAnalysis::visitNameProxy(NameProxy *proxy) { Symbol *binding = proxy->sym(); switch (binding->kind()) { case Symbol::kType: cc_.report(proxy->loc(), rmsg::cannot_use_type_as_value) << binding->asType()->type(); break; case Symbol::kConstant: { ConstantSymbol *sym = binding->toConstant(); proxy->setOutput(sym->type(), VK::rvalue); break; } case Symbol::kFunction: { FunctionSymbol *sym = binding->toFunction(); FunctionStatement *decl = sym->impl(); if (!decl) { cc_.report(proxy->loc(), rmsg::function_has_no_impl) << sym->name(); break; } if (!decl->type()) decl->setType(FunctionType::New(decl->signature())); // Function symbols are clvalues, since they are named. // :TODO: proxy->setOutput(decl->type(), VK::lvalue); break; } default: assert(false); } }