From 69ff45b7194c44f84701a8f0c565fd4cf4bbe61e Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Thu, 3 Oct 2024 23:53:47 +0100 Subject: [PATCH] Expression MP mode --- .../common/expression/Expression.java | 32 ++++- .../common/expression/ExpressionTestCase.java | 117 ++++++++++++++++++ 2 files changed, 143 insertions(+), 6 deletions(-) diff --git a/expression/src/main/java/io/smallrye/common/expression/Expression.java b/expression/src/main/java/io/smallrye/common/expression/Expression.java index dc3f69c..26acfac 100644 --- a/expression/src/main/java/io/smallrye/common/expression/Expression.java +++ b/expression/src/main/java/io/smallrye/common/expression/Expression.java @@ -413,6 +413,11 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean } else if (flags.contains(Flag.NO_$$)) { list.add(LiteralNode.DOLLAR); itr.prev(); + } else if (flags.contains(Flag.MP)) { + list.add(LiteralNode.DOLLAR); + if (!itr.hasNext() || itr.peekNext() != '{') { + itr.prev(); + } } else { // just resolve $$ to $ // TP 14 @@ -556,7 +561,7 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean //throw Assert.unreachableCode(); } case '\\': { - if (flags.contains(Flag.ESCAPES)) { + if (flags.contains(Flag.ESCAPES) || flags.contains(Flag.MP)) { if (idx > start) { list.add(new LiteralNode(itr.getStr(), start, idx)); start = idx; @@ -570,7 +575,7 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean // TP 34 throw invalidExpressionSyntax(itr.getStr(), idx); } - } else { + } else if (flags.contains(Flag.ESCAPES)) { ch = itr.next(); final LiteralNode node; switch (ch) { @@ -622,6 +627,17 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean list.add(node); start = itr.getNextIdx(); continue; + } else if (flags.contains(Flag.MP)) { + ch = itr.next(); + if (ch == '$') { + if (!itr.hasNext() || itr.peekNext() != '{') { + list.add(LiteralNode.BACKSLASH); + } + } else { + list.add(LiteralNode.BACKSLASH); + } + start = itr.getPrevIdx(); + continue; } } // TP 42 @@ -699,15 +715,19 @@ public enum Flag { */ GENERAL_EXPANSION, /** - * Support standard escape sequences in plain text and default value fields, which begin with a backslash ("{@code \}") - * character. + * Support standard escape sequences in plain text and default value fields, which begin with a backslash + * {@code \} character. */ ESCAPES, /** - * Escaping $ with $$ or /$ only applies when { follows - * the initial escaped $. + * No escape sequence for {@code $} which begin with a dollar {@code $}. */ NO_$$, + /** + * Supports escape sequences for expressions {@code ${}}, which begin with a backslash {@code \} or dollar + * {@code $}. + */ + MP, /** * Treat expressions containing a double-colon delimiter as special, encoding the entire content into the key. */ diff --git a/expression/src/test/java/io/smallrye/common/expression/ExpressionTestCase.java b/expression/src/test/java/io/smallrye/common/expression/ExpressionTestCase.java index 189c449..3e21c58 100644 --- a/expression/src/test/java/io/smallrye/common/expression/ExpressionTestCase.java +++ b/expression/src/test/java/io/smallrye/common/expression/ExpressionTestCase.java @@ -790,6 +790,8 @@ void expressions() { @Test void no$$Escapes() { + assertEquals("$", Expression.compile("\\$", ESCAPES).evaluate((c, b) -> { + })); assertEquals("$", Expression.compile("\\$", NO_$$, ESCAPES).evaluate((c, b) -> { })); assertEquals("${foo}", Expression.compile("\\${foo}", NO_$$, ESCAPES).evaluate((c, b) -> { @@ -809,4 +811,119 @@ void expressions() { assertEquals("bar", c.getKey()); })); } + + @Test + void mp() { + assertThrows(IllegalArgumentException.class, () -> Expression.compile("$", MP).evaluate((c, b) -> { + })); + assertEquals("$", Expression.compile("$", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + + assertThrows(IllegalArgumentException.class, () -> Expression.compile("$$", MP).evaluate((c, b) -> { + })); + assertEquals("$$", Expression.compile("$$", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + + assertEquals("\\$", Expression.compile("\\$", MP).evaluate((c, b) -> { + })); + + assertThrows(IllegalArgumentException.class, () -> Expression.compile("\\$$", MP).evaluate((c, b) -> { + })); + assertEquals("\\$$", Expression.compile("\\$$", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + + assertThrows(IllegalArgumentException.class, () -> Expression.compile("$$foo", MP).evaluate((c, b) -> { + })); + assertEquals("$$foo", Expression.compile("$$foo", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + + assertThrows(IllegalArgumentException.class, () -> Expression.compile("foo$$", MP).evaluate((c, b) -> { + })); + assertEquals("foo$$", Expression.compile("foo$$", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + + assertEquals("foo$$bar", Expression.compile("foo$$bar", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + + assertEquals("${foo}", Expression.compile("$${foo}", MP).evaluate((c, b) -> { + })); + assertEquals("$${foo}", Expression.compile("$$${foo}", MP).evaluate((c, b) -> { + })); + + assertThrows(IllegalArgumentException.class, () -> Expression.compile("$$${foo}$", MP).evaluate((c, b) -> { + })); + assertEquals("$${foo}$", Expression.compile("$$${foo}$", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + assertEquals("$${foo}$$", Expression.compile("$$${foo}$$", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + + assertEquals("foo${bar}", Expression.compile("foo$${bar}", MP).evaluate((c, b) -> { + })); + assertEquals("foo$${bar}", Expression.compile("foo$$${bar}", MP).evaluate((c, b) -> { + })); + assertEquals("foo$$$${bar}", Expression.compile("foo$$$$${bar}", MP).evaluate((c, b) -> { + })); + assertEquals("foo$$$${bar}$$$baz", Expression.compile("foo$$$$${bar}$$$baz", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + assertEquals("foo$$$$", Expression.compile("foo$$$$", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + assertEquals("${foo:bar}", Expression.compile("$${foo:bar}", MP).evaluate((c, b) -> { + })); + assertEquals("$${foo:bar}", Expression.compile("$$${foo:bar}", MP).evaluate((c, b) -> { + })); + assertEquals("${foo:}", Expression.compile("$${foo:${bar}}", MP).evaluate((c, b) -> { + })); + assertEquals("${foo:${bar}}", Expression.compile("$${foo:$${bar}}", MP).evaluate((c, b) -> { + })); + + assertEquals("", Expression.compile("${foo}", MP).evaluate((c, b) -> { + assertEquals("foo", c.getKey()); + })); + assertEquals("", Expression.compile("${foo}${bar}", MP).evaluate((c, b) -> { + if ("foo".equals(c.getKey())) + assertEquals("foo", c.getKey()); + if ("bar".equals(c.getKey())) + assertEquals("bar", c.getKey()); + })); + assertEquals("foobar", Expression.compile("foo${foo}${bar}bar", MP).evaluate((c, b) -> { + if ("foo".equals(c.getKey())) + assertEquals("foo", c.getKey()); + if ("bar".equals(c.getKey())) + assertEquals("bar", c.getKey()); + })); + assertEquals("foo${foo}bar", Expression.compile("foo$${foo}${bar}bar", MP).evaluate((c, b) -> { + if ("bar".equals(c.getKey())) + assertEquals("bar", c.getKey()); + })); + assertEquals("foo${foo}bar", Expression.compile("foo$${foo${bar}}bar", MP).evaluate((c, b) -> { + if ("bar".equals(c.getKey())) + assertEquals("bar", c.getKey()); + })); + assertEquals("", Expression.compile("${}", MP).evaluate((c, b) -> { + assertEquals("", c.getKey()); + })); + assertEquals("", Expression.compile("${:}", MP).evaluate((c, b) -> { + assertEquals("", c.getKey()); + })); + + assertEquals("${foo}", Expression.compile("\\${foo}", MP).evaluate((c, b) -> { + })); + assertEquals("${foo}bar", Expression.compile("\\${foo}bar", MP).evaluate((c, b) -> { + })); + assertEquals("\\$\\{%s}", Expression.compile("\\$\\{%s}", MP).evaluate((c, b) -> { + })); + assertEquals("foo${bar}", Expression.compile("foo\\${bar}", MP).evaluate((c, b) -> { + })); + assertEquals("foo\\\\", Expression.compile("foo\\\\${bar}", MP).evaluate((c, b) -> { + assertEquals("bar", c.getKey()); + })); + + assertEquals("foo\\$", Expression.compile("foo\\$${bar}", MP).evaluate((c, b) -> { + assertEquals("bar", c.getKey()); + })); + assertEquals("foo$${bar}", Expression.compile("foo$\\${bar}", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + assertEquals("foo$$\\{bar}", Expression.compile("foo$$\\{bar}", MP, LENIENT_SYNTAX).evaluate((c, b) -> { + })); + } }