GrammarFunc* Grammar::MakeFunc(const string& FuncName, const vector<GrammarNode*>& Args) { // extract the types const uint32 NumArgs = Args.size(); vector<const ESFixedTypeBase*> ArgTypes(NumArgs); for (uint32 i = 0; i < NumArgs; ++i) { ArgTypes[i] = Args[i]->GetType(); } auto Op = Solver->LookupOperator(FuncName, ArgTypes); if (Op == nullptr) { throw TypeException((string)"Could not resolve operator \"" + FuncName + "\" to anything meaningful.\n" + "This could be due to " + "mismatched parameters"); } return Get<GrammarFunc>(this, Op, Args); }
Expression ESolver::CreateExpression(const OperatorBase* OpInfo, const vector<Expression>& Children) { Expression NewExp; // Type checks if (Children.size() > 0) { auto FuncOp = OpInfo->As<FuncOperatorBase>(); const uint32 NumChildren = Children.size(); vector<const ESFixedTypeBase*> ArgTypes(NumChildren); for (uint32 i = 0; i < NumChildren; ++i) { ArgTypes[i] = Children[i]->GetType(); } // Quick type check using name mangling auto const& ExpectedName = FuncOp->GetMangledName(); auto const&& ActualName = FuncOperatorBase::MangleName(OpInfo->GetName(), ArgTypes); if (ExpectedName != ActualName) { throw TypeException((string)"Error in application of function \"" + OpInfo->GetName() + "\".\n" + "This could be due to mismatched numbers or types of parameters"); } // We're good. Create the expression if (OpInfo->As<InterpretedFuncOperator>() != nullptr) { NewExp = new UserInterpretedFuncExpression(OpInfo->As<InterpretedFuncOperator>(), Children); } else { NewExp = new UserSynthFuncExpression(OpInfo->As<SynthFuncOperator>(), Children); } } else { // This could be a constant, a UQVariable, an aux variable, // a formal param or a let bound variable if (OpInfo->As<VarOperatorBase>() != nullptr) { if (OpInfo->As<UQVarOperator>() != nullptr) { NewExp = new UserUQVarExpression(OpInfo->As<UQVarOperator>()); } else if (OpInfo->As<FormalParamOperator>() != nullptr) { NewExp = new UserFormalParamExpression(OpInfo->As<FormalParamOperator>()); } else if (OpInfo->As<AuxVarOperator>() != nullptr) { NewExp = new UserAuxVarExpression(OpInfo->As<AuxVarOperator>()); } else if (OpInfo->As<LetBoundVarOperator>() != nullptr) { NewExp = new UserLetBoundVarExpression(OpInfo->As<LetBoundVarOperator>()); } else { throw InternalError((string)"BUG: Unhandled operator type at " + __FILE__ + ":" + to_string(__LINE__)); } } else { // This can only be a const operator now if (OpInfo->As<ConstOperator>() != nullptr) { NewExp = new UserConstExpression(OpInfo->As<ConstOperator>()); } else if (OpInfo->As<MacroOperator>() != nullptr) { // OR it can be a constant macro expression NewExp = new UserInterpretedFuncExpression(OpInfo->As<MacroOperator>(), Children); } else { throw TypeException((string)"Error: Could not find a meaningful way to construct " + "an expression with operator having name \"" + OpInfo->GetName() + "\".\nPerhaps you provided arguments where none were expected, " + "or this could be a bug"); } } } ExpMgr->GC(); return ExpMgr->GetExp(NewExp); }
// Here is the test Eval function specialization. Here the CallExpr to the // function is created. CallExpr* EvaluateTSynthesizer::BuildEvalCallExpr(const QualType InstTy, Expr* SubTree, llvm::SmallVector<Expr*, 2>& CallArgs) { // Set up new context for the new FunctionDecl DeclContext* PrevContext = m_Sema->CurContext; m_Sema->CurContext = m_EvalDecl->getDeclContext(); // Create template arguments Sema::InstantiatingTemplate Inst(*m_Sema, m_NoSLoc, m_EvalDecl); // Before instantiation we need the canonical type TemplateArgument Arg(InstTy.getCanonicalType()); TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, &Arg, 1U); // Substitute the declaration of the templated function, with the // specified template argument Decl* D = m_Sema->SubstDecl(m_EvalDecl, m_EvalDecl->getDeclContext(), MultiLevelTemplateArgumentList(TemplateArgs)); FunctionDecl* Fn = dyn_cast<FunctionDecl>(D); // We expect incoming declarations (instantiations) and we // need to open the transaction to collect them. Transaction::State oldState = getTransaction()->getState(); getTransaction()->setState(Transaction::kCollecting); // Creates new body of the substituted declaration m_Sema->InstantiateFunctionDefinition(Fn->getLocation(), Fn, true, true); m_Sema->CurContext = PrevContext; const FunctionProtoType* FPT = Fn->getType()->getAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); llvm::ArrayRef<QualType> ArgTypes(FPT->arg_type_begin(), FPT->getNumArgs()); QualType FnTy = m_Context->getFunctionType(Fn->getResultType(), ArgTypes, EPI); DeclRefExpr* DRE = m_Sema->BuildDeclRefExpr(Fn, FnTy, VK_RValue, m_NoSLoc ).takeAs<DeclRefExpr>(); getTransaction()->setState(oldState); // TODO: Figure out a way to avoid passing in wrong source locations // of the symbol being replaced. This is important when we calculate the // size of the memory buffers and may lead to creation of wrong wrappers. Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); CallExpr* EvalCall = m_Sema->ActOnCallExpr(S, DRE, SubTree->getLocStart(), CallArgs, SubTree->getLocEnd() ).takeAs<CallExpr>(); assert (EvalCall && "Cannot create call to Eval"); return EvalCall; }