eval method

Decimal? eval()

Evaluates the expression.

Returns the result of the expression. Trailing zeros are stripped.

Implementation

Decimal? eval() {
  ListQueue<LazyNumber> stack = ListQueue();

  for (final Token token in getRPN()) {
    switch (token.type) {
      case TokenType.unaryOperator:
        {
          final LazyNumber value = stack.removeFirst();
          LazyNumber result = new LazyNumberImpl(eval: () {
            return operators[token.surface]?.evalLazy(value, null).eval();
          }, getString: () {
            return operators[token.surface]
                ?.evalLazy(value, null)
                .eval()
                .toString();
          });
          stack.addFirst(result);
          break;
        }
      case TokenType.operator:
        if (operators[token.surface]!.isUnaryOperator()) {
          LazyNumber value = stack.removeFirst();
          LazyNumberImpl result = new LazyNumberImpl(eval: () {
            return operators[token.surface]!.evalLazy(value, null).eval();
          }, getString: () {
            return operators[token.surface]!
                .evalLazy(value, null)
                .eval()
                .toString();
          });

          stack.addFirst(result);
        } else {
          final LazyNumber v1 = stack.removeFirst();
          final LazyNumber v2 = stack.removeFirst();
          LazyNumber result = new LazyNumberImpl(eval: () {
            return operators[token.surface]?.evalLazy(v2, v1).eval();
          }, getString: () {
            return operators[token.surface]
                ?.evalLazy(v2, v1)
                .eval()
                .toString();
          });

          stack.addFirst(result);
        }

        break;
      case TokenType.variable:
        if (!variables.containsKey(token.surface)) {
          throw new ExpressionException(
              "Unknown operator or function: " + token.toString());
        }

        stack.addFirst(LazyNumberImpl(eval: () {
          LazyNumber? lazyVariable = variables[token.surface];
          Decimal? value = lazyVariable == null ? null : lazyVariable.eval();
          return value;
        }, getString: () {
          LazyNumber? lazyVariable = variables[token.surface];
          return lazyVariable?.getString();
        }));
        break;
      case TokenType.function:
        ILazyFunction f = functions[token.surface.toUpperCase()]!;
        List<LazyNumber> p = [];
        // pop parameters off the stack until we hit the start of
        // this function's parameter list
        while (!stack.isEmpty && stack.first != _paramsStart) {
          p.insert(0, stack.removeFirst());
        }

        if (stack.first == _paramsStart) {
          stack.removeFirst();
        }

        LazyNumber? fResult = f.lazyEval(p);
        stack.addFirst(fResult);
        break;
      case TokenType.openParen:
        stack.addFirst(_paramsStart);
        break;
      case TokenType.literal:
        stack.addFirst(LazyNumberImpl(eval: () {
          if (token.surface.toLowerCase() == "null") {
            return null;
          }

          return Decimal.parse(token.surface);
        }, getString: () {
          return Decimal.parse(token.surface).toString();
        }));
        break;
      case TokenType.stringParam:
        stack.addFirst(LazyNumberImpl(eval: () {
          return null;
        }, getString: () {
          return token.surface;
        }));
        break;
      case TokenType.hexLiteral:
        stack.addFirst(LazyNumberImpl(eval: () {
          BigInt bigInt = BigInt.parse(token.surface.substring(2), radix: 16);
          return Decimal.parse(bigInt.toString());
        }, getString: () {
          BigInt bigInt = BigInt.parse(token.surface.substring(2), radix: 16);
          return Decimal.parse(bigInt.toString()).toString();
        }));
        break;
      default:
        throw new ExpressionException.pos(
            "Unexpected token " + token.surface, token.pos);
    }
  }

  Decimal? result = stack.removeFirst().eval();
  if (result == null) {
    return null;
  }

  // if (stripTrailingZeros) {
  //   result = result.stripTrailingZeros();
  // }
  return result;
}