Repository: PebbleTemplates/pebble (java)

Issue:
Printing variables starting with `is` or `contains` causes unexpected token OPERATOR
Hello!

One of my colleagues discovered, that if you try to print variable which starts with `is` or `contains` it will result in the following error:

> Unexpected token "OPERATOR" of value "is"

> Unexpected token "OPERATOR" of value "contains"

Examples to reproduce:

```
{{ is_active }}
```
```
{{ contains_value }}
```

Pull request description:
Fix variable name starting with operator
Resolves #518 

Regex checking if operator is part of variable name looks only for letters whereas variable name can also have digits and underscore.

Example of valid variable names that were failing:
- is_active
- is0

Patch:
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/lexer/LexerImpl.java b/pebble/src/main/java/com/mitchellbosecke/pebble/lexer/LexerImpl.java
index f9f8671a..c18dcc0e 100644
--- a/pebble/src/main/java/com/mitchellbosecke/pebble/lexer/LexerImpl.java
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/lexer/LexerImpl.java
@@ -662,7 +662,7 @@ public final class LexerImpl implements Lexer {
        */
       char nextChar = operator.charAt(operator.length() - 1);
       if (Character.isLetter(nextChar) || Character.getType(nextChar) == Character.LETTER_NUMBER) {
-        regex.append("(?![a-zA-Z])");
+        regex.append("(?![a-zA-Z0-9_])");
       }
     }
 


Test patch:
diff --git a/pebble/src/test/java/com/mitchellbosecke/pebble/lexer/LexerImplTest.java b/pebble/src/test/java/com/mitchellbosecke/pebble/lexer/LexerImplTest.java
index decdd53e..001ba79f 100644
--- a/pebble/src/test/java/com/mitchellbosecke/pebble/lexer/LexerImplTest.java
+++ b/pebble/src/test/java/com/mitchellbosecke/pebble/lexer/LexerImplTest.java
@@ -82,6 +82,36 @@ class LexerImplTest {
     assertThat(tokenStream.peek(3).getValue()).isNull();
   }
 
+  /**
+   * Test tokenizing an expression, e.g. {{ expression }}
+   */
+  @Test
+  void testVariableNameStartingWithOperator() {
+    Loader<String> loader = new StringLoader();
+    Reader templateReader = loader.getReader("{{ is_active + contains0 }}");
+
+    TokenStream tokenStream = this.lexer.tokenize(templateReader, this.TEMPLATE_NAME);
+
+    int i = 0;
+    assertThat(tokenStream.peek(i).getType()).isEqualTo(Type.PRINT_START);
+    assertThat(tokenStream.peek(i++).getValue()).isNull();
+
+    assertThat(tokenStream.peek(i).getType()).isEqualTo(Type.NAME);
+    assertThat(tokenStream.peek(i++).getValue()).isEqualTo("is_active");
+
+    assertThat(tokenStream.peek(i).getType()).isEqualTo(Type.OPERATOR);
+    assertThat(tokenStream.peek(i++).getValue()).isEqualTo("+");
+
+    assertThat(tokenStream.peek(i).getType()).isEqualTo(Type.NAME);
+    assertThat(tokenStream.peek(i++).getValue()).isEqualTo("contains0");
+
+    assertThat(tokenStream.peek(i).getType()).isEqualTo(Type.PRINT_END);
+    assertThat(tokenStream.peek(i++).getValue()).isEqualTo("}}");
+
+    assertThat(tokenStream.peek(i).getType()).isEqualTo(Type.EOF);
+    assertThat(tokenStream.peek(i++).getValue()).isNull();
+  }
+
   /**
    * Test tokenizing Punctuation, such as the dot in item.itemType
    */