public Object eval(String expr, Map<String, Object> params) {
    try {
      Extension ext = extensionRepo == null ? null : extensionRepo.get();
      SelType result = evaluator.evaluate(sanitize(expr), params, ext);

      switch (result.type()) {
        case STRING:
        case LONG:
        case DOUBLE:
        case BOOLEAN:
          return result.getInternalVal();
        case STRING_ARRAY:
        case LONG_ARRAY:
        case DOUBLE_ARRAY:
        case BOOLEAN_ARRAY:
        case MAP:
          return result.unbox();
        case ERROR:
          throw new MaestroInvalidExpressionException(
              "Expression throws an error [%s] for expr=[%s]", result, expr);
        default:
          throw new MaestroInvalidExpressionException(
              "Invalid return type [%s] for expr=[%s]", result.type(), expr);
      }
    } catch (MaestroRuntimeException me) {
      throw me;
    } catch (ExecutionException ee) {
      throw new MaestroInvalidExpressionException(
          ee, "Expression evaluation throws an exception for expr=[%s]", expr);
    } catch (Exception e) {
      throw new MaestroInternalError(
          e, "Expression evaluation is failed with an exception for expr=[%s]", expr);
    }
  }
@Test
  public void testMissingSemicolon() {
    assertEquals(11L, evaluator.eval("x + 1", Collections.singletonMap("x", 10)));
  }