static JsonElement *FnCallTypeToJson(const FnCallType *fn_syntax) { JsonElement *json_fn = JsonObjectCreate(10); JsonObjectAppendString(json_fn, "status", SyntaxStatusToString(fn_syntax->status)); JsonObjectAppendString(json_fn, "returnType", DataTypeToString(fn_syntax->dtype)); { JsonElement *params = JsonArrayCreate(10); for (int i = 0; fn_syntax->args[i].pattern; i++) { const FnCallArg *param = &fn_syntax->args[i]; JsonElement *json_param = JsonObjectCreate(2); JsonObjectAppendString(json_param, "type", DataTypeToString(param->dtype)); JsonObjectAppendString(json_param, "range", param->pattern); JsonArrayAppendObject(params, json_param); } JsonObjectAppendArray(json_fn, "parameters", params); } JsonObjectAppendBool(json_fn, "variadic", fn_syntax->options & FNCALL_OPTION_VARARG); JsonObjectAppendBool(json_fn, "cached", fn_syntax->options & FNCALL_OPTION_CACHED); JsonObjectAppendString(json_fn, "category", FnCallCategoryToString(fn_syntax->category)); return json_fn; }
// //////////////////////////////////////////////////////////////////////////// std::string ExcEntry::ToString(const InsItem *item_list) const { std::ostringstream o_str; o_str << std::setw(5) << sequence_number_ << " " << ((item_list[item_index_].IsInSequence()) ? "S" : " ") << ((item_list[item_index_].IsInGroup()) ? "G" : " ") << " " << std::setw(5) << item_list[item_index_].auxiliary_id_ << std::left << " " << std::setw(31) << std::left << item_list[item_index_].field_name_ << " " << std::setw(10) << DataTypeToString(item_list[item_index_].data_type_) << std::right << " = ["; if (item_list[item_index_].IsTypePrimitive()) { if (is_null_) o_str << "] <*NULL*>"; else { if (item_list[item_index_].IsTypeCharArray()) o_str << datum_ptr_ << "]"; else o_str << DatumToString(item_list[item_index_].data_type_, datum_length_, datum_ptr_) << "]"; } } else o_str << "] <*N/A*>"; return(o_str.str()); }
/** \param data_type If this parameter is not equal to \e DataType_Invalid , this function will check to ensure that any instruction context item field located has the same data type. */ const InsItem *InsContext::GetItemPtr(const InsItem &parent_ref, unsigned int auxiliary_id, const std::string &field_name, DataType data_type, bool is_required) const { try { if ((!auxiliary_id) && field_name.empty()) MLB::Utility::ThrowInvalidArgument("The specified auxiliary " "identifier is zero and the specified field name is empty --- " "at least one of them must be specified in order to locate an " "instruction item field."); const InsItem *item_ptr = &(ins_item_list_[parent_ref.item_index_]); for (unsigned int count_1 = 0; count_1 < parent_ref.element_count_; ++count_1, ++item_ptr) { if ((count_1 == 0) && (data_type != DataType_Template)) ; else { bool match_flag; if (auxiliary_id) match_flag = (auxiliary_id == item_ptr->auxiliary_id_) && (field_name == item_ptr->field_name_); else match_flag = (field_name == item_ptr->field_name_); if (match_flag) { if ((data_type != DataType_Invalid) && (item_ptr->data_type_ != data_type)) MLB::Utility::ThrowLogicError("Expected data type " + DataTypeToString(data_type) + ", but the actual data " "type is " + DataTypeToString(item_ptr->data_type_) + "."); return(item_ptr); } } } if (is_required) MLB::Utility::ThrowLogicError("Unable to locate this required field."); } catch (const std::exception &except) { MLB::Utility::Rethrow(except, "Attempt to locate instruction context " "field name '" + field_name + "', auxiliary identifier " + MLB::Utility::AnyToString(auxiliary_id) + " as a child field within " "parent " + DataTypeToString(parent_ref.data_type_) + " '" + parent_ref.field_name_ + "' failed: " + std::string(except.what())); } return(NULL); }
static JsonElement *ConstraintSyntaxToJson(const ConstraintSyntax *constraint_syntax) { JsonElement *json_constraint = JsonObjectCreate(5); JsonObjectAppendString(json_constraint, "attribute", constraint_syntax->lval); JsonObjectAppendString(json_constraint, "status", SyntaxStatusToString(constraint_syntax->status)); JsonObjectAppendString(json_constraint, "type", DataTypeToString(constraint_syntax->dtype)); if (constraint_syntax->dtype != CF_DATA_TYPE_BODY && constraint_syntax->dtype != CF_DATA_TYPE_BUNDLE) { JsonObjectAppendString(json_constraint, "range", constraint_syntax->range.validation_string); } return json_constraint; }
// //////////////////////////////////////////////////////////////////////////// std::string ExcEntry::ToStringDebug(const InsItem *item_list) const { std::ostringstream o_str; o_str << std::setw(5) << sequence_number_ << " " << ((item_list[item_index_].IsInSequence()) ? "S" : " ") << ((item_list[item_index_].IsInGroup()) ? "G" : " ") << " " << std::setw(5) << item_list[item_index_].auxiliary_id_ << std::left << " " << std::setw(31) << std::left << item_list[item_index_].field_name_ << " " << std::setw(10) << DataTypeToString(item_list[item_index_].data_type_) << " " << std::setw(13) << InsItemFlagBitsToString(item_list[item_index_].flags_) << " " << std::setw(10) << item_list[item_index_].field_operator_ #ifdef VFAST_DEBUG_EXC_ENTRY << " " << "[PMap=" << pmap_flag_ << "] " << "[Data=" << ToHexStringDebug(begin_ptr_, end_ptr_) << "]" #else << " " << "[PMap=?] " << "[Data=?? ?? ?? ?? ?? ?? ?? ?? ?? ??]" #endif // #ifdef VFAST_DEBUG_EXC_ENTRY << std::right << " = ["; if (item_list[item_index_].IsTypePrimitive()) { if (is_null_) o_str << "] <*NULL*>"; else { if (item_list[item_index_].IsTypeCharArray()) o_str << datum_ptr_ << "]"; else o_str << DatumToString(item_list[item_index_].data_type_, datum_length_, datum_ptr_) << "]"; } } else o_str << "] <*N/A*>"; return(o_str.str()); }
PromiseResult VerifyVarPromise(EvalContext *ctx, const Promise *pp, bool allow_duplicates) { ConvergeVariableOptions opts = CollectConvergeVariableOptions(ctx, pp, allow_duplicates); if (!opts.should_converge) { return PROMISE_RESULT_NOOP; } Attributes a = { {0} }; // More consideration needs to be given to using these //a.transaction = GetTransactionConstraints(pp); a.classes = GetClassDefinitionConstraints(ctx, pp); VarRef *ref = VarRefParseFromBundle(pp->promiser, PromiseGetBundle(pp)); if (strcmp("meta", pp->parent_promise_type->name) == 0) { VarRefSetMeta(ref, true); } DataType existing_value_type = CF_DATA_TYPE_NONE; const void *const existing_value = IsExpandable(pp->promiser) ? NULL : EvalContextVariableGet(ctx, ref, &existing_value_type); PromiseResult result = PROMISE_RESULT_NOOP; Rval rval = opts.cp_save->rval; if (rval.item != NULL) { DataType data_type = DataTypeFromString(opts.cp_save->lval); if (opts.cp_save->rval.type == RVAL_TYPE_FNCALL) { FnCall *fp = RvalFnCallValue(rval); const FnCallType *fn = FnCallTypeGet(fp->name); if (!fn) { assert(false && "Canary: should have been caught before this point"); FatalError(ctx, "While setting variable '%s' in bundle '%s', unknown function '%s'", pp->promiser, PromiseGetBundle(pp)->name, fp->name); } if (fn->dtype != DataTypeFromString(opts.cp_save->lval)) { FatalError(ctx, "While setting variable '%s' in bundle '%s', variable declared type '%s' but function '%s' returns type '%s'", pp->promiser, PromiseGetBundle(pp)->name, opts.cp_save->lval, fp->name, DataTypeToString(fn->dtype)); } if (existing_value_type != CF_DATA_TYPE_NONE) { // Already did this VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } FnCallResult res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), fp, pp); if (res.status == FNCALL_FAILURE) { /* We do not assign variables to failed fn calls */ RvalDestroy(res.rval); VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } else { rval = res.rval; } } else { Buffer *conv = BufferNew(); bool malformed = false, misprint = false; if (strcmp(opts.cp_save->lval, "int") == 0) { long int asint = IntFromString(opts.cp_save->rval.item); if (asint == CF_NOINT) { malformed = true; } else if (0 > BufferPrintf(conv, "%ld", asint)) { misprint = true; } else { rval = RvalNew(BufferData(conv), opts.cp_save->rval.type); } } else if (strcmp(opts.cp_save->lval, "real") == 0) { double real_value; if (!DoubleFromString(opts.cp_save->rval.item, &real_value)) { malformed = true; } else if (0 > BufferPrintf(conv, "%lf", real_value)) { misprint = true; } else { rval = RvalNew(BufferData(conv), opts.cp_save->rval.type); } } else { rval = RvalCopy(opts.cp_save->rval); } BufferDestroy(conv); if (malformed) { /* Arises when opts->cp_save->rval.item isn't yet expanded. */ /* Has already been logged by *FromString */ VarRefDestroy(ref); return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } else if (misprint) { /* Even though no problems with memory allocation can * get here, there might be other problems. */ UnexpectedError("Problems writing to buffer"); VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } else if (rval.type == RVAL_TYPE_LIST) { Rlist *rval_list = RvalRlistValue(rval); RlistFlatten(ctx, &rval_list); rval.item = rval_list; } } if (Epimenides(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, pp->promiser, rval, 0)) { Log(LOG_LEVEL_ERR, "Variable '%s' contains itself indirectly - an unkeepable promise", pp->promiser); exit(EXIT_FAILURE); } else { /* See if the variable needs recursively expanding again */ Rval returnval = EvaluateFinalRval(ctx, PromiseGetPolicy(pp), ref->ns, ref->scope, rval, true, pp); RvalDestroy(rval); // freed before function exit rval = returnval; } if (existing_value_type != CF_DATA_TYPE_NONE) { if (!opts.ok_redefine) /* only on second iteration, else we ignore broken promises */ { if (THIS_AGENT_TYPE == AGENT_TYPE_COMMON && !CompareRval(existing_value, DataTypeToRvalType(existing_value_type), rval.item, rval.type)) { switch (rval.type) { case RVAL_TYPE_SCALAR: Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant scalar '%s', was '%s' now '%s'", pp->promiser, (const char *)existing_value, RvalScalarValue(rval)); PromiseRef(LOG_LEVEL_VERBOSE, pp); break; case RVAL_TYPE_LIST: { Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant list '%s'", pp->promiser); Writer *w = StringWriter(); RlistWrite(w, existing_value); char *oldstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, "Old value '%s'", oldstr); free(oldstr); w = StringWriter(); RlistWrite(w, rval.item); char *newstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, " New value '%s'", newstr); free(newstr); PromiseRef(LOG_LEVEL_VERBOSE, pp); } break; case RVAL_TYPE_CONTAINER: case RVAL_TYPE_FNCALL: case RVAL_TYPE_NOPROMISEE: break; } } RvalDestroy(rval); VarRefDestroy(ref); return result; } } if (IsCf3VarString(pp->promiser)) { // Unexpanded variables, we don't do anything with RvalDestroy(rval); VarRefDestroy(ref); return result; } if (!IsValidVariableName(pp->promiser)) { Log(LOG_LEVEL_ERR, "Variable identifier contains illegal characters"); PromiseRef(LOG_LEVEL_ERR, pp); RvalDestroy(rval); VarRefDestroy(ref); return result; } if (rval.type == RVAL_TYPE_LIST) { if (opts.drop_undefined) { for (Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next) { if (IsNakedVar(RlistScalarValue(rp), '@')) { free(rp->val.item); rp->val.item = xstrdup(CF_NULL_VALUE); } } } for (const Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: break; default: // Cannot assign variable because value is a list containing a non-scalar item VarRefDestroy(ref); RvalDestroy(rval); return result; } } } if (ref->num_indices > 0) { if (data_type == CF_DATA_TYPE_CONTAINER) { char *lval_str = VarRefToString(ref, true); Log(LOG_LEVEL_ERR, "Cannot assign a container to an indexed variable name '%s'. Should be assigned to '%s' instead", lval_str, ref->lval); free(lval_str); VarRefDestroy(ref); RvalDestroy(rval); return result; } else { DataType existing_type = CF_DATA_TYPE_NONE; VarRef *base_ref = VarRefCopyIndexless(ref); if (EvalContextVariableGet(ctx, ref, &existing_type) && existing_type == CF_DATA_TYPE_CONTAINER) { char *lval_str = VarRefToString(ref, true); char *base_ref_str = VarRefToString(base_ref, true); Log(LOG_LEVEL_ERR, "Cannot assign value to indexed variable name '%s', because a container is already assigned to the base name '%s'", lval_str, base_ref_str); free(lval_str); free(base_ref_str); VarRefDestroy(base_ref); VarRefDestroy(ref); RvalDestroy(rval); return result; } VarRefDestroy(base_ref); } } DataType required_datatype = DataTypeFromString(opts.cp_save->lval); if (rval.type != DataTypeToRvalType(required_datatype)) { char *ref_str = VarRefToString(ref, true); char *value_str = RvalToString(rval); Log(LOG_LEVEL_ERR, "Variable '%s' expected a variable of type '%s', but was given incompatible value '%s'", ref_str, DataTypeToString(required_datatype), value_str); PromiseRef(LOG_LEVEL_ERR, pp); free(ref_str); free(value_str); VarRefDestroy(ref); RvalDestroy(rval); return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } if (!EvalContextVariablePut(ctx, ref, rval.item, required_datatype, "source=promise")) { Log(LOG_LEVEL_VERBOSE, "Unable to converge %s.%s value (possibly empty or infinite regression)", ref->scope, pp->promiser); PromiseRef(LOG_LEVEL_VERBOSE, pp); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } else { Rlist *promise_meta = PromiseGetConstraintAsList(ctx, "meta", pp); if (promise_meta) { StringSet *class_meta = EvalContextVariableTags(ctx, ref); Buffer *print; for (const Rlist *rp = promise_meta; rp; rp = rp->next) { StringSetAdd(class_meta, xstrdup(RlistScalarValue(rp))); print = StringSetToBuffer(class_meta, ','); Log(LOG_LEVEL_DEBUG, "Added tag %s to class %s, tags now [%s]", RlistScalarValue(rp), pp->promiser, BufferData(print)); BufferDestroy(print); } } } } else { Log(LOG_LEVEL_ERR, "Variable %s has no promised value", pp->promiser); Log(LOG_LEVEL_ERR, "Rule from %s at/before line %llu", PromiseGetBundle(pp)->source_path, (unsigned long long)opts.cp_save->offset.line); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } /* * FIXME: Variable promise are exempt from normal evaluation logic still, so * they are not pushed to evaluation stack before being evaluated. Due to * this reason, we cannot call cfPS here to set classes, as it will error * out with ProgrammingError. * * In order to support 'classes' body for variables as well, we call * ClassAuditLog explicitly. */ ClassAuditLog(ctx, pp, a, result); VarRefDestroy(ref); RvalDestroy(rval); return result; }
int ScopeMapBodyArgs(EvalContext *ctx, const char *ns, const char *scope, Rlist *give, const Rlist *take) { Rlist *rpg = NULL; const Rlist *rpt = NULL; FnCall *fp; DataType dtg = DATA_TYPE_NONE, dtt = DATA_TYPE_NONE; char *lval; void *rval; int len1, len2; len1 = RlistLen(give); len2 = RlistLen(take); if (len1 != len2) { Log(LOG_LEVEL_ERR, "Argument mismatch in body template give[+args] = %d, take[-args] = %d", len1, len2); return false; } for (rpg = give, rpt = take; rpg != NULL && rpt != NULL; rpg = rpg->next, rpt = rpt->next) { dtg = StringDataType(ctx, (char *) rpg->item); dtt = StringDataType(ctx, (char *) rpt->item); if (dtg != dtt) { Log(LOG_LEVEL_ERR, "Type mismatch between logical/formal parameters %s/%s", (char *) rpg->item, (char *) rpt->item); Log(LOG_LEVEL_ERR, "%s is %s whereas %s is %s", (char *) rpg->item, DataTypeToString(dtg), (char *) rpt->item, DataTypeToString(dtt)); } switch (rpg->type) { case RVAL_TYPE_SCALAR: { lval = (char *) rpt->item; rval = rpg->item; VarRef *ref = VarRefParseFromNamespaceAndScope(lval, ns, scope, CF_NS, '.'); EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_SCALAR }, dtg); } break; case RVAL_TYPE_LIST: { lval = (char *) rpt->item; rval = rpg->item; VarRef *ref = VarRefParseFromNamespaceAndScope(lval, ns, scope, CF_NS, '.'); EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_LIST }, dtg); VarRefDestroy(ref); } break; case RVAL_TYPE_FNCALL: fp = (FnCall *) rpg->item; dtg = DATA_TYPE_NONE; { const FnCallType *fncall_type = FnCallTypeGet(fp->name); if (fncall_type) { dtg = fncall_type->dtype; } } FnCallResult res = FnCallEvaluate(ctx, fp, NULL); if (res.status == FNCALL_FAILURE && THIS_AGENT_TYPE != AGENT_TYPE_COMMON) { Log(LOG_LEVEL_VERBOSE, "Embedded function argument does not resolve to a name - probably too many evaluation levels for '%s'", fp->name); } else { FnCallDestroy(fp); rpg->item = res.rval.item; rpg->type = res.rval.type; lval = (char *) rpt->item; rval = rpg->item; VarRef *ref = VarRefParseFromNamespaceAndScope(lval, ns, scope, CF_NS, '.'); EvalContextVariablePut(ctx, ref, (Rval) {rval, RVAL_TYPE_SCALAR }, dtg); VarRefDestroy(ref); } break; default: /* Nothing else should happen */ ProgrammingError("Software error: something not a scalar/function in argument literal"); } } return true; }
/** * @brief Flattens an Rlist by expanding naked scalar list-variable * members. Flattening is only one-level deep. */ void RlistFlatten(EvalContext *ctx, Rlist **list) { Rlist *next; for (Rlist *rp = *list; rp != NULL; rp = next) { next = rp->next; if (rp->val.type == RVAL_TYPE_SCALAR && IsNakedVar(RlistScalarValue(rp), '@')) { char naked[CF_MAXVARSIZE]; GetNaked(naked, RlistScalarValue(rp)); /* Make sure there are no inner expansions to take place, like if * rp was "@{blah_$(blue)}". */ if (!IsExpandable(naked)) { Log(LOG_LEVEL_DEBUG, "Flattening slist: %s", RlistScalarValue(rp)); VarRef *ref = VarRefParse(naked); DataType value_type; const void *value = EvalContextVariableGet(ctx, ref, &value_type); VarRefDestroy(ref); if (value_type == CF_DATA_TYPE_NONE) { assert(value == NULL); continue; /* undefined variable */ } if (DataTypeToRvalType(value_type) != RVAL_TYPE_LIST) { Log(LOG_LEVEL_WARNING, "'%s' failed - variable is not list but %s", RlistScalarValue(rp), DataTypeToString(value_type)); continue; } /* NOTE: Remember that value can be NULL as an empty Rlist. */ /* at_node: just a mnemonic name for the list node with @{blah}. */ Rlist *at_node = rp; Rlist *insert_after = at_node; for (const Rlist *rp2 = value; rp2 != NULL; rp2 = rp2->next) { assert(insert_after != NULL); RlistInsertAfter(insert_after, RvalCopy(rp2->val)); insert_after = insert_after->next; } /* Make sure we won't miss any element. */ assert(insert_after->next == next); RlistDestroyEntry(list, at_node); /* Delete @{blah} entry */ char *list_s = RlistToString(*list); Log(LOG_LEVEL_DEBUG, "Flattened slist: %s", list_s); free(list_s); } } } }
void ScopeMapBodyArgs(EvalContext *ctx, const Body *body, const Rlist *args) { const Rlist *arg = NULL; const Rlist *param = NULL; for (arg = args, param = body->args; arg != NULL && param != NULL; arg = arg->next, param = param->next) { DataType arg_type = StringDataType(ctx, RlistScalarValue(arg)); DataType param_type = StringDataType(ctx, RlistScalarValue(param)); if (arg_type != param_type) { Log(LOG_LEVEL_ERR, "Type mismatch between logical/formal parameters %s/%s", (char *) arg->item, (char *) param->item); Log(LOG_LEVEL_ERR, "%s is %s whereas %s is %s", (char *) arg->item, DataTypeToString(arg_type), (char *) param->item, DataTypeToString(param_type)); } switch (arg->type) { case RVAL_TYPE_SCALAR: { const char *lval = RlistScalarValue(param); void *rval = arg->item; VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.'); EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_SCALAR }, arg_type); } break; case RVAL_TYPE_LIST: { const char *lval = RlistScalarValue(param->item); void *rval = arg->item; VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.'); EvalContextVariablePut(ctx, ref, (Rval) { rval, RVAL_TYPE_LIST }, arg_type); VarRefDestroy(ref); } break; case RVAL_TYPE_FNCALL: { FnCall *fp = arg->item; arg_type = DATA_TYPE_NONE; { const FnCallType *fncall_type = FnCallTypeGet(fp->name); if (fncall_type) { arg_type = fncall_type->dtype; } } FnCallResult res = FnCallEvaluate(ctx, fp, NULL); if (res.status == FNCALL_FAILURE && THIS_AGENT_TYPE != AGENT_TYPE_COMMON) { Log(LOG_LEVEL_VERBOSE, "Embedded function argument does not resolve to a name - probably too many evaluation levels for '%s'", fp->name); } else { FnCallDestroy(fp); const char *lval = RlistScalarValue(param); void *rval = res.rval.item; VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.'); EvalContextVariablePut(ctx, ref, (Rval) {rval, RVAL_TYPE_SCALAR }, res.rval.type); VarRefDestroy(ref); } } break; default: /* Nothing else should happen */ ProgrammingError("Software error: something not a scalar/function in argument literal"); } } }