1 package org.apache.velocity.runtime.parser.node;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.velocity.context.InternalContextAdapter;
23 import org.apache.velocity.exception.MethodInvocationException;
24 import org.apache.velocity.exception.VelocityException;
25 import org.apache.velocity.runtime.RuntimeConstants;
26 import org.apache.velocity.runtime.log.Log;
27 import org.apache.velocity.runtime.parser.Parser;
28 import org.apache.velocity.util.DuckType;
29
30
31
32
33
34
35
36
37 public abstract class ASTComparisonNode extends SimpleNode
38 {
39
40
41
42 public ASTComparisonNode(int id)
43 {
44 super(id);
45 }
46
47
48
49
50
51 public ASTComparisonNode(Parser p, int id)
52 {
53 super(p, id);
54 }
55
56
57
58
59
60 public Object jjtAccept(ParserVisitor visitor, Object data)
61 {
62 return visitor.visit(this, data);
63 }
64
65
66
67
68 public boolean evaluate(InternalContextAdapter context) throws MethodInvocationException
69 {
70 Object left = jjtGetChild(0).value(context);
71 Object right = jjtGetChild(1).value(context);
72
73 if (left == null || right == null)
74 {
75 return compareNull(left, right);
76 }
77 Boolean result = compareNumbers(left, right);
78 if (result == null)
79 {
80 result = compareNonNumber(left, right);
81 }
82 return result;
83 }
84
85
86
87
88 public boolean compareNull(Object left, Object right)
89 {
90
91 String msg = (left == null ? "Left" : "Right")
92 + " side ("
93 + jjtGetChild( (left == null? 0 : 1) ).literal()
94 + ") of comparison operation has null value at "
95 + Log.formatFileString(this);
96 if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
97 {
98 throw new VelocityException(msg);
99 }
100 log.error(msg);
101 return false;
102 }
103
104 public Boolean compareNumbers(Object left, Object right)
105 {
106 try
107 {
108 left = DuckType.asNumber(left);
109 }
110 catch (NumberFormatException nfe) {}
111 try
112 {
113 right = DuckType.asNumber(right);
114 }
115 catch (NumberFormatException nfe) {}
116
117
118 if (left instanceof Number && right instanceof Number)
119 {
120 return numberTest(MathUtils.compare((Number)left, (Number)right));
121 }
122 return null;
123 }
124
125 public abstract boolean numberTest(int compareResult);
126
127 public boolean compareNonNumber(Object left, Object right)
128 {
129
130 String msg = (right instanceof Number ? "Left" : "Right")
131 + " side of comparison operation is not a number at "
132 + Log.formatFileString(this);
133 if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
134 {
135 throw new VelocityException(msg);
136 }
137 log.error(msg);
138 return false;
139 }
140
141 private String getLiteral(boolean left)
142 {
143 return jjtGetChild(left ? 0 : 1).literal();
144 }
145
146
147
148
149 public Object value(InternalContextAdapter context) throws MethodInvocationException
150 {
151 return Boolean.valueOf(evaluate(context));
152 }
153
154 }