diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ConstantExpressionNode.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/ConstantExpressionNode.java
deleted file mode 100644
index e8df21bb69..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ConstantExpressionNode.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-/**
- * A node in the parse tree representing a constant value. Evaluating the node yields the constant
- * value. Instances of this class are used both in expressions, like the {@code 23} in
- * {@code #set ($x = 23)}, and for literal text in templates. In the template...
- *
{@code
- * abc#{if}($x == 5)def#{end}xyz
- * }
- * ...each of the strings {@code abc}, {@code def}, {@code xyz} is represented by an instance of
- * this class that {@linkplain #evaluate evaluates} to that string, and the value {@code 5} is
- * represented by an instance of this class that evaluates to the integer 5.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-class ConstantExpressionNode extends ExpressionNode {
- private final Object value;
-
- ConstantExpressionNode(String resourceName, int lineNumber, Object value) {
- super(resourceName, lineNumber);
- this.value = value;
- }
-
- @Override
- Object evaluate(EvaluationContext context) {
- return value;
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/DirectiveNode.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/DirectiveNode.java
deleted file mode 100644
index e390588064..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/DirectiveNode.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-import com.google.common.base.Verify;
-import com.google.common.collect.ImmutableList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * A node in the parse tree that is a directive such as {@code #set ($x = $y)}
- * or {@code #if ($x) y #end}.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-abstract class DirectiveNode extends Node {
- DirectiveNode(String resourceName, int lineNumber) {
- super(resourceName, lineNumber);
- }
-
- /**
- * A node in the parse tree representing a {@code #set} construct. Evaluating
- * {@code #set ($x = 23)} will set {@code $x} to the value 23. It does not in itself produce
- * any text in the output.
- *
- *
Velocity supports setting values within arrays or collections, with for example
- * {@code $set ($x[$i] = $y)}. That is not currently supported here.
- */
- static class SetNode extends DirectiveNode {
- private final String var;
- private final Node expression;
-
- SetNode(String var, Node expression) {
- super(expression.resourceName, expression.lineNumber);
- this.var = var;
- this.expression = expression;
- }
-
- @Override
- Object evaluate(EvaluationContext context) {
- context.setVar(var, expression.evaluate(context));
- return "";
- }
- }
-
- /**
- * A node in the parse tree representing an {@code #if} construct. All instances of this class
- * have a true subtree and a false subtree. For a plain {@code #if (cond) body
- * #end}, the false subtree will be empty. For {@code #if (cond1) body1 #elseif (cond2) body2
- * #else body3 #end}, the false subtree will contain a nested {@code IfNode}, as if {@code #else
- * #if} had been used instead of {@code #elseif}.
- */
- static class IfNode extends DirectiveNode {
- private final ExpressionNode condition;
- private final Node truePart;
- private final Node falsePart;
-
- IfNode(
- String resourceName,
- int lineNumber,
- ExpressionNode condition,
- Node trueNode,
- Node falseNode) {
- super(resourceName, lineNumber);
- this.condition = condition;
- this.truePart = trueNode;
- this.falsePart = falseNode;
- }
-
- @Override Object evaluate(EvaluationContext context) {
- Node branch = condition.isDefinedAndTrue(context) ? truePart : falsePart;
- return branch.evaluate(context);
- }
- }
-
- /**
- * A node in the parse tree representing a {@code #foreach} construct. While evaluating
- * {@code #foreach ($x in $things)}, {$code $x} will be set to each element of {@code $things} in
- * turn. Once the loop completes, {@code $x} will go back to whatever value it had before, which
- * might be undefined. During loop execution, the variable {@code $foreach} is also defined.
- * Velocity defines a number of properties in this variable, but here we only support
- * {@code $foreach.hasNext}.
- */
- static class ForEachNode extends DirectiveNode {
- private final String var;
- private final ExpressionNode collection;
- private final Node body;
-
- ForEachNode(String resourceName, int lineNumber, String var, ExpressionNode in, Node body) {
- super(resourceName, lineNumber);
- this.var = var;
- this.collection = in;
- this.body = body;
- }
-
- @Override
- Object evaluate(EvaluationContext context) {
- Object collectionValue = collection.evaluate(context);
- Iterable> iterable;
- if (collectionValue instanceof Iterable>) {
- iterable = (Iterable>) collectionValue;
- } else if (collectionValue instanceof Object[]) {
- iterable = Arrays.asList((Object[]) collectionValue);
- } else if (collectionValue instanceof Map, ?>) {
- iterable = ((Map, ?>) collectionValue).values();
- } else {
- throw evaluationException("Not iterable: " + collectionValue);
- }
- Runnable undo = context.setVar(var, null);
- StringBuilder sb = new StringBuilder();
- Iterator> it = iterable.iterator();
- Runnable undoForEach = context.setVar("foreach", new ForEachVar(it));
- while (it.hasNext()) {
- context.setVar(var, it.next());
- sb.append(body.evaluate(context));
- }
- undoForEach.run();
- undo.run();
- return sb.toString();
- }
-
- /**
- * This class is the type of the variable {@code $foreach} that is defined within
- * {@code #foreach} loops. Its {@link #getHasNext()} method means that we can write
- * {@code #if ($foreach.hasNext)}.
- */
- private static class ForEachVar {
- private final Iterator> iterator;
-
- ForEachVar(Iterator> iterator) {
- this.iterator = iterator;
- }
-
- public boolean getHasNext() {
- return iterator.hasNext();
- }
- }
- }
-
- /**
- * A node in the parse tree representing a macro call. If the template contains a definition like
- * {@code #macro (mymacro $x $y) ... #end}, then a call of that macro looks like
- * {@code #mymacro (xvalue yvalue)}. The call is represented by an instance of this class. The
- * definition itself does not appear in the parse tree.
- *
- *
Evaluating a macro involves temporarily setting the parameter variables ({@code $x $y} in
- * the example) to thunks representing the argument expressions, evaluating the macro body, and
- * restoring any previous values that the parameter variables had.
- */
- static class MacroCallNode extends DirectiveNode {
- private final String name;
- private final ImmutableList thunks;
- private Macro macro;
-
- MacroCallNode(
- String resourceName,
- int lineNumber,
- String name,
- ImmutableList argumentNodes) {
- super(resourceName, lineNumber);
- this.name = name;
- this.thunks = argumentNodes;
- }
-
- String name() {
- return name;
- }
-
- int argumentCount() {
- return thunks.size();
- }
-
- void setMacro(Macro macro) {
- this.macro = macro;
- }
-
- @Override
- Object evaluate(EvaluationContext context) {
- Verify.verifyNotNull(macro, "Macro #%s should have been linked", name);
- return macro.evaluate(context, thunks);
- }
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/EvaluationContext.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/EvaluationContext.java
deleted file mode 100644
index 94e80db925..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/EvaluationContext.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * The context of a template evaluation. This consists of the template variables and the template
- * macros. The template variables start with the values supplied by the evaluation call, and can
- * be changed by {@code #set} directives and during the execution of {@code #foreach} and macro
- * calls. The macros are extracted from the template during parsing and never change thereafter.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-interface EvaluationContext {
- Object getVar(String var);
-
- boolean varIsDefined(String var);
-
- /**
- * Sets the given variable to the given value.
- *
- * @return a Runnable that will restore the variable to the value it had before. If the variable
- * was undefined before this method was executed, the Runnable will make it undefined again.
- * This allows us to restore the state of {@code $x} after {@code #foreach ($x in ...)}.
- */
- Runnable setVar(final String var, Object value);
-
- class PlainEvaluationContext implements EvaluationContext {
- private final Map vars;
-
- PlainEvaluationContext(Map vars) {
- this.vars = new TreeMap(vars);
- }
-
- @Override
- public Object getVar(String var) {
- return vars.get(var);
- }
-
- @Override
- public boolean varIsDefined(String var) {
- return vars.containsKey(var);
- }
-
- @Override
- public Runnable setVar(final String var, Object value) {
- Runnable undo;
- if (vars.containsKey(var)) {
- final Object oldValue = vars.get(var);
- undo = () -> vars.put(var, oldValue);
- } else {
- undo = () -> vars.remove(var);
- }
- vars.put(var, value);
- return undo;
- }
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/EvaluationException.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/EvaluationException.java
deleted file mode 100644
index 7edc67412d..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/EvaluationException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-/**
- * An exception that occurred while evaluating a template, such as an undefined variable reference
- * or a division by zero.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-public class EvaluationException extends RuntimeException {
- private static final long serialVersionUID = 1;
-
- EvaluationException(String message) {
- super(message);
- }
-
- EvaluationException(String message, Throwable cause) {
- super(cause);
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ExpressionNode.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/ExpressionNode.java
deleted file mode 100644
index c1112cd5b1..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ExpressionNode.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-import com.google.auto.value.processor.escapevelocity.Parser.Operator;
-
-/**
- * A node in the parse tree representing an expression. Expressions appear inside directives,
- * specifically {@code #set}, {@code #if}, {@code #foreach}, and macro calls. Expressions can
- * also appear inside indices in references, like {@code $x[$i]}.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-abstract class ExpressionNode extends Node {
- ExpressionNode(String resourceName, int lineNumber) {
- super(resourceName, lineNumber);
- }
-
- /**
- * True if evaluating this expression yields a value that is considered true by Velocity's
- *
- * rules. A value is false if it is null or equal to Boolean.FALSE.
- * Every other value is true.
- *
- *
Note that the text at the similar link
- * here
- * states that empty collections and empty strings are also considered false, but that is not
- * true.
- */
- boolean isTrue(EvaluationContext context) {
- Object value = evaluate(context);
- if (value instanceof Boolean) {
- return (Boolean) value;
- } else {
- return value != null;
- }
- }
-
- /**
- * True if this is a defined value and it evaluates to true. This is the same as {@link #isTrue}
- * except that it is allowed for this to be undefined variable, in which it evaluates to false.
- * The method is overridden for plain references so that undefined is the same as false.
- * The reason is to support Velocity's idiom {@code #if ($var)}, where it is not an error
- * if {@code $var} is undefined.
- */
- boolean isDefinedAndTrue(EvaluationContext context) {
- return isTrue(context);
- }
-
- /**
- * The integer result of evaluating this expression.
- *
- * @throws EvaluationException if evaluating the expression produces an exception, or if it
- * yields a value that is not an integer.
- */
- int intValue(EvaluationContext context) {
- Object value = evaluate(context);
- if (!(value instanceof Integer)) {
- throw evaluationException("Arithemtic is only available on integers, not " + show(value));
- }
- return (Integer) value;
- }
-
- /**
- * Returns a string representing the given value, for use in error messages. The string
- * includes both the value's {@code toString()} and its type.
- */
- private static String show(Object value) {
- if (value == null) {
- return "null";
- } else {
- return value + " (a " + value.getClass().getName() + ")";
- }
- }
-
- /**
- * Represents all binary expressions. In {@code #set ($a = $b + $c)}, this will be the type
- * of the node representing {@code $b + $c}.
- */
- static class BinaryExpressionNode extends ExpressionNode {
- final ExpressionNode lhs;
- final Operator op;
- final ExpressionNode rhs;
-
- BinaryExpressionNode(ExpressionNode lhs, Operator op, ExpressionNode rhs) {
- super(lhs.resourceName, lhs.lineNumber);
- this.lhs = lhs;
- this.op = op;
- this.rhs = rhs;
- }
-
- @Override Object evaluate(EvaluationContext context) {
- switch (op) {
- case OR:
- return lhs.isTrue(context) || rhs.isTrue(context);
- case AND:
- return lhs.isTrue(context) && rhs.isTrue(context);
- case EQUAL:
- return equal(context);
- case NOT_EQUAL:
- return !equal(context);
- default: // fall out
- }
- int lhsInt = lhs.intValue(context);
- int rhsInt = rhs.intValue(context);
- switch (op) {
- case LESS:
- return lhsInt < rhsInt;
- case LESS_OR_EQUAL:
- return lhsInt <= rhsInt;
- case GREATER:
- return lhsInt > rhsInt;
- case GREATER_OR_EQUAL:
- return lhsInt >= rhsInt;
- case PLUS:
- return lhsInt + rhsInt;
- case MINUS:
- return lhsInt - rhsInt;
- case TIMES:
- return lhsInt * rhsInt;
- case DIVIDE:
- return lhsInt / rhsInt;
- case REMAINDER:
- return lhsInt % rhsInt;
- default:
- throw new AssertionError(op);
- }
- }
-
- /**
- * Returns true if {@code lhs} and {@code rhs} are equal according to Velocity.
- *
- *
Velocity's definition
- * of equality differs depending on whether the objects being compared are of the same
- * class. If so, equality comes from {@code Object.equals} as you would expect. But if they
- * are not of the same class, they are considered equal if their {@code toString()} values are
- * equal. This means that integer 123 equals long 123L and also string {@code "123"}. It also
- * means that equality isn't always transitive. For example, two StringBuilder objects each
- * containing {@code "123"} will not compare equal, even though the string {@code "123"}
- * compares equal to each of them.
- */
- private boolean equal(EvaluationContext context) {
- Object lhsValue = lhs.evaluate(context);
- Object rhsValue = rhs.evaluate(context);
- if (lhsValue == rhsValue) {
- return true;
- }
- if (lhsValue == null || rhsValue == null) {
- return false;
- }
- if (lhsValue.getClass().equals(rhsValue.getClass())) {
- return lhsValue.equals(rhsValue);
- }
- // Funky equals behaviour specified by Velocity.
- return lhsValue.toString().equals(rhsValue.toString());
- }
- }
-
- /**
- * A node in the parse tree representing an expression like {@code !$a}.
- */
- static class NotExpressionNode extends ExpressionNode {
- private final ExpressionNode expr;
-
- NotExpressionNode(ExpressionNode expr) {
- super(expr.resourceName, expr.lineNumber);
- this.expr = expr;
- }
-
- @Override Object evaluate(EvaluationContext context) {
- return !expr.isTrue(context);
- }
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/Macro.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/Macro.java
deleted file mode 100644
index be65d028f0..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/Macro.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-import com.google.common.base.Verify;
-import com.google.common.collect.ImmutableList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A macro definition. Macros appear in templates using the syntax {@code #macro (m $x $y) ... #end}
- * and each one produces an instance of this class. Evaluating a macro involves setting the
- * parameters (here {$x $y)} and evaluating the macro body. Macro arguments are call-by-name, which
- * means that we need to set each parameter variable to the node in the parse tree that corresponds
- * to it, and arrange for that node to be evaluated when the variable is actually referenced.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-class Macro {
- private final int definitionLineNumber;
- private final String name;
- private final ImmutableList parameterNames;
- private final Node body;
-
- Macro(int definitionLineNumber, String name, List parameterNames, Node body) {
- this.definitionLineNumber = definitionLineNumber;
- this.name = name;
- this.parameterNames = ImmutableList.copyOf(parameterNames);
- this.body = body;
- }
-
- String name() {
- return name;
- }
-
- int parameterCount() {
- return parameterNames.size();
- }
-
- Object evaluate(EvaluationContext context, List thunks) {
- try {
- Verify.verify(thunks.size() == parameterNames.size(), "Argument mistmatch for %s", name);
- Map parameterThunks = new LinkedHashMap<>();
- for (int i = 0; i < parameterNames.size(); i++) {
- parameterThunks.put(parameterNames.get(i), thunks.get(i));
- }
- EvaluationContext newContext = new MacroEvaluationContext(parameterThunks, context);
- return body.evaluate(newContext);
- } catch (EvaluationException e) {
- EvaluationException newException = new EvaluationException(
- "In macro #" + name + " defined on line " + definitionLineNumber + ": " + e.getMessage());
- newException.setStackTrace(e.getStackTrace());
- throw e;
- }
- }
-
- /**
- * The context for evaluation within macros. This wraps an existing {@code EvaluationContext}
- * but intercepts reads of the macro's parameters so that they result in a call-by-name evaluation
- * of whatever was passed as the parameter. For example, if you write...
- *
- * ...then the {@code #mymacro} call will result in {@code $foo.bar(23)} being evaluated twice,
- * once for each time {@code $x} appears. The way this works is that {@code $x} is a thunk.
- * Historically a thunk is a piece of code to evaluate an expression in the context where it
- * occurs, for call-by-name procedures as in Algol 60. Here, it is not exactly a piece of code,
- * but it has the same responsibility.
- */
- static class MacroEvaluationContext implements EvaluationContext {
- private final Map parameterThunks;
- private final EvaluationContext originalEvaluationContext;
-
- MacroEvaluationContext(
- Map parameterThunks, EvaluationContext originalEvaluationContext) {
- this.parameterThunks = parameterThunks;
- this.originalEvaluationContext = originalEvaluationContext;
- }
-
- @Override
- public Object getVar(String var) {
- Node thunk = parameterThunks.get(var);
- if (thunk == null) {
- return originalEvaluationContext.getVar(var);
- } else {
- // Evaluate the thunk in the context where it appeared, not in this context. Otherwise
- // if you pass $x to a parameter called $x you would get an infinite recursion. Likewise
- // if you had #macro(mymacro $x $y) and a call #mymacro($y 23), you would expect that $x
- // would expand to whatever $y meant at the call site, rather than to the value of the $y
- // parameter.
- return thunk.evaluate(originalEvaluationContext);
- }
- }
-
- @Override
- public boolean varIsDefined(String var) {
- return parameterThunks.containsKey(var) || originalEvaluationContext.varIsDefined(var);
- }
-
- @Override
- public Runnable setVar(final String var, Object value) {
- // Copy the behaviour that #set will shadow a macro parameter, even though the Velocity peeps
- // seem to agree that that is not good.
- final Node thunk = parameterThunks.get(var);
- if (thunk == null) {
- return originalEvaluationContext.setVar(var, value);
- } else {
- parameterThunks.remove(var);
- final Runnable originalUndo = originalEvaluationContext.setVar(var, value);
- return () -> {
- originalUndo.run();
- parameterThunks.put(var, thunk);
- };
- }
- }
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/NOTICE b/value/src/main/java/com/google/auto/value/processor/escapevelocity/NOTICE
deleted file mode 100644
index 6d27f8f890..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/NOTICE
+++ /dev/null
@@ -1,6 +0,0 @@
-Apache Velocity
-
-Copyright (C) 2000-2007 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/Node.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/Node.java
deleted file mode 100644
index 5136fbf6de..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/Node.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * A node in the parse tree.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-abstract class Node {
- final String resourceName;
- final int lineNumber;
-
- Node(String resourceName, int lineNumber) {
- this.resourceName = resourceName;
- this.lineNumber = lineNumber;
- }
-
- /**
- * Returns the result of evaluating this node in the given context. This result may be used as
- * part of a further operation, for example evaluating {@code 2 + 3} to 5 in order to set
- * {@code $x} to 5 in {@code #set ($x = 2 + 3)}. Or it may be used directly as part of the
- * template output, for example evaluating replacing {@code name} by {@code Fred} in
- * {@code My name is $name.}.
- */
- abstract Object evaluate(EvaluationContext context);
-
- private String where() {
- String where = "In expression on line " + lineNumber;
- if (resourceName != null) {
- where += " of " + resourceName;
- }
- return where;
- }
-
- EvaluationException evaluationException(String message) {
- return new EvaluationException(where() + ": " + message);
- }
-
- EvaluationException evaluationException(Throwable cause) {
- return new EvaluationException(where() + ": " + cause, cause);
- }
-
- /**
- * Returns an empty node in the parse tree. This is used for example to represent the trivial
- * "else" part of an {@code #if} that does not have an explicit {@code #else}.
- */
- static Node emptyNode(String resourceName, int lineNumber) {
- return new Cons(resourceName, lineNumber, ImmutableList.of());
- }
-
- /**
- * Create a new parse tree node that is the concatenation of the given ones. Evaluating the
- * new node produces the same string as evaluating each of the given nodes and concatenating the
- * result.
- */
- static Node cons(String resourceName, int lineNumber, ImmutableList nodes) {
- return new Cons(resourceName, lineNumber, nodes);
- }
-
- private static final class Cons extends Node {
- private final ImmutableList nodes;
-
- Cons(String resourceName, int lineNumber, ImmutableList nodes) {
- super(resourceName, lineNumber);
- this.nodes = nodes;
- }
-
- @Override Object evaluate(EvaluationContext context) {
- StringBuilder sb = new StringBuilder();
- for (Node node : nodes) {
- sb.append(node.evaluate(context));
- }
- return sb.toString();
- }
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ParseException.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/ParseException.java
deleted file mode 100644
index 45507f05bf..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ParseException.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-/**
- * An exception that occurred while parsing a template.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-public class ParseException extends RuntimeException {
- private static final long serialVersionUID = 1;
-
- ParseException(String message, String resourceName, int lineNumber) {
- super(message + ", " + where(resourceName, lineNumber));
- }
-
- ParseException(String message, String resourceName, int lineNumber, String context) {
- super(message + ", " + where(resourceName, lineNumber) + ", at text starting: " + context);
- }
-
- private static String where(String resourceName, int lineNumber) {
- if (resourceName == null) {
- return "on line " + lineNumber;
- } else {
- return "on line " + lineNumber + " of " + resourceName;
- }
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/Parser.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/Parser.java
deleted file mode 100644
index 73e360b475..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/Parser.java
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-import com.google.auto.value.processor.escapevelocity.DirectiveNode.SetNode;
-import com.google.auto.value.processor.escapevelocity.ExpressionNode.BinaryExpressionNode;
-import com.google.auto.value.processor.escapevelocity.ExpressionNode.NotExpressionNode;
-import com.google.auto.value.processor.escapevelocity.ReferenceNode.IndexReferenceNode;
-import com.google.auto.value.processor.escapevelocity.ReferenceNode.MemberReferenceNode;
-import com.google.auto.value.processor.escapevelocity.ReferenceNode.MethodReferenceNode;
-import com.google.auto.value.processor.escapevelocity.ReferenceNode.PlainReferenceNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.CommentTokenNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.ElseIfTokenNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.ElseTokenNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.EndTokenNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.EofNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.ForEachTokenNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.IfTokenNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.MacroDefinitionTokenNode;
-import com.google.auto.value.processor.escapevelocity.TokenNode.NestedTokenNode;
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Verify;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.primitives.Chars;
-import com.google.common.primitives.Ints;
-import java.io.IOException;
-import java.io.LineNumberReader;
-import java.io.Reader;
-
-/**
- * A parser that reads input from the given {@link Reader} and parses it to produce a
- * {@link Template}.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-class Parser {
- private static final int EOF = -1;
-
- private final LineNumberReader reader;
- private final String resourceName;
- private final Template.ResourceOpener resourceOpener;
-
- /**
- * The invariant of this parser is that {@code c} is always the next character of interest.
- * This means that we almost never have to "unget" a character by reading too far. For example,
- * after we parse an integer, {@code c} will be the first character after the integer, which is
- * exactly the state we will be in when there are no more digits.
- *
- *
Sometimes we need to read two characters ahead, and in that case we use {@link #pushback}.
- */
- private int c;
-
- /**
- * A single character of pushback. If this is not negative, the {@link #next()} method will
- * return it instead of reading a character.
- */
- private int pushback = -1;
-
- Parser(Reader reader, String resourceName, Template.ResourceOpener resourceOpener)
- throws IOException {
- this.reader = new LineNumberReader(reader);
- this.reader.setLineNumber(1);
- next();
- this.resourceName = resourceName;
- this.resourceOpener = resourceOpener;
- }
-
- /**
- * Parse the input completely to produce a {@link Template}.
- *
- *
Parsing happens in two phases. First, we parse a sequence of "tokens", where tokens include
- * entire references such as
- * ${x.foo()[23]}
- *
or entire directives such as
- * #set ($x = $y + $z)
- *
But tokens do not span complex constructs. For example,
The second phase then takes the sequence of tokens and constructs a parse tree out of it.
- * Some nodes in the parse tree will be unchanged from the token sequence, such as the
- * ${x.foo()[23]}
- * #set ($x = $y + $z)
- *
examples above. But a construct such as the {@code #if ... #end} mentioned above will
- * become a single IfNode in the parse tree in the second phase.
- *
- *
The main reason for this approach is that Velocity has two kinds of lexical contexts. At the
- * top level, there can be arbitrary literal text; references like ${x.foo()}; and
- * directives like {@code #if} or {@code #set}. Inside the parentheses of a directive, however,
- * neither arbitrary text nor directives can appear, but expressions can, so we need to tokenize
- * the inside of
- * #if ($x == $a + $b)
- *
as the five tokens "$x", "==", "$a", "+", "$b". Rather than having a classical
- * parser/lexer combination, where the lexer would need to switch between these two modes, we
- * replace the lexer with an ad-hoc parser that is the first phase described above, and we
- * define a simple parser over the resultant tokens that is the second phase.
- */
- Template parse() throws IOException {
- ImmutableList tokens = parseTokens();
- return new Reparser(tokens).reparse();
- }
-
- private ImmutableList parseTokens() throws IOException {
- ImmutableList.Builder tokens = ImmutableList.builder();
- Node token;
- do {
- token = parseNode();
- tokens.add(token);
- } while (!(token instanceof EofNode));
- return tokens.build();
- }
-
- private int lineNumber() {
- return reader.getLineNumber();
- }
-
- /**
- * Gets the next character from the reader and assigns it to {@code c}. If there are no more
- * characters, sets {@code c} to {@link #EOF} if it is not already.
- */
- private void next() throws IOException {
- if (c != EOF) {
- if (pushback < 0) {
- c = reader.read();
- } else {
- c = pushback;
- pushback = -1;
- }
- }
- }
-
- /**
- * Saves the current character {@code c} to be read again, and sets {@code c} to the given
- * {@code c1}. Suppose the text contains {@code xy} and we have just read {@code y}.
- * So {@code c == 'y'}. Now if we execute {@code pushback('x')}, we will have
- * {@code c == 'x'} and the next call to {@link #next()} will set {@code c == 'y'}. Subsequent
- * calls to {@code next()} will continue reading from {@link #reader}. So the pushback
- * essentially puts us back in the state we were in before we read {@code y}.
- */
- private void pushback(int c1) {
- pushback = c;
- c = c1;
- }
-
- /**
- * If {@code c} is a space character, keeps reading until {@code c} is a non-space character or
- * there are no more characters.
- */
- private void skipSpace() throws IOException {
- while (Character.isWhitespace(c)) {
- next();
- }
- }
-
- /**
- * Gets the next character from the reader, and if it is a space character, keeps reading until
- * a non-space character is found.
- */
- private void nextNonSpace() throws IOException {
- next();
- skipSpace();
- }
-
- /**
- * Skips any space in the reader, and then throws an exception if the first non-space character
- * found is not the expected one. Sets {@code c} to the first character after that expected one.
- */
- private void expect(char expected) throws IOException {
- skipSpace();
- if (c == expected) {
- next();
- } else {
- throw parseException("Expected " + expected);
- }
- }
-
- /**
- * Parses a single node from the reader, as part of the first parsing phase.
- *
{@code
- * -> |
- * |
- *
- * }
- */
- private Node parseNode() throws IOException {
- if (c == '#') {
- next();
- switch (c) {
- case '#':
- return parseLineComment();
- case '*':
- return parseBlockComment();
- case '[':
- return parseHashSquare();
- case '{':
- return parseDirective();
- default:
- if (isAsciiLetter(c)) {
- return parseDirective();
- } else {
- // For consistency with Velocity, we treat # not followed by a letter or one of the
- // characters above as a plain character, and we treat #$foo as a literal # followed by
- // the reference $foo.
- return parsePlainText('#');
- }
- }
- }
- if (c == EOF) {
- return new EofNode(resourceName, lineNumber());
- }
- return parseNonDirective();
- }
-
- private Node parseHashSquare() throws IOException {
- // We've just seen #[ which might be the start of a #[[quoted block]]#. If the next character
- // is not another [ then it's not a quoted block, but it *is* a literal #[ followed by whatever
- // that next character is.
- assert c == '[';
- next();
- if (c != '[') {
- return parsePlainText(new StringBuilder("#["));
- }
- int startLine = lineNumber();
- next();
- StringBuilder sb = new StringBuilder();
- while (true) {
- if (c == EOF) {
- throw new ParseException(
- "Unterminated #[[ - did not see matching ]]#", resourceName, startLine);
- }
- if (c == '#') {
- // This might be the last character of ]]# or it might just be a random #.
- int len = sb.length();
- if (len > 1 && sb.charAt(len - 1) == ']' && sb.charAt(len - 2) == ']') {
- next();
- break;
- }
- }
- sb.append((char) c);
- next();
- }
- String quoted = sb.substring(0, sb.length() - 2);
- return new ConstantExpressionNode(resourceName, lineNumber(), quoted);
- }
-
- /**
- * Parses a single non-directive node from the reader.
- *
{@code
- * -> |
- *
- * }
- */
- private Node parseNonDirective() throws IOException {
- if (c == '$') {
- next();
- if (isAsciiLetter(c) || c == '{') {
- return parseReference();
- } else {
- return parsePlainText('$');
- }
- } else {
- int firstChar = c;
- next();
- return parsePlainText(firstChar);
- }
- }
-
- /**
- * Parses a single directive token from the reader. Directives can be spelled with or without
- * braces, for example {@code #if} or {@code #{if}}. We omit the brace spelling in the productions
- * here:
- */
- private Node parseDirective() throws IOException {
- String directive;
- if (c == '{') {
- next();
- directive = parseId("Directive inside #{...}");
- expect('}');
- } else {
- directive = parseId("Directive");
- }
- Node node;
- switch (directive) {
- case "end":
- node = new EndTokenNode(resourceName, lineNumber());
- break;
- case "if":
- case "elseif":
- node = parseIfOrElseIf(directive);
- break;
- case "else":
- node = new ElseTokenNode(resourceName, lineNumber());
- break;
- case "foreach":
- node = parseForEach();
- break;
- case "set":
- node = parseSet();
- break;
- case "parse":
- node = parseParse();
- break;
- case "macro":
- node = parseMacroDefinition();
- break;
- default:
- node = parsePossibleMacroCall(directive);
- }
- // Velocity skips a newline after any directive.
- // TODO(emcmanus): in fact it also skips space before the newline, which should be implemented.
- if (c == '\n') {
- next();
- }
- return node;
- }
-
- /**
- * Parses the condition following {@code #if} or {@code #elseif}.
- *
{@code
- * -> #if ( )
- * -> #elseif ( )
- * }
- *
- * @param directive either {@code "if"} or {@code "elseif"}.
- */
- private Node parseIfOrElseIf(String directive) throws IOException {
- expect('(');
- ExpressionNode condition = parseExpression();
- expect(')');
- return directive.equals("if") ? new IfTokenNode(condition) : new ElseIfTokenNode(condition);
- }
-
- /**
- * Parses a {@code #foreach} token from the reader.
{@code
- * -> #foreach ( $ in )
- * }
- */
- private Node parseForEach() throws IOException {
- expect('(');
- expect('$');
- String var = parseId("For-each variable");
- skipSpace();
- boolean bad = false;
- if (c != 'i') {
- bad = true;
- } else {
- next();
- if (c != 'n') {
- bad = true;
- }
- }
- if (bad) {
- throw parseException("Expected 'in' for #foreach");
- }
- next();
- ExpressionNode collection = parseExpression();
- expect(')');
- return new ForEachTokenNode(var, collection);
- }
-
- /**
- * Parses a {@code #set} token from the reader.
{@code
- * -> #set ( $ = )
- * }
- */
- private Node parseSet() throws IOException {
- expect('(');
- expect('$');
- String var = parseId("#set variable");
- expect('=');
- ExpressionNode expression = parseExpression();
- expect(')');
- return new SetNode(var, expression);
- }
-
- /**
- * Parses a {@code #parse} token from the reader.
{@code
- * -> #parse ( )
- * }
- *
- *
The way this works is inconsistent with Velocity. In Velocity, the {@code #parse} directive
- * is evaluated when it is encountered during template evaluation. That means that the argument
- * can be a variable, and it also means that you can use {@code #if} to choose whether or not
- * to do the {@code #parse}. Neither of those is true in EscapeVelocity. The contents of the
- * {@code #parse} are integrated into the containing template pretty much as if they had been
- * written inline. That also means that EscapeVelocity allows forward references to macros
- * inside {@code #parse} directives, which Velocity does not.
- */
- private Node parseParse() throws IOException {
- expect('(');
- skipSpace();
- if (c != '"') {
- throw parseException("#parse only supported with string literal argument");
- }
- String nestedResourceName = readStringLiteral();
- expect(')');
- try (Reader nestedReader = resourceOpener.openResource(nestedResourceName)) {
- Parser nestedParser = new Parser(nestedReader, nestedResourceName, resourceOpener);
- ImmutableList nestedTokens = nestedParser.parseTokens();
- return new NestedTokenNode(nestedResourceName, nestedTokens);
- }
- }
-
- /**
- * Parses a {@code #macro} token from the reader.
{@code
- * -> #macro ( )
- * -> |
- * $
- * }
- *
- *
Macro parameters are not separated by commas, though method-reference parameters are.
- */
- private Node parseMacroDefinition() throws IOException {
- expect('(');
- skipSpace();
- String name = parseId("Macro name");
- ImmutableList.Builder parameterNames = ImmutableList.builder();
- while (true) {
- skipSpace();
- if (c == ')') {
- next();
- break;
- }
- if (c != '$') {
- throw parseException("Macro parameters should look like $name");
- }
- next();
- parameterNames.add(parseId("Macro parameter name"));
- }
- return new MacroDefinitionTokenNode(resourceName, lineNumber(), name, parameterNames.build());
- }
-
- /**
- * Parses an identifier after {@code #} that is not one of the standard directives. The assumption
- * is that it is a call of a macro that is defined in the template. Macro definitions are
- * extracted from the template during the second parsing phase (and not during evaluation of the
- * template as you might expect). This means that a macro can be called before it is defined.
- *
{@code
- * -> # ( )
- * -> |
- *
- * -> | ,
- * }
- */
- private Node parsePossibleMacroCall(String directive) throws IOException {
- skipSpace();
- if (c != '(') {
- throw parseException("Unrecognized directive #" + directive);
- }
- next();
- ImmutableList.Builder parameterNodes = ImmutableList.builder();
- while (true) {
- skipSpace();
- if (c == ')') {
- next();
- break;
- }
- parameterNodes.add(parsePrimary());
- if (c == ',') {
- // The documentation doesn't say so, but you can apparently have an optional comma in
- // macro calls.
- next();
- }
- }
- return new DirectiveNode.MacroCallNode(
- resourceName, lineNumber(), directive, parameterNodes.build());
- }
-
- /**
- * Parses and discards a line comment, which is {@code ##} followed by any number of characters
- * up to and including the next newline.
- */
- private Node parseLineComment() throws IOException {
- int lineNumber = lineNumber();
- while (c != '\n' && c != EOF) {
- next();
- }
- next();
- return new CommentTokenNode(resourceName, lineNumber);
- }
-
- /**
- * Parses and discards a block comment, which is {@code #*} followed by everything up to and
- * including the next {@code *#}.
- */
- private Node parseBlockComment() throws IOException {
- assert c == '*';
- int startLine = lineNumber();
- int lastC = '\0';
- next();
- while (!(lastC == '*' && c == '#')) {
- if (c == EOF) {
- throw new ParseException(
- "Unterminated #* - did not see matching *#", resourceName, startLine);
- }
- lastC = c;
- next();
- }
- next();
- return new CommentTokenNode(resourceName, startLine);
- }
-
- /**
- * Parses plain text, which is text that contains neither {@code $} nor {@code #}. The given
- * {@code firstChar} is the first character of the plain text, and {@link #c} is the second
- * (if the plain text is more than one character).
- */
- private Node parsePlainText(int firstChar) throws IOException {
- StringBuilder sb = new StringBuilder();
- sb.appendCodePoint(firstChar);
- return parsePlainText(sb);
- }
-
- private Node parsePlainText(StringBuilder sb) throws IOException {
- literal:
- while (true) {
- switch (c) {
- case EOF:
- case '$':
- case '#':
- break literal;
- default:
- // Just some random character.
- }
- sb.appendCodePoint(c);
- next();
- }
- return new ConstantExpressionNode(resourceName, lineNumber(), sb.toString());
- }
-
- /**
- * Parses a reference, which is everything that can start with a {@code $}. References can
- * optionally be enclosed in braces, so {@code $x} and {@code ${x}} are the same. Braces are
- * useful when text after the reference would otherwise be parsed as part of it. For example,
- * {@code ${x}y} is a reference to the variable {@code $x}, followed by the plain text {@code y}.
- * Of course {@code $xy} would be a reference to the variable {@code $xy}.
- *
{@code
- * -> $ |
- * ${}
- * }
- *
- *
On entry to this method, {@link #c} is the character immediately after the {@code $}.
- */
- private Node parseReference() throws IOException {
- if (c == '{') {
- next();
- if (!isAsciiLetter(c)) {
- return parsePlainText(new StringBuilder("${"));
- }
- ReferenceNode node = parseReferenceNoBrace();
- expect('}');
- return node;
- } else {
- return parseReferenceNoBrace();
- }
- }
-
- /**
- * Same as {@link #parseReference()}, except it really must be a reference. A {@code $} in
- * normal text doesn't start a reference if it is not followed by an identifier. But in an
- * expression, for example in {@code #if ($x == 23)}, {@code $} must be followed by an
- * identifier.
- */
- private ReferenceNode parseRequiredReference() throws IOException {
- if (c == '{') {
- next();
- ReferenceNode node = parseReferenceNoBrace();
- expect('}');
- return node;
- } else {
- return parseReferenceNoBrace();
- }
- }
-
- /**
- * Parses a reference, in the simple form without braces.
- *
{@code
- * ->
- * }
- */
- private ReferenceNode parseReferenceNoBrace() throws IOException {
- String id = parseId("Reference");
- ReferenceNode lhs = new PlainReferenceNode(resourceName, lineNumber(), id);
- return parseReferenceSuffix(lhs);
- }
-
- /**
- * Parses the modifiers that can appear at the tail of a reference.
- *
{@code
- * -> |
- * |
- *
- * }
- *
- * @param lhs the reference node representing the first part of the reference
- * {@code $x} in {@code $x.foo} or {@code $x.foo()}, or later {@code $x.y} in {@code $x.y.z}.
- */
- private ReferenceNode parseReferenceSuffix(ReferenceNode lhs) throws IOException {
- switch (c) {
- case '.':
- return parseReferenceMember(lhs);
- case '[':
- return parseReferenceIndex(lhs);
- default:
- return lhs;
- }
- }
-
- /**
- * Parses a reference member, which is either a property reference like {@code $x.y} or a method
- * call like {@code $x.y($z)}.
- *
{@code
- * -> .
- * -> |
- * ( )
- * }
- *
- * @param lhs the reference node representing what appears to the left of the dot, like the
- * {@code $x} in {@code $x.foo} or {@code $x.foo()}.
- */
- private ReferenceNode parseReferenceMember(ReferenceNode lhs) throws IOException {
- assert c == '.';
- next();
- if (!isAsciiLetter(c)) {
- // We've seen something like `$foo.!`, so it turns out it's not a member after all.
- pushback('.');
- return lhs;
- }
- String id = parseId("Member");
- ReferenceNode reference;
- if (c == '(') {
- reference = parseReferenceMethodParams(lhs, id);
- } else {
- reference = new MemberReferenceNode(lhs, id);
- }
- return parseReferenceSuffix(reference);
- }
-
- /**
- * Parses the parameters to a method reference, like {@code $foo.bar($a, $b)}.
- *
{@code
- * -> |
- *
- * -> |
- * ,
- * }
- *
- * @param lhs the reference node representing what appears to the left of the dot, like the
- * {@code $x} in {@code $x.foo()}.
- */
- private ReferenceNode parseReferenceMethodParams(ReferenceNode lhs, String id)
- throws IOException {
- assert c == '(';
- nextNonSpace();
- ImmutableList.Builder args = ImmutableList.builder();
- if (c != ')') {
- args.add(parseExpression());
- while (c == ',') {
- nextNonSpace();
- args.add(parseExpression());
- }
- if (c != ')') {
- throw parseException("Expected )");
- }
- }
- assert c == ')';
- next();
- return new MethodReferenceNode(lhs, id, args.build());
- }
-
- /**
- * Parses an index suffix to a method, like {@code $x[$i]}.
- *
{@code
- * -> [ ]
- * }
- *
- * @param lhs the reference node representing what appears to the left of the dot, like the
- * {@code $x} in {@code $x[$i]}.
- */
- private ReferenceNode parseReferenceIndex(ReferenceNode lhs) throws IOException {
- assert c == '[';
- next();
- ExpressionNode index = parseExpression();
- if (c != ']') {
- throw parseException("Expected ]");
- }
- next();
- ReferenceNode reference = new IndexReferenceNode(lhs, index);
- return parseReferenceSuffix(reference);
- }
-
- enum Operator {
- /**
- * A dummy operator with low precedence. When parsing subexpressions, we always stop when we
- * reach an operator of lower precedence than the "current precedence". For example, when
- * parsing {@code 1 + 2 * 3 + 4}, we'll stop parsing the subexpression {@code * 3 + 4} when
- * we reach the {@code +} because it has lower precedence than {@code *}. This dummy operator,
- * then, behaves like {@code +} when the minimum precedence is {@code *}. We also return it
- * if we're looking for an operator and don't find one. If this operator is {@code ⊙}, it's as
- * if our expressions are bracketed with it, like {@code ⊙ 1 + 2 * 3 + 4 ⊙}.
- */
- STOP("", 0),
-
- // If a one-character operator is a prefix of a two-character operator, like < and <=, then
- // the one-character operator must come first.
- OR("||", 1),
- AND("&&", 2),
- EQUAL("==", 3), NOT_EQUAL("!=", 3),
- LESS("<", 4), LESS_OR_EQUAL("<=", 4), GREATER(">", 4), GREATER_OR_EQUAL(">=", 4),
- PLUS("+", 5), MINUS("-", 5),
- TIMES("*", 6), DIVIDE("/", 6), REMAINDER("%", 6);
-
- final String symbol;
- final int precedence;
-
- Operator(String symbol, int precedence) {
- this.symbol = symbol;
- this.precedence = precedence;
- }
-
- @Override
- public String toString() {
- return symbol;
- }
- }
-
- /**
- * Maps a code point to the operators that begin with that code point. For example, maps
- * {@code <} to {@code LESS} and {@code LESS_OR_EQUAL}.
- */
- private static final ImmutableListMultimap CODE_POINT_TO_OPERATORS;
- static {
- ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder();
- for (Operator operator : Operator.values()) {
- if (operator != Operator.STOP) {
- builder.put((int) operator.symbol.charAt(0), operator);
- }
- }
- CODE_POINT_TO_OPERATORS = builder.build();
- }
-
- /**
- * Parses an expression, which can occur within a directive like {@code #if} or {@code #set},
- * or within a reference like {@code $x[$a + $b]} or {@code $x.m($a + $b)}.
- *
- */
- private ExpressionNode parseExpression() throws IOException {
- ExpressionNode lhs = parseUnaryExpression();
- return new OperatorParser().parse(lhs, 1);
- }
-
- /**
- * An operator-precedence parser for the binary operations we understand. It implements an
- * algorithm from Wikipedia
- * that uses recursion rather than having an explicit stack of operators and values.
- */
- private class OperatorParser {
- /**
- * The operator we have just scanned, in the same way that {@link #c} is the character we have
- * just read. If we were not able to scan an operator, this will be {@link Operator#STOP}.
- */
- private Operator currentOperator;
-
- OperatorParser() throws IOException {
- nextOperator();
- }
-
- /**
- * Parse a subexpression whose left-hand side is {@code lhs} and where we only consider
- * operators with precedence at least {@code minPrecedence}.
- *
- * @return the parsed subexpression
- */
- ExpressionNode parse(ExpressionNode lhs, int minPrecedence) throws IOException {
- while (currentOperator.precedence >= minPrecedence) {
- Operator operator = currentOperator;
- ExpressionNode rhs = parseUnaryExpression();
- nextOperator();
- while (currentOperator.precedence > operator.precedence) {
- rhs = parse(rhs, currentOperator.precedence);
- }
- lhs = new BinaryExpressionNode(lhs, operator, rhs);
- }
- return lhs;
- }
-
- /**
- * Updates {@link #currentOperator} to be an operator read from the input,
- * or {@link Operator#STOP} if there is none.
- */
- private void nextOperator() throws IOException {
- skipSpace();
- ImmutableList possibleOperators = CODE_POINT_TO_OPERATORS.get(c);
- if (possibleOperators.isEmpty()) {
- currentOperator = Operator.STOP;
- return;
- }
- char firstChar = Chars.checkedCast(c);
- next();
- Operator operator = null;
- for (Operator possibleOperator : possibleOperators) {
- if (possibleOperator.symbol.length() == 1) {
- Verify.verify(operator == null);
- operator = possibleOperator;
- } else if (possibleOperator.symbol.charAt(1) == c) {
- next();
- operator = possibleOperator;
- }
- }
- if (operator == null) {
- throw parseException(
- "Expected " + Iterables.getOnlyElement(possibleOperators) + ", not just " + firstChar);
- }
- currentOperator = operator;
- }
- }
-
- /**
- * Parses an expression not containing any operators (except inside parentheses).
- *
- */
- private ExpressionNode parsePrimary() throws IOException {
- ExpressionNode node;
- if (c == '$') {
- next();
- node = parseRequiredReference();
- } else if (c == '"') {
- node = parseStringLiteral();
- } else if (c == '-') {
- // Velocity does not have a negation operator. If we see '-' it must be the start of a
- // negative integer literal.
- next();
- node = parseIntLiteral("-");
- } else if (isAsciiDigit(c)) {
- node = parseIntLiteral("");
- } else if (isAsciiLetter(c)) {
- node = parseBooleanLiteral();
- } else {
- throw parseException("Expected an expression");
- }
- skipSpace();
- return node;
- }
-
- private ExpressionNode parseStringLiteral() throws IOException {
- return new ConstantExpressionNode(resourceName, lineNumber(), readStringLiteral());
- }
-
- private String readStringLiteral() throws IOException {
- assert c == '"';
- StringBuilder sb = new StringBuilder();
- next();
- while (c != '"') {
- if (c == '\n' || c == EOF) {
- throw parseException("Unterminated string constant");
- }
- if (c == '$' || c == '\\') {
- // In real Velocity, you can have a $ reference expanded inside a "" string literal.
- // There are also '' string literals where that is not so. We haven't needed that yet
- // so it's not supported.
- throw parseException(
- "Escapes or references in string constants are not currently supported");
- }
- sb.appendCodePoint(c);
- next();
- }
- next();
- return sb.toString();
- }
-
- private ExpressionNode parseIntLiteral(String prefix) throws IOException {
- StringBuilder sb = new StringBuilder(prefix);
- while (isAsciiDigit(c)) {
- sb.appendCodePoint(c);
- next();
- }
- Integer value = Ints.tryParse(sb.toString());
- if (value == null) {
- throw parseException("Invalid integer: " + sb);
- }
- return new ConstantExpressionNode(resourceName, lineNumber(), value);
- }
-
- /**
- * Parses a boolean literal, either {@code true} or {@code false}.
- * -> true |
- * false
- */
- private ExpressionNode parseBooleanLiteral() throws IOException {
- String s = parseId("Identifier without $");
- boolean value;
- if (s.equals("true")) {
- value = true;
- } else if (s.equals("false")) {
- value = false;
- } else {
- throw parseException("Identifier in expression must be preceded by $ or be true or false");
- }
- return new ConstantExpressionNode(resourceName, lineNumber(), value);
- }
-
- private static final CharMatcher ASCII_LETTER =
- CharMatcher.inRange('A', 'Z')
- .or(CharMatcher.inRange('a', 'z'))
- .precomputed();
-
- private static final CharMatcher ASCII_DIGIT =
- CharMatcher.inRange('0', '9')
- .precomputed();
-
- private static final CharMatcher ID_CHAR =
- ASCII_LETTER
- .or(ASCII_DIGIT)
- .or(CharMatcher.anyOf("-_"))
- .precomputed();
-
- private static boolean isAsciiLetter(int c) {
- return (char) c == c && ASCII_LETTER.matches((char) c);
- }
-
- private static boolean isAsciiDigit(int c) {
- return (char) c == c && ASCII_DIGIT.matches((char) c);
- }
-
- private static boolean isIdChar(int c) {
- return (char) c == c && ID_CHAR.matches((char) c);
- }
-
- /**
- * Parse an identifier as specified by the
- * VTL
- * . Identifiers are ASCII: starts with a letter, then letters, digits, {@code -} and
- * {@code _}.
- */
- private String parseId(String what) throws IOException {
- if (!isAsciiLetter(c)) {
- throw parseException(what + " should start with an ASCII letter");
- }
- StringBuilder id = new StringBuilder();
- while (isIdChar(c)) {
- id.appendCodePoint(c);
- next();
- }
- return id.toString();
- }
-
- /**
- * Returns an exception to be thrown describing a parse error with the given message, and
- * including information about where it occurred.
- */
- private ParseException parseException(String message) throws IOException {
- StringBuilder context = new StringBuilder();
- if (c == EOF) {
- context.append("EOF");
- } else {
- int count = 0;
- while (c != EOF && count < 20) {
- context.appendCodePoint(c);
- next();
- count++;
- }
- if (c != EOF) {
- context.append("...");
- }
- }
- return new ParseException(message, resourceName, lineNumber(), context.toString());
- }
-}
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/README.md b/value/src/main/java/com/google/auto/value/processor/escapevelocity/README.md
deleted file mode 100644
index 9882aea879..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/README.md
+++ /dev/null
@@ -1,377 +0,0 @@
-# EscapeVelocity summary
-
-EscapeVelocity is a templating engine that can be used from Java. It is a reimplementation of a subset of
-functionality from [Apache Velocity](http://velocity.apache.org/).
-
-For a fuller explanation of Velocity's functioning, see its
-[User Guide](http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html)
-
-If EscapeVelocity successfully produces a result from a template evaluation, that result should be
-the exact same string that Velocity produces. If not, that is a bug.
-
-EscapeVelocity has no facilities for HTML escaping and it is not appropriate for producing
-HTML output that might include portions of untrusted input.
-
-
-## Motivation
-
-Velocity has a convenient templating language. It is easy to read, and it has widespread support
-from tools such as editors and coding websites. However, *using* Velocity can prove difficult.
-Its use to generate Java code in the [AutoValue][AutoValue] annotation processor required many
-[workarounds][VelocityHacks]. The way it dynamically loads classes as part of its standard operation
-makes it hard to [shade](https://maven.apache.org/plugins/maven-shade-plugin/) it, which in the case
-of AutoValue led to interference if Velocity was used elsewhere in a project.
-
-EscapeVelocity has a simple API that does not involve any class-loading or other sources of
-problems. It and its dependencies can be shaded with no difficulty.
-
-## Loading a template
-
-The entry point for EscapeVelocity is the `Template` class. To obtain an instance, use
-`Template.from(Reader)`. If a template is stored in a file, that file conventionally has the
-suffix `.vm` (for Velocity Macros). But since the argument is a `Reader`, you can also load
-a template directly from a Java string, using `StringReader`.
-
-Here's how you might make a `Template` instance from a template file that is packaged as a resource
-in the same package as the calling class:
-
-```java
-InputStream in = getClass().getResourceAsStream("foo.vm");
-if (in == null) {
- throw new IllegalArgumentException("Could not find resource foo.vm");
-}
-Reader reader = new BufferedReader(new InputStreamReader(in));
-Template template = Template.parseFrom(reader);
-```
-
-## Expanding a template
-
-Once you have a `Template` object, you can use it to produce a string where the variables in the
-template are given the values you provide. You can do this any number of times, specifying the
-same or different values each time.
-
-Suppose you have this template:
-
-```
-The $language word for $original is $translated.
-```
-
-You might write this code:
-
-```java
-Map vars = new HashMap<>();
-vars.put("language", "French");
-vars.put("original", "toe");
-vars.put("translated", "orteil");
-String result = template.evaluate(vars);
-```
-
-The `result` string would then be: `The French word for toe is orteil.`
-
-## Comments
-
-The characters `##` introduce a comment. Characters from `##` up to and including the following
-newline are omitted from the template. This template has comments:
-
-```
-Line 1 ## with a comment
-Line 2
-```
-
-It is the same as this template:
-```
-Line 1 Line 2
-```
-
-## References
-
-EscapeVelocity supports most of the reference types described in the
-[Velocity User Guide](http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html#References)
-
-### Variables
-
-A variable has an ASCII name that starts with a letter (a-z or A-Z) and where any other characters
-are also letters or digits or hyphens (-) or underscores (_). A variable reference can be written
-as `$foo` or as `${foo}`. The value of a variable can be of any Java type. If the value `v` of
-variable `foo` is not a String then the result of `$foo` in a template will be `String.valueOf(v)`.
-Variables must be defined before they are referenced; otherwise an `EvaluationException` will be
-thrown.
-
-Variable names are case-sensitive: `$foo` is not the same variable as `$Foo` or `$FOO`.
-
-Initially the values of variables come from the Map that is passed to `Template.evaluate`. Those
-values can be changed, and new ones defined, using the `#set` directive in the template:
-
-```
-#set ($foo = "bar")
-```
-
-Setting a variable affects later references to it in the template, but has no effect on the
-`Map` that was passed in or on later template evaluations.
-
-### Properties
-
-If a reference looks like `$purchase.Total` then the value of the `$purchase` variable must be a
-Java object that has a public method `getTotal()` or `gettotal()`, or a method called `isTotal()` or
-`istotal()` that returns `boolean`. The result of `$purchase.Total` is then the result of calling
-that method on the `$purchase` object.
-
-If you want to have a period (`.`) after a variable reference *without* it being a property
-reference, you can use braces like this: `${purchase}.Total`. If, after a property reference, you
-have a further period, you can put braces around the reference like this:
-`${purchase.Total}.nonProperty`.
-
-### Methods
-
-If a reference looks like `$purchase.addItem("scones", 23)` then the value of the `$purchase`
-variable must be a Java object that has a public method `addItem` with two parameters that match
-the given values. Unlike Velocity, EscapeVelocity requires that there be exactly one such method.
-It is OK if there are other `addItem` methods provided they are not compatible with the
-arguments provided.
-
-Properties are in fact a special case of methods: instead of writing `$purchase.Total` you could
-write `$purchase.getTotal()`. Braces can be used to make the method invocation explicit
-(`${purchase.getTotal()}`) or to prevent method invocation (`${purchase}.getTotal()`).
-
-### Indexing
-
-If a reference looks like `$indexme[$i]` then the value of the `$indexme` variable must be a Java
-object that has a public `get` method that takes one argument that is compatible with the index.
-For example, `$indexme` might be a `List` and `$i` might be an integer. Then the reference would
-be the result of `List.get(int)` for that list and that integer. Or, `$indexme` might be a `Map`,
-and the reference would be the result of `Map.get(Object)` for the object `$i`. In general,
-`$indexme[$i]` is equivalent to `$indexme.get($i)`.
-
-Unlike Velocity, EscapeVelocity does not allow `$indexme` to be a Java array.
-
-### Undefined references
-
-If a variable has not been given a value, either by being in the initial Map argument or by being
-set in the template, then referencing it will provoke an `EvaluationException`. There is
-a special case for `#if`: if you write `#if ($var)` then it is allowed for `$var` not to be defined,
-and it is treated as false.
-
-### Setting properties and indexes: not supported
-
-Unlke Velocity, EscapeVelocity does not allow `#set` assignments with properties or indexes:
-
-```
-#set ($data.User = "jon") ## Allowed in Velocity but not in EscapeVelocity
-#set ($map["apple"] = "orange") ## Allowed in Velocity but not in EscapeVelocity
-```
-
-## Expressions
-
-In certain contexts, such as the `#set` directive we have just seen or certain other directives,
-EscapeVelocity can evaluate expressions. An expression can be any of these:
-
-* A reference, of the kind we have just seen. The value is the value of the reference.
-* A string literal enclosed in double quotes, like `"this"`. A string literal must appear on
- one line. EscapeVelocity does not support the characters `$` or `\\` in a string literal.
-* An integer literal such as `23` or `-100`. EscapeVelocity does not support floating-point
- literals.
-* A Boolean literal, `true` or `false`.
-* Simpler expressions joined together with operators that have the same meaning as in Java:
- `!`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `&&`, `||`, `+`, `-`, `*`, `/`, `%`. The operators have the
- same precedence as in Java.
-* A simpler expression in parentheses, for example `(2 + 3)`.
-
-Velocity supports string literals with single quotes, like `'this`' and also references within
-strings, like `"a $reference in a string"`, but EscapeVelocity does not.
-
-## Directives
-
-A directive is introduced by a `#` character followed by a word. We have already seen the `#set`
-directive, which sets the value of a variable. The other directives are listed below.
-
-Directives can be spelled with or without braces, so `#set` or `#{set}`.
-
-### `#if`/`#elseif`/`#else`
-
-The `#if` directive selects parts of the template according as a condition is true or false.
-The simplest case looks like this:
-
-```
-#if ($condition) yes #end
-```
-
-This evaluates to the string ` yes ` if the variable `$condition` is defined and has a true value,
-and to the empty string otherwise. It is allowed for `$condition` not to be defined in this case,
-and then it is treated as false.
-
-The expression in `#if` (here `$condition`) is considered true if its value is not null and not
-equal to the Boolean value `false`.
-
-An `#if` directive can also have an `#else` part, for example:
-
-```
-#if ($condition) yes #else no #end
-```
-
-This evaluates to the string ` yes ` if the condition is true or the string ` no ` if it is not.
-
-An `#if` directive can have any number of `#elseif` parts. For example:
-
-```
-#if ($i == 0) zero #elseif ($i == 1) one #elseif ($i == 2) two #else many #end
-```
-
-### `#foreach`
-
-The `#foreach` directive repeats a part of the template once for each value in a list.
-
-```
-#foreach ($product in $allProducts)
- ${product}!
-#end
-```
-
-This will produce one line for each value in the `$allProducts` variable. The value of
-`$allProducts` can be a Java `Iterable`, such as a `List` or `Set`; or it can be an object array;
-or it can be a Java `Map`. When it is a `Map` the `#foreach` directive loops over every *value*
-in the `Map`.
-
-If `$allProducts` is a `List` containing the strings `oranges` and `lemons` then the result of the
-`#foreach` would be this:
-
-```
-
- oranges!
-
-
- lemons!
-
-```
-
-When the `#foreach` completes, the loop variable (`$product` in the example) goes back to whatever
-value it had before, or to being undefined if it was undefined before.
-
-Within the `#foreach`, a special variable `$foreach` is defined, such that you can write
-`$foreach.hasNext`, which will be true if there are more values after this one or false if this
-is the last value. For example:
-
-```
-#foreach ($product in $allProducts)${product}#if ($foreach.hasNext), #end#end
-```
-
-This would produce the output `oranges, lemons` for the list above. (The example is scrunched up
-to avoid introducing extraneous spaces, as described in the [section](#spaces) on spaces
-below.)
-
-Velocity gives the `$foreach` variable other properties (`index` and `count`) but EscapeVelocity
-does not.
-
-### Macros
-
-A macro is a part of the template that can be reused in more than one place, potentially with
-different parameters each time. In the simplest case, a macro has no arguments:
-
-```
-#macro (hello) bonjour #end
-```
-
-Then the macro can be referenced by writing `#hello()` and the result will be the string ` bonjour `
-inserted at that point.
-
-Macros can also have parameters:
-
-```
-#macro (greet $hello $world) $hello, $world! #end
-```
-
-Then `#greet("bonjour", "monde")` would produce ` bonjour, monde! `. The comma is optional, so
-you could also write `#greet("bonjour" "monde")`.
-
-When a macro completes, the parameters (`$hello` and `$world` in the example) go back to whatever
-values they had before, or to being undefined if they were undefined before.
-
-All macro definitions take effect before the template is evaluated, so you can use a macro at a
-point in the template that is before the point where it is defined. This also means that you can't
-define a macro conditionally:
-
-```
-## This doesn't work!
-#if ($language == "French")
-#macro (hello) bonjour #end
-#else
-#macro (hello) hello #end
-#end
-```
-
-There is no particular reason to define the same macro more than once, but if you do it is the
-first definition that is retained. In the `#if` example just above, the `bonjour` version will
-always be used.
-
-Macros can make templates hard to understand. You may prefer to put the logic in a Java method
-rather than a macro, and call the method from the template using `$methods.doSomething("foo")`
-or whatever.
-
-## Block quoting
-
-If you have text that should be treated verbatim, you can enclose it in `#[[...]]#`. The text
-represented by `...` will be copied into the output. `#` and `$` characters will have no
-effect in that text.
-
-```
-#[[ This is not a #directive, and this is not a $variable. ]]#
-```
-
-## Including other templates
-
-If you want to include a template from another file, you can use the `#parse` directive.
-This can be useful if you have macros that are shared between templates, for example.
-
-```
-#set ($foo = "bar")
-#parse("macros.vm")
-#mymacro($foo) ## #mymacro defined in macros.vm
-```
-
-For this to work, you will need to tell EscapeVelocity how to find "resources" such as
-`macro.vm` in the example. You might use something like this:
-
-```
-ResourceOpener resourceOpener = resourceName -> {
- InputStream inputStream = getClass().getResource(resourceName);
- if (inputStream == null) {
- throw new IOException("Unknown resource: " + resourceName);
- }
- return new BufferedReader(InputStreamReader(inputStream, StandardCharsets.UTF_8));
-};
-Template template = Template.parseFrom("foo.vm", resourceOpener);
-```
-
-In this case, the `resourceOpener` is used to find the main template `foo.vm`, as well as any
-templates it may reference in `#parse` directives.
-
-## Spaces
-
-For the most part, spaces and newlines in the template are preserved exactly in the output.
-To avoid unwanted newlines, you may end up using `##` comments. In the `#foreach` example above
-we had this:
-
-```
-#foreach ($product in $allProducts)${product}#if ($foreach.hasNext), #end#end
-```
-
-That was to avoid introducing unwanted spaces and newlines. A more readable way to achieve the same
-result is this:
-
-```
-#foreach ($product in $allProducts)##
-${product}##
-#if ($foreach.hasNext), #end##
-#end
-```
-
-Spaces are ignored between the `#` of a directive and the `)` that closes it, so there is no trace
-in the output of the spaces in `#foreach ($product in $allProducts)` or `#if ($foreach.hasNext)`.
-Spaces are also ignored inside references, such as `$indexme[ $i ]` or `$callme( $i , $j )`.
-
-If you are concerned about the detailed formatting of the text from the template, you may want to
-post-process it. For example, if it is Java code, you could use a formatter such as
-[google-java-format](https://github.com/google/google-java-format). Then you shouldn't have to
-worry about extraneous spaces.
-
-[VelocityHacks]: https://github.com/google/auto/blob/ca2384d5ad15a0c761b940384083cf5c50c6e839/value/src/main/java/com/google/auto/value/processor/TemplateVars.java#L54
-[AutoValue]: https://github.com/google/auto/tree/master/value
diff --git a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ReferenceNode.java b/value/src/main/java/com/google/auto/value/processor/escapevelocity/ReferenceNode.java
deleted file mode 100644
index 4f56140c27..0000000000
--- a/value/src/main/java/com/google/auto/value/processor/escapevelocity/ReferenceNode.java
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2015 Google, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package com.google.auto.value.processor.escapevelocity;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.primitives.Primitives;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A node in the parse tree that is a reference. A reference is anything beginning with {@code $},
- * such as {@code $x} or {@code $x[$i].foo($j)}.
- *
- * @author emcmanus@google.com (Éamonn McManus)
- */
-abstract class ReferenceNode extends ExpressionNode {
- ReferenceNode(String resourceName, int lineNumber) {
- super(resourceName, lineNumber);
- }
-
- /**
- * A node in the parse tree that is a plain reference such as {@code $x}. This node may appear
- * inside a more complex reference like {@code $x.foo}.
- */
- static class PlainReferenceNode extends ReferenceNode {
- final String id;
-
- PlainReferenceNode(String resourceName, int lineNumber, String id) {
- super(resourceName, lineNumber);
- this.id = id;
- }
-
- @Override Object evaluate(EvaluationContext context) {
- if (context.varIsDefined(id)) {
- return context.getVar(id);
- } else {
- throw evaluationException("Undefined reference $" + id);
- }
- }
-
- @Override
- boolean isDefinedAndTrue(EvaluationContext context) {
- if (context.varIsDefined(id)) {
- return isTrue(context);
- } else {
- return false;
- }
- }
- }
-
- /**
- * A node in the parse tree that is a reference to a property of another reference, like
- * {@code $x.foo} or {@code $x[$i].foo}.
- */
- static class MemberReferenceNode extends ReferenceNode {
- final ReferenceNode lhs;
- final String id;
-
- MemberReferenceNode(ReferenceNode lhs, String id) {
- super(lhs.resourceName, lhs.lineNumber);
- this.lhs = lhs;
- this.id = id;
- }
-
- private static final String[] PREFIXES = {"get", "is"};
- private static final boolean[] CHANGE_CASE = {false, true};
-
- @Override Object evaluate(EvaluationContext context) {
- Object lhsValue = lhs.evaluate(context);
- if (lhsValue == null) {
- throw evaluationException("Cannot get member " + id + " of null value");
- }
- // Velocity specifies that, given a reference .foo, it will first look for getfoo() and then
- // for getFoo(), and likewise given .Foo it will look for getFoo() and then getfoo().
- for (String prefix : PREFIXES) {
- for (boolean changeCase : CHANGE_CASE) {
- String baseId = changeCase ? changeInitialCase(id) : id;
- String methodName = prefix + baseId;
- Method method;
- try {
- method = lhsValue.getClass().getMethod(methodName);
- if (!prefix.equals("is") || method.getReturnType().equals(boolean.class)) {
- // Don't consider methods that happen to be called isFoo() but don't return boolean.
- return invokeMethod(method, lhsValue, ImmutableList.of());
- }
- } catch (NoSuchMethodException e) {
- // Continue with next possibility
- }
- }
- }
- throw evaluationException(
- "Member " + id + " does not correspond to a public getter of " + lhsValue
- + ", a " + lhsValue.getClass().getName());
- }
-
- private static String changeInitialCase(String id) {
- int initial = id.codePointAt(0);
- String rest = id.substring(Character.charCount(initial));
- if (Character.isUpperCase(initial)) {
- initial = Character.toLowerCase(initial);
- } else if (Character.isLowerCase(initial)) {
- initial = Character.toUpperCase(initial);
- }
- return new StringBuilder().appendCodePoint(initial).append(rest).toString();
- }
- }
-
- /**
- * A node in the parse tree that is an indexing of a reference, like {@code $x[0]} or
- * {@code $x.foo[$i]}. Indexing is array indexing or calling the {@code get} method of a list
- * or a map.
- */
- static class IndexReferenceNode extends ReferenceNode {
- final ReferenceNode lhs;
- final ExpressionNode index;
-
- IndexReferenceNode(ReferenceNode lhs, ExpressionNode index) {
- super(lhs.resourceName, lhs.lineNumber);
- this.lhs = lhs;
- this.index = index;
- }
-
- @Override Object evaluate(EvaluationContext context) {
- Object lhsValue = lhs.evaluate(context);
- if (lhsValue == null) {
- throw evaluationException("Cannot index null value");
- }
- if (lhsValue instanceof List>) {
- Object indexValue = index.evaluate(context);
- if (!(indexValue instanceof Integer)) {
- throw evaluationException("List index is not an integer: " + indexValue);
- }
- List> lhsList = (List>) lhsValue;
- int i = (Integer) indexValue;
- if (i < 0 || i >= lhsList.size()) {
- throw evaluationException(
- "List index " + i + " is not valid for list of size " + lhsList.size());
- }
- return lhsList.get(i);
- } else if (lhsValue instanceof Map, ?>) {
- Object indexValue = index.evaluate(context);
- Map, ?> lhsMap = (Map, ?>) lhsValue;
- return lhsMap.get(indexValue);
- } else {
- // In general, $x[$y] is equivalent to $x.get($y). We've covered the most common cases
- // above, but for other cases like Multimap we resort to evaluating the equivalent form.
- MethodReferenceNode node = new MethodReferenceNode(lhs, "get", ImmutableList.of(index));
- return node.evaluate(context);
- }
- }
- }
-
- /**
- * A node in the parse tree representing a method reference, like {@code $list.size()}.
- */
- static class MethodReferenceNode extends ReferenceNode {
- final ReferenceNode lhs;
- final String id;
- final List args;
-
- MethodReferenceNode(ReferenceNode lhs, String id, List args) {
- super(lhs.resourceName, lhs.lineNumber);
- this.lhs = lhs;
- this.id = id;
- this.args = args;
- }
-
- /**
- * {@inheritDoc}
- *
- *
Evaluating a method expression such as {@code $x.foo($y)} involves looking at the actual
- * types of {@code $x} and {@code $y}. The type of {@code $x} must have a public method
- * {@code foo} with a parameter type that is compatible with {@code $y}.
- *
- *
Currently we don't allow there to be more than one matching method. That is a difference
- * from Velocity, which blithely allows you to invoke {@link List#remove(int)} even though it
- * can't really know that you didn't mean to invoke {@link List#remove(Object)} with an Object
- * that just happens to be an Integer.
- *
- *
The method to be invoked must be visible in a public class or interface that is either the
- * class of {@code $x} itself or one of its supertypes. Allowing supertypes is important because
- * you may want to invoke a public method like {@link List#size()} on a list whose class is not
- * public, such as the list returned by {@link java.util.Collections#singletonList}.
- */
- @Override Object evaluate(EvaluationContext context) {
- Object lhsValue = lhs.evaluate(context);
- if (lhsValue == null) {
- throw evaluationException("Cannot invoke method " + id + " on null value");
- }
- List