// 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; }
// 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); } }