// Resolve build-in operations for non-map types, e.g.: 'str'.len() packToken TypeSpecificFunction(const packToken& p_left, const packToken& p_right, evaluationData* data) { if (p_left->type == MAP) throw Operation::Reject(); TokenMap& attr_map = calculator::type_attribute_map()[p_left->type]; std::string& key = p_right.asString(); packToken* attr = attr_map.find(key); if (attr) { // Note: If attr is a function, it will receive have // scope["this"] == source, so it can make changes on this object. // Or just read some information for example: its length. return RefToken(key, (*attr), p_left); } else { throw undefined_operation(data->op, p_left, p_right); } }
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 have_all_operations_been_seen (void) { char missing_list[MAX_IDENT_LEN * MAX_NUM_OPS]; char unneeded_list[MAX_IDENT_LEN * MAX_NUM_OPS]; SPECIAL_OP op; int q; missing_list[0] = '\0'; unneeded_list[0] = '\0'; FOREACH_OPERATION_INDEX(q) { op = op_tab[q].op_num; if (op_exists_in_realm(op, layer_realm) && !seen[op]) { if (op == DDLHINT_OP) { if (!annotations) { /* The "no annotation" remark is enough to call gen_ddl */ gen_ddl(); } else { /* There's no other notion of default for this procedure */ strcat(missing_list, op_tab[q].name); strcat(missing_list, " "); } continue; } if (retrieval_op(op) && !retrieval) { /* Okay. We don't expect them here (BJG). */ continue; } if (!call_below(op, 0)) { /* Then what happens is that this is the last layer that the operation can exist in (since it can't be called below). We generate a warning & some notion of a default. The default depends on if the operation can be an expression or not. (BJG) */ out(op_tab[q].proc, layer_name); if (op == REF_OP || op == IREF_OP) { out("{ NODE *P2_r, *P2_result = NULL;"); do_action((op == REF_OP) ? "ref" : "iref", "cursor0", "field"); out("if (!P2_result)" "P2_result = terminal_string1(\" \");" "return(P2_result); }"); } else { out("{ return("); undefined_operation(op_tab[q].name, op); out("); }"); } seen[op] = TRUE; continue; } if (retrieval_op(op)) { switch (retrieval) { case 0: /* NEVER */ /* ok. don't need retrieval ops */ break; case 1: case 2: /* SOMETIMES */ /* ALWAYS */ warning(3, "retrieval operation %s not defined for layer %s", op_tab[q].name, layer_name); break; default: error("Error in retrieval value"); } continue; } } if (!(op_exists_in_realm(op, layer_realm)) && seen[op]) { strcat(unneeded_list, op_tab[q].name); strcat(unneeded_list, " "); } } if (missing_list[0] != '\0') error("missing operations: %s", missing_list); if (unneeded_list[0] != '\0') error("unneeded operations: %s", unneeded_list); }