From a05a3ff3cf8675d1225f2e6b7cff2988ee80ad69 Mon Sep 17 00:00:00 2001 From: Sam Pullara Date: Tue, 8 Jun 2021 14:58:45 -0700 Subject: [PATCH] ISSUE-266: add a character location for an improperly closed variable --- .../github/mustachejava/MustacheParser.java | 18 ++++++++++++++++-- .../github/mustachejava/InterpreterTest.java | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/compiler/src/main/java/com/github/mustachejava/MustacheParser.java b/compiler/src/main/java/com/github/mustachejava/MustacheParser.java index 9f475c36..f8f4a378 100644 --- a/compiler/src/main/java/com/github/mustachejava/MustacheParser.java +++ b/compiler/src/main/java/com/github/mustachejava/MustacheParser.java @@ -71,8 +71,10 @@ protected Mustache compile(final Reader reader, String tag, final AtomicInteger currentLine.compareAndSet(0, 1); StringBuilder out = new StringBuilder(); try { + int n = 0; int c; while ((c = br.read()) != -1) { + n++; // We remember that we saw a carriage return so we can put it back in later if (c == '\r') { sawCR = true; @@ -90,6 +92,7 @@ protected Mustache compile(final Reader reader, String tag, final AtomicInteger iterable = false; onlywhitespace = true; startOfLine = true; + n = 0; continue; } sawCR = false; @@ -102,13 +105,16 @@ protected Mustache compile(final Reader reader, String tag, final AtomicInteger StringBuilder sb = new StringBuilder(); br.mark(1); c = br.read(); + n++; boolean delimiter = c == '='; if (delimiter) { sb.append((char) c); } else { br.reset(); + n--; } while ((c = br.read()) != -1) { + n++; br.mark(1); if (delimiter) { if (c == '=') { @@ -123,10 +129,12 @@ protected Mustache compile(final Reader reader, String tag, final AtomicInteger if (em.length() > 1) { if (br.read() == em.charAt(1)) { // Matched end + n++; break; } else { // Only one br.reset(); + n--; } } else break; } @@ -197,10 +205,15 @@ protected Mustache compile(final Reader reader, String tag, final AtomicInteger if (specConformWhitespace && startOfLine) { br.mark(2); int ca = br.read(); + n++; if (ca == '\r') { ca = br.read(); + n++; + } + if (ca != '\n') { + n--; + br.reset(); } - if (ca != '\n') br.reset(); } break; } @@ -212,9 +225,10 @@ protected Mustache compile(final Reader reader, String tag, final AtomicInteger name = variable.substring(0, variable.length() - 1); } else { if (br.read() != '}') { + n++; TemplateContext tc = new TemplateContext(sm, em, file, currentLine.get(), startOfLine); throw new MustacheException( - "Improperly closed variable in " + file + ":" + currentLine, tc); + "Improperly closed variable: " + variable + " in " + file + ":" + currentLine + "@" + n, tc); } } mv.value(new TemplateContext(sm, em, file, currentLine.get(), false), name, false); diff --git a/compiler/src/test/java/com/github/mustachejava/InterpreterTest.java b/compiler/src/test/java/com/github/mustachejava/InterpreterTest.java index accc942e..0c9d0420 100644 --- a/compiler/src/test/java/com/github/mustachejava/InterpreterTest.java +++ b/compiler/src/test/java/com/github/mustachejava/InterpreterTest.java @@ -1436,7 +1436,7 @@ public void testImproperlyClosedVariable() throws IOException { new DefaultMustacheFactory().compile(new StringReader("{{{#containers}} {{/containers}}"), "example"); fail("Should have throw MustacheException"); } catch (MustacheException actual) { - assertEquals("Improperly closed variable in example:1 @[example:1]", actual.getMessage()); + assertEquals("Improperly closed variable: #containers in example:1@16 @[example:1]", actual.getMessage()); } }