/*************************************************************** * Function: RangeExpr::getSubExprs() * Purpose : Access sub-expressions * Initial : Maxime Chevalier-Boisvert on January 8, 2009 **************************************************************** Revisions and bug fixes: */ Expression::ExprVector RangeExpr::getSubExprs() const { // Create a list to store the sub-expression pointers ExprVector list; // Add the sub-expressions to the list list.push_back(m_pStartExpr); list.push_back(m_pStepExpr); list.push_back(m_pEndExpr); // Return the list return list; }
// Return true if a comma (or closing brace) is necessary after the // __if_exists/if_not_exists statement. bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, bool &InitExprsOk) { bool trailingComma = false; IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return false; BalancedDelimiterTracker Braces(*this, tok::l_brace); if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected) << tok::l_brace; return false; } switch (Result.Behavior) { case IEB_Parse: // Parse the declarations below. break; case IEB_Dependent: Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists) << Result.IsIfExists; // Fall through to skip. case IEB_Skip: Braces.skipToEnd(); return false; } while (!isEofOrEom()) { trailingComma = false; // If we know that this cannot be a designation, just parse the nested // initializer directly. ExprResult SubElt; if (MayBeDesignationStart()) SubElt = ParseInitializerWithPotentialDesignator(); else SubElt = ParseInitializer(); if (Tok.is(tok::ellipsis)) SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); // If we couldn't parse the subelement, bail out. if (!SubElt.isInvalid()) InitExprs.push_back(SubElt.release()); else InitExprsOk = false; if (Tok.is(tok::comma)) { ConsumeToken(); trailingComma = true; } if (Tok.is(tok::r_brace)) break; } Braces.consumeClose(); return !trailingComma; }
// Flatten out all expressions with a given head. void Expression::Flatten(const string head) { ExprVector newLeaves; newLeaves.reserve(leaves.size()); for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf) if((*leaf)->FunctionName() == head) { for(ExprVector::const_iterator subLeaf = (*leaf)->Leaves().begin(); subLeaf != (*leaf)->Leaves().end(); ++subLeaf) newLeaves.push_back(*subLeaf); (*leaf)->Leaves().clear(); delete *leaf; } else newLeaves.push_back(*leaf); leaves = newLeaves; }
void OpReplaceRepeated::Apply(Expression *expression, Calculator *calculator, int32 recursions) { if(expression->LeafCount() != 2) throw ArgumentException("ReplaceRepeated expects 2 arguments."); if(expression->LeafCount() != 2) throw ArgumentException("ReplaceRepeated expects 2 arguments."); string leafFunction = expression->Leaf(1)->FunctionName(); if(leafFunction != "Rule" && leafFunction != "RuleDelayed" && leafFunction != "List") throw ArgumentException("ReplaceRepeated expects its second argument to be a rule or a list of rules."); ExprVector rules; if(leafFunction == "List") { for(ExprVector::const_iterator item = expression->Leaf(1)->Leaves().begin(); item != expression->Leaf(1)->Leaves().end(); ++ item) if((*item)->FunctionName() != "Rule" && (*item)->FunctionName() != "RuleDelayed") throw ArgumentException("ReplaceRepeated expects its second argument to be a rule or a list of rules."); rules = expression->Leaf(1)->Leaves(); } else rules.push_back(expression->Leaf(1)); int32 iterations(0); Expression *result = expression->Leaf(0); while(true) { bool changed(false); if(!result->ReplaceAll(rules, calculator, &changed)) break; if(!changed) break; ++iterations; if(iterations >= Max_ReplaceRepeated_Iterations) throw LimitationException("Maximum number of iterations reached."); } expression->AssignLeaf(0); expression->Evaluate(calculator, recursions); }
void TransformVector::MakeElementExprs(DeclVector &DeclVec, ExprVector &ExprVec, ExtVectorElementExpr *E) { llvm::SmallVector<unsigned, 4> Indices; E->getEncodedElementAccess(Indices); Expr *BE = E->getBase(); // If E is an arrow expression, the base pointer expression needs to be // converted into a vector value expression. if (E->isArrow()) { QualType BaseTy = BE->getType(); const PointerType *PTy = BaseTy->getAs<PointerType>(); assert(PTy && "Not a pointer type"); BE = new (ASTCtx) UnaryOperator(BE, UO_Deref, PTy->getPointeeType(), VK_RValue, OK_Ordinary, SourceLocation()); BE = new (ASTCtx) ParenExpr(SourceLocation(), SourceLocation(), BE); } if (ExtVectorElementExpr *BP = dyn_cast<ExtVectorElementExpr>(BE)) { ExprVector BaseExprVec; MakeElementExprs(DeclVec, BaseExprVec, BP); for (unsigned i = 0, e = Indices.size(); i < e; i++) { ExprVec.push_back(BaseExprVec[Indices[i]]); } } else if (CompoundLiteralExpr *BP = dyn_cast<CompoundLiteralExpr>(BE)) { for (unsigned i = 0, e = Indices.size(); i < e; i++) { Expr *ElemE = GetSingleValueOfVecLiteral(DeclVec, BP, Indices[i]); ExprVec.push_back(ElemE); } } else { Expr *NewBE = ConvertVecLiteralInExpr(DeclVec, BE); const ExtVectorType *VecTy = NewBE->getType()->getAs<ExtVectorType>(); assert(VecTy && "The type of BaseExpr is not a vector type."); QualType ElemTy = VecTy->getElementType(); SourceLocation loc; for (unsigned i = 0, e = Indices.size(); i < e; i++) { unsigned Kind = CLExpressions::ZERO + Indices[i]; ArraySubscriptExpr *ElemE = new (ASTCtx) ArraySubscriptExpr( NewBE, CLExprs.getExpr((CLExpressions::ExprKind)(Kind)), ElemTy, VK_RValue, OK_Ordinary, loc); ExprVec.push_back(ElemE); } } }
/** * @brief Converts the given LLVM call instruction @a inst into an expression in BIR. */ ShPtr<CallExpr> LLVMInstructionConverter::convertCallInstToCallExpr(llvm::CallInst &inst) { ExprVector args; for (auto &arg: inst.arg_operands()) { args.push_back(getConverter()->convertValueToExpression(arg)); } auto calledExpr = getConverter()->convertValueToExpression(inst.getCalledValue()); return CallExpr::create(calledExpr, args); }
/*************************************************************** * Function: ParamExpr::getSubExprs() * Purpose : Access sub-expressions * Initial : Maxime Chevalier-Boisvert on January 8, 2009 **************************************************************** Revisions and bug fixes: */ Expression::ExprVector ParamExpr::getSubExprs() const { // Create a list to store the sub-expression pointers ExprVector list; // Add the symbol to the list list.push_back(m_pSymbolExpr); // For each argument for (size_t i = 0; i < m_arguments.size(); ++i) { // Add the sub-expression to the list list.push_back(m_arguments[i]); } // Return the list return list; }
/*************************************************************** * Function: ParamExpr::copy() * Purpose : Copy this IIR node recursively * Initial : Maxime Chevalier-Boisvert on November 8, 2008 **************************************************************** Revisions and bug fixes: */ ParamExpr* ParamExpr::copy() const { // Create an argument vector to store the argument copies ExprVector arguments; // Copy each argument for (ExprVector::const_iterator itr = m_arguments.begin(); itr != m_arguments.end(); ++itr) arguments.push_back((Expression*)(*itr)->copy()); // Create and return a copy of this node return new ParamExpr( m_pSymbolExpr->copy(), arguments ); }
/*************************************************************** * Function: AssignStmt::copy() * Purpose : Copy this IIR node recursively * Initial : Maxime Chevalier-Boisvert on November 6, 2008 **************************************************************** Revisions and bug fixes: */ AssignStmt* AssignStmt::copy() const { // Create a vector for the left expression copies ExprVector leftExprs; // Copy each left expression for (ExprVector::const_iterator itr = m_leftExprs.begin(); itr != m_leftExprs.end(); ++itr) leftExprs.push_back((*itr)->copy()); // Create and return a copy of this node return new AssignStmt( leftExprs, m_pRightExpr->copy(), m_suppressOut ); }
void RecursiveCFGBuilder::visit(ShPtr<IfStmt> stmt) { ShPtr<CFG::Node> beforeIfNode(currNode); // Create a node for the if statement. ShPtr<CFG::Node> ifNode(new CFG::Node()); firstStmtNodeMapping[stmt] = ifNode; cfg->stmtNodeMapping[stmt] = ifNode; ifNode->stmts.push_back(stmt); cfg->addNode(ifNode); cfg->addEdge(beforeIfNode, ifNode); // Create a node for the bodies of the if statement. ExprVector conds; for (auto i = stmt->clause_begin(), e = stmt->clause_end(); i != e; ++i) { ShPtr<CFG::Node> clauseBody(addNode(i->second)); cfg->addEdge(ifNode, clauseBody, generateIfCondEdgeLabel(conds, i->first)); conds.push_back(i->first); } // Create a node for the else clause/statement's successor. If there is an // else clause, then we don't have to generate a node for the statement's // successor here. Indeed, if the else clause always ends with a return // statement, then the statement's successor is never entered. If the else // clause doesn't always ends with a return, the statement's successor will // be traversed when adding a node for the else clause. if (stmt->hasElseClause()) { ShPtr<CFG::Node> clauseBody(addNode(stmt->getElseClause())); cfg->addEdge(ifNode, clauseBody, generateIfCondEdgeLabel(conds)); return; } ShPtr<Expression> edgeCond(generateIfCondEdgeLabel(conds)); if (ShPtr<Statement> stmtSucc = stmt->getSuccessor()) { ShPtr<CFG::Node> afterIfNode(addNode(stmtSucc)); cfg->addEdge(ifNode, afterIfNode, edgeCond); return; } currNode = ifNode; addForwardOrBackwardEdge(stmt, edgeCond); }
void OpReplaceAll::Apply(Expression *expression, Calculator *calculator, int32 recursions) { if(expression->LeafCount() != 2) throw ArgumentException("ReplaceAll expects 2 arguments."); string leafFunction = expression->Leaf(1)->FunctionName(); if(leafFunction != "Rule" && leafFunction != "RuleDelayed" && leafFunction != "List") throw ArgumentException("ReplaceAll expects its second argument to be a rule or a list of rules."); if(leafFunction == "List") { for(ExprVector::const_iterator item = expression->Leaf(1)->Leaves().begin(); item != expression->Leaf(1)->Leaves().end(); ++ item) if((*item)->FunctionName() != "Rule" && (*item)->FunctionName() != "RuleDelayed") throw ArgumentException("ReplaceAll expects its second argument to be a rule or a list of rules."); expression->Leaf(0)->ReplaceAll(expression->Leaf(1)->Leaves(), calculator); } else { ExprVector rules; rules.push_back(expression->Leaf(1)); expression->Leaf(0)->ReplaceAll(rules, calculator); } expression->AssignLeaf(0); expression->Evaluate(calculator, recursions); }
Stmt *TransformVector::VisitInitListExpr(InitListExpr *Node) { // For conventional vector literals such as '{1, 2, 3, 4}' QualType ETy = Node->getType(); if (ETy->isExtVectorType()) { CompoundLiteralExpr *CLE = new (ASTCtx) CompoundLiteralExpr( SourceLocation(), ASTCtx.getTrivialTypeSourceInfo(ETy), ETy, Node->getValueKind(), Node, false); return VisitCompoundLiteralExpr(CLE); } if (NeedFlattening) { ExprVector InitExprs; ExprVector *PrvInitExprs = CurInitExprs; CurInitExprs = &InitExprs; for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { assert(Node->getInit(i) && "NULL InitExpr?"); Expr *InitExpr = TransformExpr(Node->getInit(i)); InitExprs.push_back(InitExpr); } for (unsigned i =0, e = InitExprs.size(); i < e; ++i) { Node->updateInit(ASTCtx, i, InitExprs[i]); } CurInitExprs = PrvInitExprs; } else { for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { if (Node->getInit(i)) { Node->setInit(i, TransformExpr(Node->getInit(i))); } } } return Node; }
/// ParseBraceInitializer - Called when parsing an initializer that has a /// leading open brace. /// /// initializer: [C99 6.7.8] /// '{' initializer-list '}' /// '{' initializer-list ',' '}' /// [GNU] '{' '}' /// /// initializer-list: /// designation[opt] initializer ...[opt] /// initializer-list ',' designation[opt] initializer ...[opt] /// ExprResult Parser::ParseBraceInitializer() { InMessageExpressionRAIIObject InMessage(*this, false); BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); SourceLocation LBraceLoc = T.getOpenLocation(); /// InitExprs - This is the actual list of expressions contained in the /// initializer. ExprVector InitExprs; if (Tok.is(tok::r_brace)) { // Empty initializers are a C++ feature and a GNU extension to C. if (!getLangOpts().CPlusPlus) Diag(LBraceLoc, diag::ext_gnu_empty_initializer); // Match the '}'. return Actions.ActOnInitList(LBraceLoc, None, ConsumeBrace()); } bool InitExprsOk = true; while (1) { // Handle Microsoft __if_exists/if_not_exists if necessary. if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { if (ParseMicrosoftIfExistsBraceInitializer(InitExprs, InitExprsOk)) { if (Tok.isNot(tok::comma)) break; ConsumeToken(); } if (Tok.is(tok::r_brace)) break; continue; } // Parse: designation[opt] initializer // If we know that this cannot be a designation, just parse the nested // initializer directly. ExprResult SubElt; if (MayBeDesignationStart()) SubElt = ParseInitializerWithPotentialDesignator(); else SubElt = ParseInitializer(); if (Tok.is(tok::ellipsis)) SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); // If we couldn't parse the subelement, bail out. if (!SubElt.isInvalid()) { InitExprs.push_back(SubElt.release()); } else { InitExprsOk = false; // We have two ways to try to recover from this error: if the code looks // grammatically ok (i.e. we have a comma coming up) try to continue // parsing the rest of the initializer. This allows us to emit // diagnostics for later elements that we find. If we don't see a comma, // assume there is a parse error, and just skip to recover. // FIXME: This comment doesn't sound right. If there is a r_brace // immediately, it can't be an error, since there is no other way of // leaving this loop except through this if. if (Tok.isNot(tok::comma)) { SkipUntil(tok::r_brace, StopBeforeMatch); break; } } // If we don't have a comma continued list, we're done. if (Tok.isNot(tok::comma)) break; // TODO: save comma locations if some client cares. ConsumeToken(); // Handle trailing comma. if (Tok.is(tok::r_brace)) break; } bool closed = !T.consumeClose(); if (InitExprsOk && closed) return Actions.ActOnInitList(LBraceLoc, InitExprs, T.getCloseLocation()); return ExprError(); // an error occurred. }
void RemoveUnusedStructField::getInitExprs(const Type *Ty, const Expr *E, const IndexVector *IdxVec, ExprVector &InitExprs) { const ArrayType *ArrayTy = dyn_cast<ArrayType>(Ty); if (ArrayTy) { const InitListExpr *ILE = dyn_cast<InitListExpr>(E); TransAssert(ILE && "Invalid array initializer!"); unsigned int NumInits = ILE->getNumInits(); Ty = ArrayTy->getElementType().getTypePtr(); for (unsigned I = 0; I < NumInits; ++I) { const Expr *Init = ILE->getInit(I); getInitExprs(Ty, Init, IdxVec, InitExprs); } return; } const InitListExpr *ILE = dyn_cast<InitListExpr>(E); if (!ILE) return; const RecordType *RT = NULL; if (Ty->isUnionType()) { RT = Ty->getAsUnionType(); } else if (Ty->isStructureType()) { RT = Ty->getAsStructureType(); } else { TransAssert(0 && "Bad RecordType!"); } const RecordDecl *RD = RT->getDecl(); unsigned int VecSz = IdxVec->size(); for (IndexVector::const_iterator FI = IdxVec->begin(), FE = IdxVec->end(); FI != FE; ++FI) { const FieldDecl *FD = getFieldDeclByIdx(RD, (*FI)); TransAssert(FD && "NULL FieldDecl!"); IndexVector *FieldIdxVec = FieldToIdxVector[FD]; TransAssert(FieldIdxVec && "Cannot find FieldIdxVec!"); Ty = FD->getType().getTypePtr(); const Expr *Init; unsigned int InitListIdx; if (RD->isUnion()) InitListIdx = 0; else InitListIdx = (*FI); if (InitListIdx >= ILE->getNumInits()) return; Init = ILE->getInit(InitListIdx); if (FD == TheFieldDecl) { InitExprs.push_back(Init); TransAssert((VecSz == 1) && "Bad IndexVector size!"); (void)VecSz; } else { getInitExprs(Ty, Init, FieldIdxVec, InitExprs); } } }
/// ParseAsmStatement - Parse a GNU extended asm statement. /// asm-statement: /// gnu-asm-statement /// ms-asm-statement /// /// [GNU] gnu-asm-statement: /// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' /// /// [GNU] asm-argument: /// asm-string-literal /// asm-string-literal ':' asm-operands[opt] /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] /// ':' asm-clobbers /// /// [GNU] asm-clobbers: /// asm-string-literal /// asm-clobbers ',' asm-string-literal /// StmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { msAsm = true; return ParseMicrosoftAsmStatement(AsmLoc); } DeclSpec DS(AttrFactory); SourceLocation Loc = Tok.getLocation(); ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed); // GNU asms accept, but warn, about type-qualifiers other than volatile. if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(Loc, diag::w_asm_qualifier_ignored) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict"; // FIXME: Once GCC supports _Atomic, check whether it permits it here. if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic"; // Remember if this was a volatile asm. bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after) << "asm"; SkipUntil(tok::r_paren, StopAtSemi); return StmtError(); } BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ExprResult AsmString(ParseAsmStringLiteral()); // Check if GNU-style InlineAsm is disabled. // Error on anything other than empty string. if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) { const auto *SL = cast<StringLiteral>(AsmString.get()); if (!SL->getString().trim().empty()) Diag(Loc, diag::err_gnu_inline_asm_disabled); } if (AsmString.isInvalid()) { // Consume up to and including the closing paren. T.skipToEnd(); return StmtError(); } SmallVector<IdentifierInfo *, 4> Names; ExprVector Constraints; ExprVector Exprs; ExprVector Clobbers; if (Tok.is(tok::r_paren)) { // We have a simple asm expression like 'asm("foo")'. T.consumeClose(); return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation()); } // Parse Outputs, if present. bool AteExtraColon = false; if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { // In C++ mode, parse "::" like ": :". AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); } unsigned NumOutputs = Names.size(); // Parse Inputs, if present. if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { // In C++ mode, parse "::" like ": :". if (AteExtraColon) AteExtraColon = false; else { AteExtraColon = Tok.is(tok::coloncolon); ConsumeToken(); } if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) return StmtError(); } assert(Names.size() == Constraints.size() && Constraints.size() == Exprs.size() && "Input operand size mismatch!"); unsigned NumInputs = Names.size() - NumOutputs; // Parse the clobbers, if present. if (AteExtraColon || Tok.is(tok::colon)) { if (!AteExtraColon) ConsumeToken(); // Parse the asm-string list for clobbers if present. if (Tok.isNot(tok::r_paren)) { while (1) { ExprResult Clobber(ParseAsmStringLiteral()); if (Clobber.isInvalid()) break; Clobbers.push_back(Clobber.get()); if (!TryConsumeToken(tok::comma)) break; } } } T.consumeClose(); return Actions.ActOnGCCAsmStmt( AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation()); }
// Evaluates an expression. Considers all rules etc. In some cases there are simply // no changes possible and the expression remains unchanged (e.g. a+b). void Expression::Evaluate(Calculator *calculator, int32 recursions) { // Since the expression is expected to be already structured, it must have a head. if(!head) throw DefinitionException("Expression::Evaluate: Expression has no head."); if(recursions > Max_Evaluate_Recursions) throw LimitationException("Maximum number of recursive definitions reached."); head->Evaluate(calculator, recursions); // If Expression is a symbol Definition *symbolDef = SymbolDefinition(calculator); if(symbolDef) { // Look if value is defined if(symbolDef->Value()) { bool changed = !SameExpression(symbolDef->Value()); AssignCloned(symbolDef->Value()); if(changed) Evaluate(calculator, recursions + 1); } } // If head is a pure function if(head->FunctionName() == "Function" && head->LeafCount() == 1) { ExprPtr body(head->leaves.at(0)); body->SubstituteSlots(leaves); body->Evaluate(calculator, recursions); head->leaves.clear(); MoveNotCloned(body); } // If Expression is Function call Definition *def = FunctionDefinition(calculator); if(def) { AttributeSet attributes = def->Attributes(); // Evaluate child leaves if no Hold attribute if(!attributes.Contains(atHoldAll) && !attributes.Contains(atHoldAllComplete)) { if(!attributes.Contains(atHoldFirst)) if(!leaves.empty()) leaves.at(0)->Evaluate(calculator, recursions); if(!attributes.Contains(atHoldRest)) if(leaves.size() > 1) for(ExprVector::const_iterator leaf = leaves.begin()+1; leaf != leaves.end(); ++leaf) (*leaf)->Evaluate(calculator, recursions); } // Flatten out sequences if(!attributes.Contains(atSequenceHold)) { Flatten("Sequence"); } // Apply down values for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf) { Definition *def(0); if((*leaf)->SymbolHead()) def = (*leaf)->SymbolDefinition(calculator); else if((*leaf)->IsFunctionCall()) def = (*leaf)->FrontFunctionDefinition(calculator); if(def) { bool changed(false); if(def->ApplyUpValues(this, calculator, &changed) && changed) { Evaluate(calculator, recursions + 1); return; } } } // Apply Flat attribute if(attributes.Contains(atFlat)) { Flatten(FunctionName()); } // Apply OneIdentity attribute if(attributes.Contains(atOneIdentity)) { if(ApplyOneIdentity()) return; } // Apply Listable attribute if(attributes.Contains(atListable)) { // Determine resulting list length, check if there are lists with different lengths bool listFound(false); ExprVector::size_type listSize(0); for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf) if((*leaf)->FunctionName() == "List") if(!listFound) { listSize = (*leaf)->LeafCount(); listFound = true; } else if(listSize != (*leaf)->LeafCount()) throw EvaluateException("Listable operation requires lists of the same length."); // Construct resulting list if(listFound) { ExprVector items; // Number of resulting list items = items in operand list items.reserve(listSize); // Loop through list items for(ExprVector::size_type position = 0; position < listSize; ++position) { // List item = function call, number of operands = number of original operands Expression *item = new Expression(FunctionName(), leaves.size()); for(ExprVector::iterator itemLeaf = leaves.begin(); itemLeaf != leaves.end(); ++itemLeaf) { if((*itemLeaf)->FunctionName() == "List") { // Add corresponding list item item->AppendLeaf(*((*itemLeaf)->leaves.begin() + position)); } else { // Add "whole" item (clone if necessary) if(position == 0) item->AppendLeaf(*itemLeaf); else item->AppendLeaf((*itemLeaf)->Clone()); } } items.push_back(item); } // Delete lists (elements are now in resulting list) for(ExprVector::iterator itemLeaf = leaves.begin(); itemLeaf != leaves.end(); ++itemLeaf) if((*itemLeaf)->FunctionName() == "List") { (*itemLeaf)->leaves.clear(); delete *itemLeaf; } delete head; head = new Expression("List"); leaves = items; // Evaluate the list for itself Evaluate(calculator, recursions); return; } } // Apply Orderless attribute if(attributes.Contains(atOrderless)) { std::sort(leaves.begin(), leaves.end(), &Compare); } // Apply down value rules bool changed(false); if(def->ApplyDownValues(this, calculator, &changed)) { if(changed) Evaluate(calculator, recursions + 1); return; } // Execute linked operator, if specified if(def->Predef()) def->Predef()->Apply(this, calculator, recursions); } else { // Otherwise simply evaluate the leaves for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf) (*leaf)->Evaluate(calculator, recursions); } }