summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/concepts/expressions.md5
-rw-r--r--src/buildtool/build_engine/expression/evaluator.cpp10
-rw-r--r--test/buildtool/build_engine/expression/expression.test.cpp16
3 files changed, 31 insertions, 0 deletions
diff --git a/doc/concepts/expressions.md b/doc/concepts/expressions.md
index aead2c31..c5d120e4 100644
--- a/doc/concepts/expressions.md
+++ b/doc/concepts/expressions.md
@@ -74,6 +74,11 @@ the value `null` is taken as default for `"default"`) and
evaluated. The value obtained this way is the result of the
evaluation.
+##### Quoting: `"'"`
+
+The value is the value of the key `"$1"` uninterpreted, if present,
+and `null` otherwise.
+
##### Sequential binding: `"let*"`
The key `"bindings"` (default `[]`) has to be (syntactically) a
diff --git a/src/buildtool/build_engine/expression/evaluator.cpp b/src/buildtool/build_engine/expression/evaluator.cpp
index 2256a040..673b80b3 100644
--- a/src/buildtool/build_engine/expression/evaluator.cpp
+++ b/src/buildtool/build_engine/expression/evaluator.cpp
@@ -499,6 +499,15 @@ auto VarExpr(SubExprEvaluator&& eval,
return result;
}
+auto QuoteExpr(SubExprEvaluator&& /*eval*/,
+ ExpressionPtr const& expr,
+ Configuration const& /*env*/) -> ExpressionPtr {
+ if (auto const literal = expr->At("$1")) {
+ return *literal;
+ }
+ return Expression::kNone;
+}
+
auto IfExpr(SubExprEvaluator&& eval,
ExpressionPtr const& expr,
Configuration const& env) -> ExpressionPtr {
@@ -1089,6 +1098,7 @@ auto AssertNonEmptyExpr(SubExprEvaluator&& eval,
auto const kBuiltInFunctions =
FunctionMap::MakePtr({{"var", VarExpr},
+ {"'", QuoteExpr},
{"if", IfExpr},
{"cond", CondExpr},
{"case", CaseExpr},
diff --git a/test/buildtool/build_engine/expression/expression.test.cpp b/test/buildtool/build_engine/expression/expression.test.cpp
index 8dd0aa92..888e7216 100644
--- a/test/buildtool/build_engine/expression/expression.test.cpp
+++ b/test/buildtool/build_engine/expression/expression.test.cpp
@@ -389,6 +389,22 @@ TEST_CASE("Expression Evaluation", "[expression]") { // NOLINT
CHECK(overwrite == Expression::FromJson(R"(["bar"])"_json));
}
+ SECTION("quote expression") {
+ auto expr = Expression::FromJson(R"(
+ {"type": "'", "$1": {"type": "var", "name": "this is literal"}}
+ )"_json);
+ REQUIRE(expr);
+
+ auto result = expr.Evaluate(env, fcts);
+ CHECK(result == Expression::FromJson(R"(
+ {"type": "var", "name": "this is literal"})"_json));
+
+ auto expr_empty = Expression::FromJson(R"({"type": "'"})"_json);
+ REQUIRE(expr_empty);
+ auto result_empty = expr_empty.Evaluate(env, fcts);
+ CHECK(result_empty == Expression::FromJson(R"(null)"_json));
+ }
+
SECTION("if expression") {
auto expr = Expression::FromJson(R"(
{ "type": "if"