gt:         PAREN_OPEN("(", 10, Assoc.BRACKET_OPEN, false, ")"),
context: package CustomOreGen.Config;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.EmptyStackException;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Stack;
  
  public class ExpressionEvaluator
  {
      protected static Map<String,TokenType> _symbolMap = new HashMap<String, TokenType>();
  
      protected Object getIdentifierValue(String identifier)
      {
          return null;
      }
  
      public Object evaluate(String expression) throws EvaluatorException
      {
          Stack<Token> input = this.parse(expression);
  
          if (input.isEmpty())
          {
              return null;
          }
          else
          {
              Object result = null;
  
              try
              {
                  result = evaluate(input);
              }
              catch (EmptyStackException var5)
              {
                  throw new EvaluatorException("Incomplete expression.", new Token(expression, expression.length(), expression.length()));
              }
  
              if (!input.isEmpty())
              {
                  throw new EvaluatorException("Expression contains too many values.", input.peek());
              }
              else
              {
                  return result;
              }
          }
      }
  
      protected static Object evaluate(Stack<Token> input) throws EmptyStackException, EvaluatorException
      {
          Token token = input.pop();
  
          if (!token.type.retain)
          {
              throw new EvaluatorException("Un-evaluatable token.", token);
          }
          else
          {
              boolean rhs;
              boolean lhs;
              Object rhs1;
              double rhs2;
              Object lhs1;
              String lhs2;
              String rhs3;
  
              switch (token.type)
              {
                  case SCIENTIFIC:
                      rhs2 = evaluateNumber(input);
                      return Double.valueOf(evaluateNumber(input) * Math.pow(10.0D, rhs2));
  
                  case TO_STRING:
                      return evaluate(input).toString();
  
                  case TO_NUMBER:
                      rhs1 = evaluate(input);
  
                      if (rhs1 instanceof Number)
                      {
                          return (Number)rhs1;
                      }
                      else if (rhs1 instanceof Boolean)
                      {
                          return Long.valueOf(((Boolean)rhs1).booleanValue() ? 1L : 0L);
                      }
                      else
                      {
                          if (rhs1 instanceof String)
                          {
                              try
                              {
                                  if (rhs1.toString().contains("."))
                                  {
                                      return Double.valueOf(Double.parseDouble(rhs1.toString()));
                                  }
  
                                  return Long.decode(rhs1.toString());
                              }
                              catch (NumberFormatException var5)
                              {
                                  ;
                              }
                          }
  
                          throw new EvaluatorException("Cannot reduce \'" + rhs1 + "\' to a numerical value.", token);
                      }
  
                  case TO_BOOLEAN:
                      rhs1 = evaluate(input);
  
                      if (rhs1 instanceof Boolean)
                      {
                          return (Boolean)rhs1;
                      }
                      else if (rhs1 instanceof Number)
                      {
                          return Boolean.valueOf(((Number)rhs1).doubleValue() != 0.0D);
                      }
                      else
                      {
                          if (rhs1 instanceof String)
                          {
                              if (rhs1.toString().equalsIgnoreCase("true"))
                              {
                                  return Boolean.TRUE;
                              }
  
                              if (rhs1.toString().equalsIgnoreCase("false"))
                              {
                                  return Boolean.FALSE;
                              }
                          }
  
                          throw new EvaluatorException("Cannot reduce \'" + rhs1 + "\' to a boolean value.", token);
                      }
  
                  case LOGICAL_NOT:
                      return Boolean.valueOf(!evaluateBoolean(input));
  
                  case UNARY_MINUS:
                      return Double.valueOf(-evaluateNumber(input));
  
                  case UNARY_PLUS:
                      return Double.valueOf(evaluateNumber(input));
  
                  case IF:
                      rhs1 = evaluate(input);
                      lhs1 = evaluate(input);
                      return evaluateBoolean(input) ? lhs1 : rhs1;
  
                  case MATCH:
                      rhs3 = evaluateString(input);
                      lhs2 = evaluateString(input);
                      return Boolean.valueOf(lhs2.matches(rhs3));
  
                  case REPLACE:
                      rhs3 = evaluateString(input);
                      lhs2 = evaluateString(input);
                      String equal1 = evaluateString(input);
                      return equal1.replaceAll(lhs2, rhs3);
  
                  case MULTIPLY:
                      return Double.valueOf(evaluateNumber(input) * evaluateNumber(input));
  
                  case DIVIDE:
                      rhs2 = evaluateNumber(input);
                      return Double.valueOf(evaluateNumber(input) / rhs2);
  
                  case MODULUS:
                      rhs2 = evaluateNumber(input);
                      return Double.valueOf(evaluateNumber(input) % rhs2);
  
                  case ADD:
                      return Double.valueOf(evaluateNumber(input) + evaluateNumber(input));
  
                  case SUBTRACT:
                      rhs2 = evaluateNumber(input);
                      return Double.valueOf(evaluateNumber(input) - rhs2);
  
                  case CONCATENATE:
                      rhs3 = evaluateString(input);
                      lhs2 = evaluateString(input);
                      return lhs2 + rhs3;
  
                  case LESS:
                      rhs2 = evaluateNumber(input);
                      return Boolean.valueOf(evaluateNumber(input) < rhs2);
  
                  case LESS_EQUAL:
                      rhs2 = evaluateNumber(input);
                      return Boolean.valueOf(evaluateNumber(input) <= rhs2);
                  case GREATER:
  
                      rhs2 = evaluateNumber(input);
                      return Boolean.valueOf(evaluateNumber(input) > rhs2);
  
                  case GREATER_EQUAL:
                      rhs2 = evaluateNumber(input);
                      return Boolean.valueOf(evaluateNumber(input) >= rhs2);
  
                  case EQUAL:
                  case NOT_EQUAL:
                      rhs1 = evaluate(input);
                      lhs1 = evaluate(input);
                      boolean equal = false;
  
                      if (lhs1 instanceof Number && rhs1 instanceof Number)
                      {
                          equal = ((Number)lhs1).doubleValue() == ((Number)rhs1).doubleValue();
                      }
                      else
                      {
                          if (!lhs1.getClass().isAssignableFrom(rhs1.getClass()))
                          {
                              throw new EvaluatorException("Cannot compare equality of \'" + lhs1.getClass().getSimpleName() + "\' and \'" + rhs1.getClass().getSimpleName() + "\'.", token);
                          }
  
                          equal = rhs1.equals(lhs1);
                      }
  
                      return Boolean.valueOf(token.type == TokenType.EQUAL ? equal : !equal);
  
                  case AND:
                      rhs = evaluateBoolean(input);
                      lhs = evaluateBoolean(input);
                      return Boolean.valueOf(lhs && rhs);
  
                  case OR:
                      rhs = evaluateBoolean(input);
                      lhs = evaluateBoolean(input);
                      return Boolean.valueOf(lhs || rhs);
  
                  default:
                      if (token.data == null)
                      {
                          throw new EvaluatorException("Un-evaluatable token.", token);
                      }
                      else if (token.data instanceof EvaluationDelegate)
                      {
                          return ((EvaluationDelegate)token.data).evaluate(token, input);
                      }
                      else
                      {
                          return token.data;
                      }
              }
          }
      }
  
      protected static String evaluateString(Stack<Token> input) throws EmptyStackException, EvaluatorException
      {
          Token token = input.peek();
          Object value = evaluate(input);
  
          try
          {
              return (String)value;
          }
          catch (ClassCastException var4)
          {
              throw new EvaluatorException("Expected a string value.", token, var4);
          }
      }
  
      protected static double evaluateNumber(Stack<Token> input) throws EmptyStackException, EvaluatorException
      {
          Token token = input.peek();
          Object value = evaluate(input);
  
          try
          {
              return ((Number)value).doubleValue();
          }
          catch (ClassCastException var4)
          {
              throw new EvaluatorException("Expected a numeric value.", token, var4);
          }
      }
  
      protected static boolean evaluateBoolean(Stack<Token> input) throws EmptyStackException, EvaluatorException
      {
          Token token = input.peek();
          Object value = evaluate(input);
  
          try
          {
              return ((Boolean)value).booleanValue();
          }
          catch (ClassCastException var4)
          {
              throw new EvaluatorException("Expected a boolean value.", token, var4);
          }
      }
  
      public Stack<Token> parse(String expression) throws EvaluatorException
      {
          Stack<Token> output = new Stack<Token>();
          Stack<Token> held = new Stack<Token>();
          Token lastToken = null;
          Assoc lastAssoc = Assoc.RIGHT;
          Token heldTop;
  
          for (heldTop = this.getToken(expression, 0); heldTop != null; heldTop = this.getToken(expression, heldTop.end))
          {
              Assoc assoc = heldTop.type.associativity;
  
              if (assoc == Assoc.BRACKET_OPEN)
              {
                  assoc = Assoc.RIGHT;
              }
              else if (assoc == Assoc.BRACKET_CLOSE)
              {
                  assoc = Assoc.LEFT;
              }
  
              if (assoc == Assoc.LEFT != (lastAssoc == Assoc.NONE))
              {
                  if (heldTop.type == TokenType.ADD)
                  {
                      heldTop = new Token(heldTop.source, heldTop.start, heldTop.end, TokenType.UNARY_PLUS);
                  }
                  else
                  {
                      if (heldTop.type != TokenType.SUBTRACT)
                      {
                          throw new EvaluatorException("\'" + heldTop + "\' cannot follow \'" + lastToken + "\'.", heldTop);
                      }
  
                      heldTop = new Token(heldTop.source, heldTop.start, heldTop.end, TokenType.UNARY_MINUS);
                  }
              }
  
              lastAssoc = assoc;
              lastToken = heldTop;
              Token heldTop1;
  
              switch (heldTop.type.associativity)
              {
                  case NONE:
                      if (heldTop.type.retain)
                      {
                          output.push(heldTop);
                      }
  
                      break;
  
                  case BRACKET_OPEN:
                      held.push(heldTop);
                      break;
  
                  case BRACKET_CLOSE:
                      heldTop1 = null;
  
                      while (heldTop1 == null && !held.isEmpty())
                      {
                          Token heldTop2 = held.pop();
  
                          if (heldTop2.type.associativity == Assoc.BRACKET_OPEN)
                          {
                              if (!heldTop2.toString().equals(heldTop.data))
                              {
                                  throw new EvaluatorException("Missing corresponding " + heldTop2.data + ".", heldTop2);
                              }
  
                              heldTop1 = heldTop2;
                          }
                          else if (heldTop2.type.retain)
                          {
                              output.push(heldTop2);
                          }
                      }
  
                      if (heldTop1 == null)
                      {
                          throw new EvaluatorException("Missing corresponding " + heldTop.data + ".", heldTop);
                      }
  
                      if (heldTop.type.retain)
                      {
                          output.push(heldTop1);
                          output.push(heldTop);
                      }
  
                      lastAssoc = Assoc.NONE;
                      break;
  
                  case LEFT:
                  case RIGHT:
                      while (!held.isEmpty())
                      {
                          heldTop1 = held.peek();
  
                          if (heldTop1.type.associativity != Assoc.LEFT && heldTop1.type.associativity != Assoc.RIGHT || heldTop.type.associativity == Assoc.RIGHT && heldTop.type.precedence == heldTop1.type.precedence || heldTop.type.precedence < heldTop1.type.precedence)
                          {
                              break;
                          }
  
                          held.pop();
  
                          if (heldTop1.type.retain)
                          {
                              output.push(heldTop1);
                          }
                      }
  
                      held.push(heldTop);
              }
          }
  
          if (!output.isEmpty() && lastAssoc != Assoc.NONE)
          {
              throw new EvaluatorException("Incomplete expression.", new Token(expression, expression.length(), expression.length()));
          }
          else
          {
              while (!held.isEmpty())
              {
                  heldTop = held.pop();
  
                  if (heldTop.type.associativity == Assoc.BRACKET_OPEN)
                  {
                      throw new EvaluatorException("Missing corresponding " + heldTop.data + ".", heldTop);
                  }
  
                  if (heldTop.type.retain)
                  {
                      output.push(heldTop);
                  }
              }
  
              return output;
          }
      }
  
      public Token getToken(String input, int start) throws EvaluatorException
      {
          if (input != null && !input.isEmpty())
          {
              while (input.length() > start && Character.isWhitespace(input.charAt(start)))
              {
                  ++start;
              }
  
              if (input.length() <= start)
              {
                  return null;
              }
              else
              {
                  char ch = input.charAt(start);
                  int end = start + 1;
  
                  if (Character.isDigit(ch))
                  {
                      boolean isReal = false;
                      char ex;
  
                      if (ch == 48 && input.length() > end && Character.toLowerCase(input.charAt(end)) == 'x')
                      {
                          ++end;
  
                          while (input.length() > end)
                          {
                              ex = input.charAt(end);
  
                              if (!Character.isDigit(ex) && (ex < 'a' || ex > 'f') && (ex < 'A' || ex > 'F'))
                              {
                                  break;
                              }
  
                              ++end;
                          }
                      }
                      else
                      {
                          while (input.length() > end)
                          {
                              ex = input.charAt(end);
  
                              if (Character.isDigit(ex))
                              {
                                  ++end;
                              }
                              else
                              {
                                  if (ex != '.')
                                  {
                                      break;
                                  }
  
                                  ++end;
                                  isReal = true;
                              }
                          }
                      }
  
                      try
                      {
                          return isReal ? new Token(input, start, end, TokenType.NUMBER, Double.valueOf(Double.parseDouble(input.substring(start, end)))) : new Token(input, start, end, TokenType.NUMBER, Long.decode(input.substring(start, end)));
                      }
                      catch (NumberFormatException var7)
                      {
                          throw new EvaluatorException("Invalid number.", new Token(input, start, end));
                      }
                  }
                  else
                  {
                      if (!Character.isLetter(ch) && ch != '_')
                      {
                          if (ch == '"' || ch == '\'')
                          {
                              end = input.indexOf(ch, end);
  
                              if (end < 0)
                              {
                                  throw new EvaluatorException("Unmatched string delimeter " + ch + ".", new Token(input, start, start + 1));
                              }
  
                              ++end;
                              return new Token(input, start, end, TokenType.STRING, input.substring(start + 1, end - 1));
                          }
  
                          if ((ch == '<' || ch == '>' || ch == '!') && input.length() > end && input.charAt(end) == '=')
                          {
                              ++end;
                          }
                      }
                      else
                      {
                          while (input.length() > end)
                          {
                              char type = input.charAt(end);
  
                              if (!Character.isLetterOrDigit(type) && type != '_' && type != '.')
                              {
                                  break;
                              }
  
                              ++end;
                          }
  
                          Object id = this.getIdentifierValue(input.substring(start, end));
  
                          if (id != null)
                          {
                              if (id instanceof EvaluationDelegate && ((EvaluationDelegate)id).explicitArguments() > 0)
                              {
                                  return new Token(input, start, end, TokenType.FUNCTION, id);
                              }
  
                              return new Token(input, start, end, TokenType.VARIABLE, id);
                          }
                      }
  
                      TokenType sym = _symbolMap.get(input.substring(start, end).toLowerCase());
  
                      if (sym != null)
                      {
                          return new Token(input, start, end, sym);
                      }
                      else
                      {
                          throw new EvaluatorException("Unexpected token.", new Token(input, start, end));
                      }
                  }
              }
          }
          else
          {
              return null;
          }
      }
  
      static
      {
      	for (TokenType type : TokenType.values()) {
          	if (type.symbol != null)
              {
                  _symbolMap.put(type.symbol, type);
              }
          }
      }
      
      public static enum TokenType
      {
          TRUE("true", 0, Assoc.NONE, true, Boolean.valueOf(true)),
          FALSE("false", 0, Assoc.NONE, true, Boolean.valueOf(false)),
          NUMBER((String)null, 0, Assoc.NONE, true, (Object)null),
          HEXNUMBER((String)null, 0, Assoc.NONE, true, (Object)null),
          STRING((String)null, 0, Assoc.NONE, true, (Object)null),
          VARIABLE((String)null, 0, Assoc.NONE, true, (Object)null),
  