* @todo - short-circuit && / || need to be updated. This requires various magic in their instantiation
* routines, which is not yet done.
*
- * @todo - Check for input flags->pure, and node->internal && node->token != T_INVALID && node->pure. If
- * so, we call xlat_purify() to purify the results. This capability lets us write tests for parsing
- * which use simple numbers, to verify that the parser is OK.
+ * @todo - all function arguments should be in groups, so we need to fix that. Right now, binary
+ * expressions are fixed. But unary ones are not. We did it via a hack, but it might be better to do it
+ * a different way in the future. The problem is that no matter which way we choose, we'll have to
+ * talloc_steal() something.
+ *
+ * @todo - run xlat_purify_expr() after creating the unary node.
*
* The purify function should also be smart enough to do things like remove redundant casts.
*
return rcode;
}
+static xlat_exp_t *xlat_groupify_node(TALLOC_CTX *ctx, xlat_exp_t *node)
+{
+ xlat_exp_t *group;
+
+ fr_assert(node->type != XLAT_GROUP);
+
+ group = xlat_exp_alloc_null(ctx);
+ xlat_exp_set_type(group, XLAT_GROUP);
+ group->quote = T_BARE_WORD;
+
+ group->child = talloc_steal(group, node);
+ group->flags = node->flags;
+
+ if (node->next) {
+ group->next = xlat_groupify_node(ctx, node->next);
+ node->next = NULL;
+ }
+
+ return group;
+}
+
+/*
+ * Any function requires each argument to be in it's own XLAT_GROUP. But we can't create an XLAT_GROUP
+ * from the start of parsing, as we might need to return an XLAT_FUNC, or another type of xlat. Instead,
+ * we just work on the bare nodes, and then later groupify them. For now, it's just easier to do it this way.
+ */
+static void xlat_groupify_expr(xlat_exp_t *node)
+{
+ xlat_t const *func;
+
+ if (node->type != XLAT_FUNC) return;
+
+ func = node->call.func;
+
+ if (!func->internal) return;
+
+ if (func->token == T_INVALID) return;
+
+ /*
+ * It's already been groupified, don't do anything.
+ */
+ if (node->child->type == XLAT_GROUP) return;
+
+ node->child = xlat_groupify_node(node, node->child);
+}
+
static xlat_arg_parser_t const cast_xlat_args[] = {
{ .required = true, .type = FR_TYPE_INT32 },
{ .required = true, .type = FR_TYPE_VOID },
cast->child->next = node;
xlat_flags_merge(&cast->flags, &node->flags);
node = cast;
+
+ xlat_groupify_expr(node);
}
check_unary:
}
}
+ /*
+ * Ensure that the various nodes are grouped properly.
+ */
+ xlat_groupify_expr(node);
+
lhs = node;
goto redo;
}
if (node->quote != T_BARE_WORD) FR_SBUFF_IN_CHAR_RETURN(out, fr_token_quote[node->quote]);
xlat_print(out, node->child, fr_value_escape_by_quote[node->quote]);
if (node->quote != T_BARE_WORD) FR_SBUFF_IN_CHAR_RETURN(out, fr_token_quote[node->quote]);
- if (node->next) FR_SBUFF_IN_CHAR_RETURN(out, ' '); /* Add ' ' between args */
+ if (node->next) FR_SBUFF_IN_CHAR_RETURN(out, ' '); /* Add ' ' between args */
goto done;
case XLAT_BOX:
+ /*
+ * @todo - respect node->quote here, too. Which also means updating the parser.
+ */
FR_SBUFF_RETURN(fr_value_box_print, out, &node->data, e_rules);
goto done;
} else {
FR_SBUFF_IN_STRCPY_LITERAL_RETURN(out, "(");
- xlat_print_node(out, node->child, e_rules);
- FR_SBUFF_IN_CHAR_RETURN(out, ' ');
+ xlat_print_node(out, node->child, e_rules); /* prints a space after the first argument */
/*
* @todo - when things like "+" support more than 2 arguments, print them all out
# Strings of various forms
#
xlat_expr &Filter-Id == "foo"
-match (%{Filter-Id} == \"foo\")
+match (%{Filter-Id} == "foo")
xlat_expr "foo" == "bar"
-match (\"foo\" == \"bar\")
+match ("foo" == "bar")
# note '/' is a prefix, not "divide by 24".
# and a useless cast is removed
match %{Filter-Id}
xlat_expr %{md5:foo} + "foo"
-match (%{md5:foo} + \"foo\")
+match (%{md5:foo} + "foo")
# We can name the xlat's, tho we don't need to
xlat_expr %(op_add:4 3) + 6
-match ((4 + 3) + 6)
+match ((4 + 3) + 6)
#
proto-dictionary radius
+#xlat_purify %(op_add:4 3) + 6
+#match 13
+
#
# xlat_expr, but purified
#
# Strings of various forms
#
xlat_purify &Filter-Id == "foo"
-match (%{Filter-Id} == \"foo\")
+match (%{Filter-Id} == "foo")
xlat_purify "foo" == "bar"
match no
match %{Filter-Id}
xlat_purify %{md5:foo} + "foo"
-match (%{md5:foo} + \"foo\")
+match (%{md5:foo} + "foo")
# We can name the xlat's, tho we don't need to
+#
+# And naming the xlat's means that they don't set up
+# with the magic token field, so optimizations don't work?
+#
xlat_purify %(op_add:4 3) + 6
-match ((4 + 3) + 6)
+match ((4 + 3) + 6)
#