Skip to content

Commit

Permalink
Expression NO_$$ mode (#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez authored Oct 1, 2024
1 parent dbb8aa3 commit 9aff0b4
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean
if (flags.contains(Flag.MINI_EXPRS)) {
// TP 13
list.add(new ExpressionNode(false, LiteralNode.DOLLAR, Node.NULL));
} else if (flags.contains(Flag.NO_$$)) {
list.add(LiteralNode.DOLLAR);
itr.prev();
} else {
// just resolve $$ to $
// TP 14
Expand Down Expand Up @@ -493,10 +496,12 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean
Node.NULL));
start = itr.getNextIdx();
continue;
} else if (flags.contains(Flag.LENIENT_SYNTAX)) {
} else if (flags.contains(Flag.LENIENT_SYNTAX) || flags.contains(Flag.NO_$$)) {
// TP 26
// just treat it as literal
start = itr.getPrevIdx() - 1; // we can use 1 here because unicode '$' is one char in size
list.add(LiteralNode.DOLLAR);
itr.prev();
start = itr.getNextIdx();
continue;
} else {
// TP 27
Expand Down Expand Up @@ -594,6 +599,10 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean
node = LiteralNode.FORM_FEED;
break;
}
case '$': {
node = LiteralNode.DOLLAR;
break;
}
case '\\': {
// TP 45
node = LiteralNode.BACKSLASH;
Expand Down Expand Up @@ -694,6 +703,11 @@ public enum Flag {
* character.
*/
ESCAPES,
/**
* Escaping <code>$</code> with <code>$$</code> or <code>/$</code> only applies when <code>{</code> follows
* the initial escaped <code>$</code>.
*/
NO_$$,
/**
* Treat expressions containing a double-colon delimiter as special, encoding the entire content into the key.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,8 +674,8 @@ void expressions() {
}), "SRCOM01000: Invalid expression syntax at position 0");
assertThrows(IllegalArgumentException.class, () -> Expression.compile("a\\", ESCAPES).evaluate((c, b) -> {
}), "SRCOM01000: Invalid expression syntax at position 0");
assertThrows(IllegalArgumentException.class, () -> Expression.compile("\\${foo}", ESCAPES).evaluate((c, b) -> {
}), "SRCOM01000: Invalid expression syntax at position 0");
assertEquals("${foo}", Expression.compile("\\${foo}", ESCAPES).evaluate((c, b) -> {
}));

// NO_SMART_BRACES
assertEquals("", Expression.compile("${foo}", NO_SMART_BRACES).evaluate((c, b) -> {
Expand All @@ -693,4 +693,120 @@ void expressions() {
b.append(c.getExpandedDefault());
}));
}

@Test
void no$$() {
assertThrows(IllegalArgumentException.class, () -> Expression.compile("$", NO_$$).evaluate((c, b) -> {
}));
assertThrows(IllegalArgumentException.class, () -> Expression.compile("$$", NO_$$).evaluate((c, b) -> {
}));
assertThrows(IllegalArgumentException.class, () -> Expression.compile("\\$", NO_$$).evaluate((c, b) -> {
}));
assertThrows(IllegalArgumentException.class, () -> Expression.compile("\\$$", NO_$$).evaluate((c, b) -> {
}));
assertEquals("$$foo", Expression.compile("$$foo", NO_$$).evaluate((c, b) -> {
}));
assertThrows(IllegalArgumentException.class, () -> Expression.compile("foo$$", NO_$$).evaluate((c, b) -> {
}));
assertEquals("foo$$bar", Expression.compile("foo$$bar", NO_$$).evaluate((c, b) -> {
}));
assertEquals("$", Expression.compile("$${foo}", NO_$$).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("$$", Expression.compile("$$${foo}", NO_$$).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("foo$", Expression.compile("foo$${bar}", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
assertEquals("foo$$", Expression.compile("foo$$${bar}", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
assertEquals("foo$$$$", Expression.compile("foo$$$$${bar}", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
assertEquals("foo$$$$$$$baz", Expression.compile("foo$$$$${bar}$$$baz", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
assertEquals("$", Expression.compile("$${foo:bar}", NO_$$).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("$$", Expression.compile("$$${foo:bar}", NO_$$).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("$", Expression.compile("$${foo:${bar}}", NO_$$).evaluate((c, b) -> {
assertTrue(c.getKey().equals("foo") || c.getKey().equals("bar"));
}));
assertEquals("$", Expression.compile("$${foo:$${bar}}", NO_$$).evaluate((c, b) -> {
assertTrue(c.getKey().equals("foo") || c.getKey().equals("bar"));
}));

assertEquals("", Expression.compile("${foo}", NO_$$).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("", Expression.compile("${foo}${bar}", NO_$$).evaluate((c, b) -> {
assertTrue(c.getKey().equals("foo") || c.getKey().equals("bar"));
}));
assertEquals("foobar", Expression.compile("foo${foo}${bar}bar", NO_$$).evaluate((c, b) -> {
assertTrue(c.getKey().equals("foo") || c.getKey().equals("bar"));
}));
assertEquals("foo$bar", Expression.compile("foo$${foo}${bar}bar", NO_$$).evaluate((c, b) -> {
assertTrue(c.getKey().equals("foo") || c.getKey().equals("bar"));
}));
assertEquals("foo$bar", Expression.compile("foo$${foo${bar}}bar", NO_$$).evaluate((c, b) -> {
assertTrue(c.getKey().equals("foo") || c.getKey().equals("bar"));
}));
assertEquals("", Expression.compile("${}", NO_$$).evaluate((c, b) -> {
assertEquals("", c.getKey());
}));
assertEquals("", Expression.compile("${:}", NO_$$).evaluate((c, b) -> {
assertEquals("", c.getKey());
}));

assertEquals("\\", Expression.compile("\\${foo}", NO_$$).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("\\bar", Expression.compile("\\${foo}bar", NO_$$).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("\\$\\{%s}", Expression.compile("\\$\\{%s}", NO_$$).evaluate((c, b) -> {
}));
assertEquals("foo\\", Expression.compile("foo\\${bar}", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
assertEquals("foo\\\\", Expression.compile("foo\\\\${bar}", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));

assertEquals("foo\\$", Expression.compile("foo\\$${bar}", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
assertEquals("foo$\\", Expression.compile("foo$\\${bar}", NO_$$).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
assertEquals("foo$$\\{bar}", Expression.compile("foo$$\\{bar}", NO_$$).evaluate((c, b) -> {
}));
}

@Test
void no$$Escapes() {
assertEquals("$", Expression.compile("\\$", NO_$$, ESCAPES).evaluate((c, b) -> {
}));
assertEquals("${foo}", Expression.compile("\\${foo}", NO_$$, ESCAPES).evaluate((c, b) -> {
}));

assertEquals("${foo}bar", Expression.compile("\\${foo}bar", NO_$$, ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo${bar}", Expression.compile("foo\\${bar}", NO_$$, ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo\\", Expression.compile("foo\\\\${bar}", NO_$$, ESCAPES).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));

assertEquals("foo$${bar}", Expression.compile("foo$\\${bar}", NO_$$, ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo$${bar}", Expression.compile("foo$\\${bar}", NO_$$, ESCAPES).evaluate((c, b) -> {
assertEquals("bar", c.getKey());
}));
}
}

0 comments on commit 9aff0b4

Please sign in to comment.