packToken calculator::eval(TokenMap vars, bool keep_refs) const { TokenBase* value = calculate(this->RPN, vars, opMap()); packToken p = packToken(value->clone()); if (keep_refs) { return packToken(value); } else { return packToken(resolve_reference(value)); } }
void add_node_dependencies( sd_dep_graph& g, sd_node_ref nref, sd_tree const& tree, sd_build_node_map_t& nd_map) { auto const& node = tree[nref.nd]; // Add node nref to graph and node map, assuming it has not been added already if(nd_map.find(nref) == std::end(nd_map)) { auto vtx = boost::add_vertex(sd_dg_vertex_props(nref), g); nd_map[nref] = vtx; } auto src = nd_map.at(nref); // TODO: Wanted? // First add the node's parent as a dependency auto parent = tree.get_parent(nref.nd); if(parent.second) { auto parent_ref = sd_node_ref{ parent.first }; // If the parent is not already in the graph/node map, then add it if(nd_map.find(parent_ref) == std::end(nd_map)) { auto p_vtx = boost::add_vertex(sd_dg_vertex_props(parent_ref), g); nd_map[parent_ref] = p_vtx; } auto parent_vtx = nd_map.at(parent_ref); auto props = dg_edge_props{ DependencyType::Parent }; boost::add_edge(src, parent_vtx, props, g); } // Iterate over direct dependencies of nref auto defn_deps = get_node_deps(node.defn); for(auto const& dd : defn_deps) { // Resolve the dependency reference (possibly to 0, 1 or multiple instantiated nodes) auto sd_deps = resolve_reference(dd, navigator{ &tree, nref }); for(auto const& sdd : sd_deps) { auto props = dg_edge_props{ DependencyType::Generic }; // If the dependency is not already in the graph/node map, then add it if(nd_map.find(sdd) == std::end(nd_map)) { auto d_vtx = boost::add_vertex(sd_dg_vertex_props(sdd), g); nd_map[sdd] = d_vtx; } auto dst = nd_map.at(sdd); // Add a directed edge from nref to the dependency boost::add_edge(src, dst, props, g); } } }
packToken calculator::calculate(const char* expr, TokenMap vars, const char* delim, const char** rest) { // Convert to RPN with Dijkstra's Shunting-yard algorithm. RAII_TokenQueue_t rpn = calculator::toRPN(expr, vars, delim, rest); TokenBase* ret = calculator::calculate(rpn, vars); return packToken(resolve_reference(ret)); }
std::string calculator::str(TokenQueue_t rpn) { std::stringstream ss; ss << "calculator { RPN: [ "; while (rpn.size()) { ss << packToken(resolve_reference(rpn.front()->clone())).str(); rpn.pop(); ss << (rpn.size() ? ", ":""); } ss << " ] }"; return ss.str(); }
TokenBase* calculator::calculate(const TokenQueue_t& rpn, TokenMap scope, const opMap_t& opMap) { evaluationData data(rpn, scope, opMap); // Evaluate the expression in RPN form. std::stack<TokenBase*> evaluation; while (!data.rpn.empty()) { TokenBase* base = data.rpn.front()->clone(); data.rpn.pop(); // Operator: if (base->type == OP) { data.op = static_cast<Token<std::string>*>(base)->val; delete base; /* * * * * Resolve operands Values and References: * * * * */ if (evaluation.size() < 2) { cleanStack(evaluation); throw std::domain_error("Invalid equation."); } TokenBase* b_right = evaluation.top(); evaluation.pop(); TokenBase* b_left = evaluation.top(); evaluation.pop(); if (b_right->type == VAR) { std::string var_name = static_cast<Token<std::string>*>(b_right)->val; delete b_right; delete resolve_reference(b_left); cleanStack(evaluation); throw std::domain_error("Unable to find the variable '" + var_name + "'."); } else { b_right = resolve_reference(b_right, &data.scope); } packToken r_left; packToken m_left; if (b_left->type & REF) { RefToken* left = static_cast<RefToken*>(b_left); r_left = left->key; m_left = left->source; b_left = resolve_reference(left, &data.scope); } else if (b_left->type == VAR) { r_left = static_cast<Token<std::string>*>(b_left)->val; } /* * * * * Resolve Asign Operation * * * * */ if (!data.op.compare("=")) { delete b_left; // If the left operand has a variable name: if (r_left->type == STR) { if (m_left->type == MAP) { TokenMap& map = m_left.asMap(); std::string& key = r_left.asString(); map[key] = packToken(b_right->clone()); } else { TokenMap* map = data.scope.findMap(r_left.asString()); if (!map || *map == TokenMap::default_global()) { // Assign on the local scope. // The user should not be able to implicitly overwrite // variables he did not declare, since it's error prone. data.scope[r_left.asString()] = packToken(b_right->clone()); } else { (*map)[r_left.asString()] = packToken(b_right->clone()); } } evaluation.push(b_right); // If the left operand has an index number: } else if (r_left->type & NUM) { if (m_left->type == LIST) { TokenList& list = m_left.asList(); size_t index = r_left.asInt(); list[index] = packToken(b_right->clone()); } else { delete b_right; cleanStack(evaluation); throw std::domain_error("Left operand of assignment is not a list!"); } evaluation.push(b_right); } else { packToken p_right(b_right->clone()); delete b_right; cleanStack(evaluation); throw undefined_operation(data.op, r_left, p_right); } } else if (b_left->type == FUNC && data.op == "()") { Function* f_left = static_cast<Function*>(b_left); if (!data.op.compare("()")) { // Collect the parameter tuple: Tuple right; if (b_right->type == TUPLE) { right = *static_cast<Tuple*>(b_right); } else { right = Tuple(b_right); } delete b_right; packToken _this; if (m_left->type != NONE) { _this = m_left; } else { _this = data.scope; } // Execute the function: packToken ret; try { ret = Function::call(_this, f_left, &right, data.scope); } catch (...) { cleanStack(evaluation); delete f_left; throw; } delete f_left; evaluation.push(ret->clone()); } else { packToken p_right(b_right->clone()); packToken p_left(b_left->clone()); delete b_right; cleanStack(evaluation); throw undefined_operation(data.op, p_left, p_right); } } else { data.opID = Operation::build_mask(b_left->type, b_right->type); packToken p_left(b_left); packToken p_right(b_right); TokenBase* result = 0; try { // Resolve the operation: result = exec_operation(p_left, p_right, &data, data.op); if (!result) { result = exec_operation(p_left, p_right, &data, ANY_OP); } } catch (...) { cleanStack(evaluation); throw; } if (result) { evaluation.push(result); } else { cleanStack(evaluation); throw undefined_operation(data.op, p_left, p_right); } } } else if (base->type == VAR) { // Variable packToken* value = NULL; std::string key = static_cast<Token<std::string>*>(base)->val; value = data.scope.find(key); if (value) { TokenBase* copy = (*value)->clone(); evaluation.push(new RefToken(key, copy)); delete base; } else { evaluation.push(base); } } else { evaluation.push(base); } } return evaluation.top(); }
void cleanStack(std::stack<TokenBase*> st) { while (st.size() > 0) { delete resolve_reference(st.top()); st.pop(); } }
void rpnBuilder::cleanRPN(TokenQueue_t* rpn) { while (rpn->size()) { delete resolve_reference(rpn->front()); rpn->pop(); } }