diff options
author | Håvard Pettersen <havardpe@oath.com> | 2019-12-04 13:14:38 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2019-12-04 13:16:37 +0000 |
commit | 47b692982387a3b13f4c0dc2b57792086506fc25 (patch) | |
tree | 48e3eeecaf085f4d48b49187c8bc9c980e462520 /eval/src | |
parent | f994bcc1ad620009c3853d125dd32c301f6d046a (diff) |
auto-convert Number/String single-node expressions
... inside tensor peek address to verbatim labels
Diffstat (limited to 'eval/src')
-rw-r--r-- | eval/src/tests/eval/function/function_test.cpp | 15 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/basic_nodes.h | 2 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/function.cpp | 22 |
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)); + } } } } |