• 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 
20 /**
21  * A node in the parse tree.
22  *
23  * @author emcmanus@google.com (Éamonn McManus)
24  */
25 abstract class Node {
26   final String resourceName;
27   final int lineNumber;
28 
Node(String resourceName, int lineNumber)29   Node(String resourceName, int lineNumber) {
30     this.resourceName = resourceName;
31     this.lineNumber = lineNumber;
32   }
33 
34   /**
35    * Returns the result of evaluating this node in the given context. This result may be used as
36    * part of a further operation, for example evaluating {@code 2 + 3} to 5 in order to set
37    * {@code $x} to 5 in {@code #set ($x = 2 + 3)}. Or it may be used directly as part of the
38    * template output, for example evaluating replacing {@code name} by {@code Fred} in
39    * {@code My name is $name.}.
40    */
evaluate(EvaluationContext context)41   abstract Object evaluate(EvaluationContext context);
42 
where()43   private String where() {
44     String where = "In expression on line " + lineNumber;
45     if (resourceName != null) {
46       where += " of " + resourceName;
47     }
48     return where;
49   }
50 
evaluationException(String message)51   EvaluationException evaluationException(String message) {
52     return new EvaluationException(where() + ": " + message);
53   }
54 
evaluationException(Throwable cause)55   EvaluationException evaluationException(Throwable cause) {
56     return new EvaluationException(where() + ": " + cause, cause);
57   }
58 
59   /**
60    * Returns an empty node in the parse tree. This is used for example to represent the trivial
61    * "else" part of an {@code #if} that does not have an explicit {@code #else}.
62    */
emptyNode(String resourceName, int lineNumber)63   static Node emptyNode(String resourceName, int lineNumber) {
64     return new Cons(resourceName, lineNumber, ImmutableList.<Node>of());
65   }
66 
67   /**
68    * Create a new parse tree node that is the concatenation of the given ones. Evaluating the
69    * new node produces the same string as evaluating each of the given nodes and concatenating the
70    * result.
71    */
cons(String resourceName, int lineNumber, ImmutableList<Node> nodes)72   static Node cons(String resourceName, int lineNumber, ImmutableList<Node> nodes) {
73     return new Cons(resourceName, lineNumber, nodes);
74   }
75 
76   private static final class Cons extends Node {
77     private final ImmutableList<Node> nodes;
78 
Cons(String resourceName, int lineNumber, ImmutableList<Node> nodes)79     Cons(String resourceName, int lineNumber, ImmutableList<Node> nodes) {
80       super(resourceName, lineNumber);
81       this.nodes = nodes;
82     }
83 
evaluate(EvaluationContext context)84     @Override Object evaluate(EvaluationContext context) {
85       StringBuilder sb = new StringBuilder();
86       for (Node node : nodes) {
87         sb.append(node.evaluate(context));
88       }
89       return sb.toString();
90     }
91   }
92 }
93