return XLAT_ACTION_DONE;
}
+/** Convert XLAT_BOX arguments to XLAT_TMPL
+ *
+ * xlat_tokenize() just makes all unknown arguments into XLAT_BOX, of data type FR_TYPE_STRING. Whereas
+ * xlat_tokenize_expr() calls tmpl_afrom_substr(), which tries hard to create a particular data type.
+ *
+ * This function fixes up calls of the form %(op_add: 3 4), which normally passes 2 arguments of "3" and "4",
+ * so that the arguments are instead passed as integers 3 and 4.
+ *
+ * This fixup isn't *strictly* necessary, but it's good to have no surprises in the code, if the user creates
+ * an expression manually.
+ */
+static int xlat_function_args_to_tmpl(xlat_inst_ctx_t const *xctx)
+{
+ xlat_exp_foreach(xctx->ex->call.args, arg) {
+ ssize_t slen;
+ xlat_exp_t *node;
+ tmpl_t *vpt;
+
+ fr_assert(arg->type == XLAT_GROUP);
+
+ node = xlat_exp_head(arg->group);
+ if (!node) continue;
+ if (node->type != XLAT_BOX) continue;
+ if (node->data.type != FR_TYPE_STRING) continue;
+
+ /*
+ * Try to parse it. If we can't, leave it for a run-time error.
+ */
+ slen = tmpl_afrom_substr(node, &vpt, &FR_SBUFF_IN(node->data.vb_strvalue, node->data.vb_length),
+ node->quote, NULL, NULL);
+ if (slen <= 0) continue;
+ if ((size_t) slen < node->data.vb_length) continue;
+
+ /*
+ * Leave it as XLAT_BOX, but with the (guessed) new data type.
+ */
+ fr_value_box_clear(&node->data);
+ fr_value_box_copy(node, &node->data, tmpl_value(vpt));
+ talloc_free(vpt);
+ }
+
+ return 0;
+}
+
+
#undef XLAT_REGISTER_BINARY_OP
#define XLAT_REGISTER_BINARY_OP(_op, _name) \
do { \
xlat_func_args(xlat, binary_op_xlat_args); \
xlat_internal(xlat); \
xlat_print_set(xlat, xlat_expr_print_binary); \
+ xlat_async_instantiate_set(xlat, xlat_function_args_to_tmpl, NULL, NULL, NULL); \
xlat->token = _op; \
} while (0)
match 13
#
-# @todo - this gets parsed as "4" + "3", because the parsing of
-# XLAT_BOX in xlat_tokenize_string() just makes everything into
-# FR_TYPE_STRING. The parsing in tmpl_tokenize() is different,
-# as it tries to figure out what data type things are.
-#
-# The solution is likely to have the expression code double-check
-# it's arguments on instantiate, and if they are FR_TYPE_STRING with
-# quote T_BARE_WORD, then go re-evaluate them. Tho that seems
-# terrible, TBH. A cleaner way would be to add a parse flag which tells
-# the xlat tokenizer "please try to figure out WTF this value is".
-#
-# which then gets "43", and then "43" to int, and 43+6 -> 49
-#
-# The rules for parsing tmpls at run-time are apparently different
-# than parsing them at compile time?
+# xlat_tokenize() parses it's arguments as XLAT_BOX,
+# of FR_TYPE_STRING. The binary op instantiation function
+# fixes those up via tmpl_afrom_substr().
#
xlat_purify %(op_add:4 3) + 6
-match 49
-#match ((4 + 3) + 6)
+match 13
#
# useless casts are omitted.
#match ERROR offset 1: Failed resolving attribute in expansion: Message
#
-# @todo - find some way quote the RHS? Maybe just make it
-# T_SINGLE_QUOTED_STRING for "string" types, and leave it T_BARE_WORD
-# for everything else. But this presumes that the RHS is always only
-# one value-box, and perhaps it isn't?
+# Strings are single quoted
#
xlat_purify &Filter-Id == ("foo" + "bar")
match (%{Filter-Id} == 'foobar')