summaryrefslogtreecommitdiff
path: root/expression.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2014-02-17 00:05:40 +1100
committerDavid Gibson <david@gibson.dropbear.id.au>2014-03-03 10:51:50 +1100
commit827ac8eca016c39b13fc916bbdb16f9f2fe3c34c (patch)
treee7369759973f262d99a57641c1d503d7d15e379e /expression.c
parent9a8a1f41dd1ba0d8612f2177ec58e22eff312055 (diff)
downloaddevice-tree-compiler-expressions.tar.gz
Implement string concatenate and repeat operatorsexpressions
This patch exercises the new expression infrastructure to implement syntax to concatenate and repeat strings. We use syntax inspired by Python, with '+' overloaded for string concatenation and '*' overloaded for string repeat. Normally we'd use C syntax to inspire dts syntax, but C has no obvious candidates for these string operators. Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'expression.c')
-rw-r--r--expression.c117
1 files changed, 115 insertions, 2 deletions
diff --git a/expression.c b/expression.c
index 8d6474b..2b86fed 100644
--- a/expression.c
+++ b/expression.c
@@ -294,9 +294,7 @@ INT_UNARY_OP(logic_not, !)
INT_BINARY_OP(mod, %)
INT_BINARY_OP(div, /)
-INT_BINARY_OP(mul, *)
-INT_BINARY_OP(add, +)
INT_BINARY_OP(sub, -)
INT_BINARY_OP(lshift, <<)
@@ -317,6 +315,121 @@ INT_BINARY_OP(bit_or, |)
INT_BINARY_OP(logic_and, &&)
INT_BINARY_OP(logic_or, ||)
+/*
+ * We need to write out add and mul in full, since they can be used on
+ * both integer and string arguments with different meanings
+ */
+
+static struct expression_value op_eval_mul(struct expression *expr,
+ enum expr_type context)
+{
+ struct expression_value arg0, arg1;
+ struct expression_value v;
+ uint64_t n, i;
+ struct data s;
+ struct data d = empty_data;
+
+ assert(expr->nargs == 2);
+ EVALUATE(arg0, expr->arg[0], EXPR_VOID);
+ EVALUATE(arg1, expr->arg[1], EXPR_VOID);
+
+ if ((arg0.type == EXPR_INTEGER) && (arg1.type == EXPR_INTEGER)) {
+ v.type = EXPR_INTEGER;
+ v.value.integer = arg0.value.integer * arg1.value.integer;
+ return v;
+ } else if ((arg0.type != EXPR_INTEGER) && (arg0.type != EXPR_STRING)) {
+ return type_error(expr->arg[0], "Expected integer or string"
+ " expression (found %s)",
+ expression_typename(arg0.type));
+ } else if (arg0.type == EXPR_INTEGER) {
+ if (arg1.type != EXPR_STRING)
+ return type_error(expr->arg[1], "Expected string"
+ " expression (found %s)",
+ expression_typename(arg1.type));
+ n = arg0.value.integer;
+ s = arg1.value.d;
+ } else {
+ assert(arg0.type == EXPR_STRING);
+ if (arg1.type != EXPR_INTEGER)
+ return type_error(expr->arg[1], "Expected integer"
+ " expression (found %s)",
+ expression_typename(arg1.type));
+ n = arg1.value.integer;
+ s = arg0.value.d;
+ }
+
+ for (i = 0; i < n; i++)
+ d = data_append_data(d, s.val, s.len - 1);
+
+ v.type = EXPR_STRING;
+ v.value.d = data_append_byte(d, 0); /* Terminating \0 */
+
+ return v;
+}
+static struct operator op_mul = {
+ .name = "*",
+ .evaluate = op_eval_mul,
+};
+struct expression *expression_mul(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1)
+{
+ return expression_build(loc, &op_mul, arg0, arg1);
+}
+
+static struct expression_value op_eval_add(struct expression *expr,
+ enum expr_type context)
+{
+ struct expression_value arg0, arg1;
+ struct expression_value v;
+
+ assert(expr->nargs == 2);
+ EVALUATE(arg0, expr->arg[0], EXPR_VOID);
+ EVALUATE(arg1, expr->arg[1], EXPR_VOID);
+ if ((arg0.type != EXPR_INTEGER) && (arg0.type != EXPR_STRING))
+ return type_error(expr->arg[0], "Expected integer or string"
+ " expression (found %s)",
+ expression_typename(arg0.type));
+ if ((arg1.type != EXPR_INTEGER) && (arg1.type != EXPR_STRING))
+ return type_error(expr->arg[0], "Expected integer or string"
+ " expression (found %s)",
+ expression_typename(arg1.type));
+
+ if (arg0.type != arg1.type)
+ return type_error(expr, "Operand types to + (%s, %s) don't match",
+ expression_typename(arg0.type),
+ expression_typename(arg1.type));
+
+ v.type = arg0.type;
+
+ switch (v.type) {
+ case EXPR_INTEGER:
+ v.value.integer = arg0.value.integer + arg1.value.integer;
+ break;
+
+ case EXPR_STRING:
+ v.value.d = data_copy_mem(arg0.value.d.val,
+ arg0.value.d.len - 1);
+ v.value.d = data_append_data(v.value.d, arg1.value.d.val,
+ arg1.value.d.len);
+ break;
+
+ default:
+ assert(0);
+ }
+ return v;
+}
+static struct operator op_add = {
+ .name = "+",
+ .evaluate = op_eval_add,
+};
+struct expression *expression_add(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1)
+{
+ return expression_build(loc, &op_add, arg0, arg1);
+}
+
static struct expression_value op_eval_conditional(struct expression *expr,
enum expr_type context)
{