156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/*
256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc.
356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License");
556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License.
656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at
756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0
956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software
1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS,
1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and
1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License.
1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.interpreter;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.EscapeMode;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.DataContext;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.functions.FunctionExecutor;
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.analysis.DepthFirstAdapter;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AAddExpression;
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AAndExpression;
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADecimalExpression;
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADescendVariable;
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADivideExpression;
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEqExpression;
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AExistsExpression;
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AFunctionExpression;
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AGtExpression;
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AGteExpression;
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AHexExpression;
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALtExpression;
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALteExpression;
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AModuloExpression;
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AMultiplyExpression;
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANameVariable;
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANeExpression;
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANegativeExpression;
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANotExpression;
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANumericAddExpression;
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANumericEqExpression;
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANumericExpression;
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANumericNeExpression;
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AOrExpression;
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AStringExpression;
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ASubtractExpression;
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AVariableExpression;
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PExpression;
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.values.Value;
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.values.Value.literalValue;
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.LinkedList;
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Walks the tree of a PExpression node and evaluates the expression.
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @see #evaluate(PExpression)
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class ExpressionEvaluator extends DepthFirstAdapter {
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private Value currentValue;
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final DataContext context;
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final FunctionExecutor functionExecutor;
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param context
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param functionExecutor Used for executing functions in expressions. As well as looking up
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *        named functions (e.g. html_escape), it also uses
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public ExpressionEvaluator(DataContext context, FunctionExecutor functionExecutor) {
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.context = context;
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.functionExecutor = functionExecutor;
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Evaluate an expression into a single value.
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Value evaluate(PExpression expression) {
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    assert currentValue == null;
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    expression.apply(this);
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Value result = currentValue;
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    currentValue = null;
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    assert result != null : "No result set from " + expression.getClass();
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return result;
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAVariableExpression(AVariableExpression node) {
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    VariableLocator variableLocator = new VariableLocator(this);
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String variableName = variableLocator.getVariableName(node.getVariable());
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    setResult(Value.variableValue(variableName, context));
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAStringExpression(AStringExpression node) {
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String value = node.getValue().getText();
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    value = value.substring(1, value.length() - 1); // Remove enclosing quotes.
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // The expression was a constant string literal. Does not
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // need to be autoescaped, as it was created by the template developer.
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Value result = literalValue(value, EscapeMode.ESCAPE_IS_CONSTANT, false);
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    setResult(result);
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseADecimalExpression(ADecimalExpression node) {
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String value = node.getValue().getText();
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    setResult(literalValue(Integer.parseInt(value), EscapeMode.ESCAPE_IS_CONSTANT, false));
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAHexExpression(AHexExpression node) {
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String value = node.getValue().getText();
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    value = value.substring(2); // Remove 0x prefix.
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    setResult(literalValue(Integer.parseInt(value, 16), EscapeMode.ESCAPE_IS_CONSTANT, false));
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANumericExpression(ANumericExpression node) {
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("#", node.getExpression());
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANotExpression(ANotExpression node) {
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("!", node.getExpression());
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAExistsExpression(AExistsExpression node) {
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("?", node.getExpression());
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAEqExpression(AEqExpression node) {
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("==", node.getLeft(), node.getRight());
14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANumericEqExpression(ANumericEqExpression node) {
14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("#==", node.getLeft(), node.getRight());
14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANeExpression(ANeExpression node) {
14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("!=", node.getLeft(), node.getRight());
15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANumericNeExpression(ANumericNeExpression node) {
15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("#!=", node.getLeft(), node.getRight());
15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseALtExpression(ALtExpression node) {
15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("<", node.getLeft(), node.getRight());
16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAGtExpression(AGtExpression node) {
16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction(">", node.getLeft(), node.getRight());
16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseALteExpression(ALteExpression node) {
16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("<=", node.getLeft(), node.getRight());
17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAGteExpression(AGteExpression node) {
17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction(">=", node.getLeft(), node.getRight());
17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAAndExpression(AAndExpression node) {
17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("&&", node.getLeft(), node.getRight());
18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAOrExpression(AOrExpression node) {
18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("||", node.getLeft(), node.getRight());
18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAAddExpression(AAddExpression node) {
18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("+", node.getLeft(), node.getRight());
19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANumericAddExpression(ANumericAddExpression node) {
19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("#+", node.getLeft(), node.getRight());
19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseASubtractExpression(ASubtractExpression node) {
19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("-", node.getLeft(), node.getRight());
20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAMultiplyExpression(AMultiplyExpression node) {
20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("*", node.getLeft(), node.getRight());
20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseADivideExpression(ADivideExpression node) {
20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("/", node.getLeft(), node.getRight());
21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAModuloExpression(AModuloExpression node) {
21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("%", node.getLeft(), node.getRight());
21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANegativeExpression(ANegativeExpression node) {
21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction("-", node.getExpression());
22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAFunctionExpression(AFunctionExpression node) {
22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    LinkedList<PExpression> argsList = node.getArgs();
22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    PExpression[] args = argsList.toArray(new PExpression[argsList.size()]);
22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    executeFunction(getFullFunctionName(node), args);
22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void executeFunction(String name, PExpression... expressions) {
23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Value[] args = new Value[expressions.length];
23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (int i = 0; i < args.length; i++) {
23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      args[i] = evaluate(expressions[i]);
23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    setResult(functionExecutor.executeFunction(name, args));
23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Sets a result from inside an expression.
24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void setResult(Value value) {
24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    assert value != null;
24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    currentValue = value;
24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private String getFullFunctionName(AFunctionExpression node) {
24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    final StringBuilder result = new StringBuilder();
25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    node.getName().apply(new DepthFirstAdapter() {
25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      @Override
25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      public void caseANameVariable(ANameVariable node) {
25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        result.append(node.getWord().getText());
25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      @Override
25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      public void caseADescendVariable(ADescendVariable node) {
25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        node.getParent().apply(this);
26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        result.append('.');
26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        node.getChild().apply(this);
26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    });
26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return result.toString();
26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
268