aboutsummaryrefslogtreecommitdiffstats
path: root/eval
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2019-12-04 13:14:38 +0000
committerHåvard Pettersen <havardpe@oath.com>2019-12-04 13:16:37 +0000
commit47b692982387a3b13f4c0dc2b57792086506fc25 (patch)
tree48e3eeecaf085f4d48b49187c8bc9c980e462520 /eval
parentf994bcc1ad620009c3853d125dd32c301f6d046a (diff)
auto-convert Number/String single-node expressions
... inside tensor peek address to verbatim labels
Diffstat (limited to 'eval')
-rw-r--r--eval/src/tests/eval/function/function_test.cpp15
-rw-r--r--eval/src/vespa/eval/eval/basic_nodes.h2
-rw-r--r--eval/src/vespa/eval/eval/function.cpp22
3 files changed, 35 insertions, 4 deletions
diff --git a/eval/src/tests/eval/function/function_test.cpp b/eval/src/tests/eval/function/function_test.cpp
index 6932ba46eab..6b9b52900c7 100644
--- a/eval/src/tests/eval/function/function_test.cpp
+++ b/eval/src/tests/eval/function/function_test.cpp
@@ -951,11 +951,22 @@ TEST("require that tensor peek can contain expressions") {
TEST_DO(verify_parse("t{x:1,y:(foo)}", "f(t,foo)(t{x:1,y:(foo)})"));
}
+TEST("require that trivial tensor peek string/number expressions are converted to verbatim labels") {
+ TEST_DO(verify_parse("t{x:\"foo\"}", "f(t)(t{x:foo})"));
+ TEST_DO(verify_parse("t{x:(\"foo\")}", "f(t)(t{x:foo})"));
+ TEST_DO(verify_parse("t{x:5.5}", "f(t)(t{x:5})"));
+ TEST_DO(verify_parse("t{x:(5.5)}", "f(t)(t{x:5})"));
+}
+
TEST("require that tensor peek can contain extra whitespace") {
TEST_DO(verify_parse(" t { x : 1 + bar , y : foo + 2 } ",
"f(t,bar,foo)(t{x:(1+bar),y:(foo+2)})"));
}
+TEST("require that converted tensor peek string expression must be valid identifier") {
+ TEST_DO(verify_error("x{a:\"5.5\"}", "[x{a:\"5.5\"]...[invalid identifier: '5.5']...[}]"));
+}
+
TEST("require that empty tensor peek is not allowed") {
TEST_DO(verify_error("x{}", "[x{}]...[empty peek spec]...[]"));
}
@@ -963,8 +974,8 @@ TEST("require that empty tensor peek is not allowed") {
//-----------------------------------------------------------------------------
TEST("require that nested tensor lambda using tensor peek can be parsed") {
- vespalib::string expect("tensor(x[2]):{{x:0}:tensor(y[2]):{{y:0}:((0+0)+a),{y:1}:((0+1)+a)}{y:(0)},"
- "{x:1}:tensor(y[2]):{{y:0}:((1+0)+a),{y:1}:((1+1)+a)}{y:(1)}}");
+ vespalib::string expect("tensor(x[2]):{{x:0}:tensor(y[2]):{{y:0}:((0+0)+a),{y:1}:((0+1)+a)}{y:0},"
+ "{x:1}:tensor(y[2]):{{y:0}:((1+0)+a),{y:1}:((1+1)+a)}{y:1}}");
EXPECT_EQUAL(Function::parse(expect).dump(), expect);
auto fun = Function::parse("tensor(x[2])(tensor(y[2])(x+y+a){y:(x)})");
EXPECT_EQUAL(fun.dump(), expect);
diff --git a/eval/src/vespa/eval/eval/basic_nodes.h b/eval/src/vespa/eval/eval/basic_nodes.h
index 52f39510a9b..62af30fb71f 100644
--- a/eval/src/vespa/eval/eval/basic_nodes.h
+++ b/eval/src/vespa/eval/eval/basic_nodes.h
@@ -122,7 +122,7 @@ public:
String(const vespalib::string &value_in) : _value(value_in) {}
bool is_const() const override { return true; }
double get_const_value() const override { return hash(); }
- const vespalib::string value() const { return _value; }
+ const vespalib::string &value() const { return _value; }
uint32_t hash() const { return hash_code(_value.data(), _value.size()); }
vespalib::string dump(DumpContext &ctx) const override;
void accept(NodeVisitor &visitor) const override;
diff --git a/eval/src/vespa/eval/eval/function.cpp b/eval/src/vespa/eval/eval/function.cpp
index a7eaf14e9cd..593451d6838 100644
--- a/eval/src/vespa/eval/eval/function.cpp
+++ b/eval/src/vespa/eval/eval/function.cpp
@@ -445,6 +445,14 @@ bool is_ident(char c, bool first) {
(c == '$' && !first));
}
+bool is_ident(const vespalib::string &str) {
+ bool result = str.empty() ? false : is_ident(str[0], true);
+ for (size_t i = 1; result && (i < str.size()); ++i) {
+ result &= is_ident(str[i], false);
+ }
+ return result;
+}
+
vespalib::string get_ident(ParseContext &ctx, bool allow_empty) {
ctx.skip_spaces();
vespalib::string ident;
@@ -797,7 +805,19 @@ void parse_tensor_peek(ParseContext &ctx) {
peek_spec.emplace(dim_name, label);
} else {
ctx.restore_input_mark(before_label);
- peek_spec.emplace(dim_name, get_expression(ctx));
+ auto expr = get_expression(ctx);
+ if (auto num = nodes::as<nodes::Number>(*expr)) {
+ size_t index(num->value());
+ peek_spec.emplace(dim_name, make_string("%zu", index));
+ } else if (auto str = nodes::as<nodes::String>(*expr)) {
+ if (is_ident(str->value())) {
+ peek_spec.emplace(dim_name, str->value());
+ } else {
+ ctx.fail(make_string("invalid identifier: '%s'", str->value().c_str()));
+ }
+ } else {
+ peek_spec.emplace(dim_name, std::move(expr));
+ }
}
}
}