Skip to content

Commit

Permalink
Expression STRICT_ESCAPES mode
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Sep 23, 2024
1 parent f3eefdd commit 309ad2b
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ static final class Itr {
this.str = str;
}

boolean hasPrev() {
return idx > 0;
}

boolean hasNext() {
return idx < str.length();
}
Expand Down Expand Up @@ -258,6 +262,25 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean
// treat as plain content
continue;
}
if (flags.contains(Flag.STRICT_ESCAPES)) {
if (!itr.hasNext()) {
continue;
} else if (itr.peekNext() == '$') {
list.add(new LiteralNode(itr.getStr(), start, itr.getNextIdx()));
start = itr.getNextIdx();
continue;
} else if (itr.peekNext() != '{') {
continue;
} else if (itr.hasPrev()) {
itr.prev();
if (itr.hasPrev() && itr.peekPrev() == '$') {
itr.next();
start = itr.getNextIdx();
continue;
}
itr.next();
}
}
// check to see if it's a dangling $
if (!itr.hasNext()) {
if (!flags.contains(Flag.LENIENT_SYNTAX)) {
Expand Down Expand Up @@ -614,6 +637,21 @@ private static Node parseString(Itr itr, final boolean allowExpr, final boolean
start = itr.getNextIdx();
continue;
}
} else if (flags.contains(Flag.STRICT_ESCAPES)) {
int escape = itr.getNextIdx();
if (itr.hasNext() && itr.peekNext() == '$') {
itr.next();
if (itr.hasNext() && itr.peekNext() == '{') {
list.add(new LiteralNode(itr.getStr(), start, escape - 1));
list.add(new LiteralNode(itr.getStr(), escape, itr.getNextIdx()));
start = itr.getNextIdx();
} else if (itr.hasNext() && itr.peekNext() == '$') {
list.add(new LiteralNode(itr.getStr(), start, escape));
start = itr.getPrevIdx();
itr.prev();
}
}
continue;
}
// TP 42
// otherwise, just...
Expand Down Expand Up @@ -694,6 +732,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>.
*/
STRICT_ESCAPES,
/**
* 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 @@ -693,4 +693,98 @@ void expressions() {
b.append(c.getExpandedDefault());
}));
}

@Test
void strictEscapes() {
assertEquals("$", Expression.compile("$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("$$", Expression.compile("$$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("\\$", Expression.compile("\\$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("\\$$", Expression.compile("\\$$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("$$foo", Expression.compile("$$foo", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo$$", Expression.compile("foo$$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("$$foo", Expression.compile("$$foo", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo$$bar", Expression.compile("foo$$bar", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("${foo}", Expression.compile("$${foo}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("$${foo}", Expression.compile("$$${foo}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("$${foo}$", Expression.compile("$$${foo}$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("$${foo}$$", Expression.compile("$$${foo}$$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo${bar}", Expression.compile("foo$${bar}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo$${bar}", Expression.compile("foo$$${bar}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo$$$${bar}", Expression.compile("foo$$$$${bar}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo$$$${bar}$$$baz", Expression.compile("foo$$$$${bar}$$$baz", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("foo$$$$", Expression.compile("foo$$$$", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("${foo:bar}", Expression.compile("$${foo:bar}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("$${foo:bar}", Expression.compile("$$${foo:bar}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("${foo:}", Expression.compile("$${foo:${bar}}", STRICT_ESCAPES).evaluate((c, b) -> {
}));
assertEquals("${foo:${bar}}", Expression.compile("$${foo:$${bar}}", STRICT_ESCAPES).evaluate((c, b) -> {
}));

assertEquals("", Expression.compile("${foo}", STRICT_ESCAPES).evaluate((c, b) -> {
assertEquals("foo", c.getKey());
}));
assertEquals("", Expression.compile("${foo}${bar}", STRICT_ESCAPES).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", STRICT_ESCAPES).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", STRICT_ESCAPES).evaluate((c, b) -> {
if ("bar".equals(c.getKey()))
assertEquals("bar", c.getKey());
}));
assertEquals("foo${foo}bar", Expression.compile("foo$${foo${bar}}bar", STRICT_ESCAPES).evaluate((c, b) -> {
if ("bar".equals(c.getKey()))
assertEquals("bar", c.getKey());
}));
assertEquals("", Expression.compile("${}", STRICT_ESCAPES).evaluate((c, b) -> {
assertEquals("", c.getKey());
}));
assertEquals("", Expression.compile("${:}", STRICT_ESCAPES).evaluate((c, b) -> {
assertEquals("", c.getKey());
}));

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

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

0 comments on commit 309ad2b

Please sign in to comment.