• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.escapevelocity;
17 
18 import com.google.common.collect.ImmutableList;
19 import java.util.List;
20 
21 /**
22  * A parsing node that will be deleted during the construction of the parse tree, to be replaced
23  * by a higher-level construct such as {@link DirectiveNode.IfNode}. See {@link Parser#parse()}
24  * for a description of the way these tokens work.
25  *
26  * @author emcmanus@google.com (Éamonn McManus)
27  */
28 abstract class TokenNode extends Node {
TokenNode(String resourceName, int lineNumber)29   TokenNode(String resourceName, int lineNumber) {
30     super(resourceName, lineNumber);
31   }
32 
33   /**
34    * This method always throws an exception because a node like this should never be found in the
35    * final parse tree.
36    */
evaluate(EvaluationContext vars)37   @Override Object evaluate(EvaluationContext vars) {
38     throw new UnsupportedOperationException(getClass().getName());
39   }
40 
41   /**
42    * The name of the token, for use in parse error messages.
43    */
name()44   abstract String name();
45 
46   /**
47    * A synthetic node that represents the end of the input. This node is the last one in the
48    * initial token string and also the last one in the parse tree.
49    */
50   static final class EofNode extends TokenNode {
EofNode(String resourceName, int lineNumber)51     EofNode(String resourceName, int lineNumber) {
52       super(resourceName, lineNumber);
53     }
54 
55     @Override
name()56     String name() {
57       return "end of file";
58     }
59   }
60 
61   static final class EndTokenNode extends TokenNode {
EndTokenNode(String resourceName, int lineNumber)62     EndTokenNode(String resourceName, int lineNumber) {
63       super(resourceName, lineNumber);
64     }
65 
name()66     @Override String name() {
67       return "#end";
68     }
69   }
70 
71   /**
72    * A node in the parse tree representing a comment. Comments are introduced by {@code ##} and
73    * extend to the end of the line. The only reason for recording comment nodes is so that we can
74    * skip space between a comment and a following {@code #set}, to be compatible with Velocity
75    * behaviour.
76    */
77   static class CommentTokenNode extends TokenNode {
CommentTokenNode(String resourceName, int lineNumber)78     CommentTokenNode(String resourceName, int lineNumber) {
79       super(resourceName, lineNumber);
80     }
81 
name()82     @Override String name() {
83       return "##";
84     }
85   }
86 
87   abstract static class IfOrElseIfTokenNode extends TokenNode {
88     final ExpressionNode condition;
89 
IfOrElseIfTokenNode(ExpressionNode condition)90     IfOrElseIfTokenNode(ExpressionNode condition) {
91       super(condition.resourceName, condition.lineNumber);
92       this.condition = condition;
93     }
94   }
95 
96   static final class IfTokenNode extends IfOrElseIfTokenNode {
IfTokenNode(ExpressionNode condition)97     IfTokenNode(ExpressionNode condition) {
98       super(condition);
99     }
100 
name()101     @Override String name() {
102       return "#if";
103     }
104   }
105 
106   static final class ElseIfTokenNode extends IfOrElseIfTokenNode {
ElseIfTokenNode(ExpressionNode condition)107     ElseIfTokenNode(ExpressionNode condition) {
108       super(condition);
109     }
110 
name()111     @Override String name() {
112       return "#elseif";
113     }
114   }
115 
116   static final class ElseTokenNode extends TokenNode {
ElseTokenNode(String resourceName, int lineNumber)117     ElseTokenNode(String resourceName, int lineNumber) {
118       super(resourceName, lineNumber);
119     }
120 
name()121     @Override String name() {
122       return "#else";
123     }
124   }
125 
126   static final class ForEachTokenNode extends TokenNode {
127     final String var;
128     final ExpressionNode collection;
129 
ForEachTokenNode(String var, ExpressionNode collection)130     ForEachTokenNode(String var, ExpressionNode collection) {
131       super(collection.resourceName, collection.lineNumber);
132       this.var = var;
133       this.collection = collection;
134     }
135 
name()136     @Override String name() {
137       return "#foreach";
138     }
139   }
140 
141   static final class NestedTokenNode extends TokenNode {
142     final ImmutableList<Node> nodes;
143 
NestedTokenNode(String resourceName, ImmutableList<Node> nodes)144     NestedTokenNode(String resourceName, ImmutableList<Node> nodes) {
145       super(resourceName, 1);
146       this.nodes = nodes;
147     }
148 
name()149     @Override String name() {
150       return "#parse(\"" + resourceName + "\")";
151     }
152   }
153 
154   static final class MacroDefinitionTokenNode extends TokenNode {
155     final String name;
156     final ImmutableList<String> parameterNames;
157 
MacroDefinitionTokenNode( String resourceName, int lineNumber, String name, List<String> parameterNames)158     MacroDefinitionTokenNode(
159         String resourceName, int lineNumber, String name, List<String> parameterNames) {
160       super(resourceName, lineNumber);
161       this.name = name;
162       this.parameterNames = ImmutableList.copyOf(parameterNames);
163     }
164 
name()165     @Override String name() {
166       return "#macro(" + name + ")";
167     }
168   }
169 }
170