Esempio n. 1
0
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);
    }
}