public Object apply()

in metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/StellarCompiler.java [156:282]


    public Object apply(ExpressionState state) {
      Deque<Token<?>> instanceDeque = new ArrayDeque<>();
      {
        int skipElseCount = 0;
        boolean skipMatchClauses = false;
        Token<?> token = null;
        for (Iterator<Token<?>> it = getTokenDeque().descendingIterator(); it.hasNext(); ) {
          token = it.next();
          //if we've skipped an else previously, then we need to skip the deferred tokens associated with the else.
          if (skipElseCount > 0 && token.getUnderlyingType() == ElseExpr.class) {
            while (it.hasNext()) {
              token = it.next();
              if (token.getUnderlyingType() == EndConditional.class) {
                break;
              }
            }
            // We've completed a single else.
            skipElseCount--;
          }
          if (skipMatchClauses && (token.getUnderlyingType() == MatchClauseEnd.class
              || token.getUnderlyingType() == MatchClauseCheckExpr.class)) {
            while (it.hasNext()) {
              token = it.next();
              if (token.getUnderlyingType() == MatchClausesEnd.class) {
                break;
              }
            }
            skipMatchClauses = false;
          }
          /*
          curr is the current value on the stack.  This is the non-deferred actual evaluation for this expression
          and with the current context.
           */
          Token<?> curr = instanceDeque.peek();
          boolean isFalsey = curr != null &&
                  (isBoolean(token, curr.getValue()) || isEmptyList(token, curr.getValue()));
          if(isFalsey){
            //If we're in a situation where the token is a boolean token and the current value is one of the implicitly falsey scenarios
            //* null or missing variable
            //* empty list
            // then we want to treat it as explicitly false by replacing the current token.
            curr = new Token<>(false, Boolean.class, curr.getMultiArgContext());
            instanceDeque.removeFirst();
            instanceDeque.addFirst(curr);
          }
          if (curr != null && curr.getValue() != null && curr.getValue() instanceof Boolean
              && ShortCircuitOp.class.isAssignableFrom(token.getUnderlyingType())) {
            //if we have a boolean as the current value and the next non-contextual token is a short circuit op
            //then we need to short circuit possibly
            if (token.getUnderlyingType() == BooleanArg.class) {
              if (token.getMultiArgContext() != null
                  && token.getMultiArgContext().getVariety() == FrameContext.BOOLEAN_OR
                  && (Boolean) (curr.getValue())) {
                //short circuit the or
                FrameContext.Context context = curr.getMultiArgContext();
                shortCircuit(it, context);
              } else if (token.getMultiArgContext() != null
                  && token.getMultiArgContext().getVariety() == FrameContext.BOOLEAN_AND
                  && !(Boolean) (curr.getValue())) {
                //short circuit the and
                FrameContext.Context context = curr.getMultiArgContext();
                shortCircuit(it, context);
              }
            } else if (token.getUnderlyingType() == IfExpr.class) {
              //short circuit the if/then/else
              instanceDeque.pop();
              if((Boolean)curr.getValue()) {
                //choose then.  Need to make sure we're keeping track of nesting.
                skipElseCount++;
              } else {
                //choose else
                // Need to count in case we see another if-else, to avoid breaking on wrong else.
                int innerIfCount = 0;
                while (it.hasNext()) {
                  Token<?> t = it.next();
                  if (t.getUnderlyingType() == IfExpr.class) {
                    innerIfCount++;
                  } else if (t.getUnderlyingType() == ElseExpr.class) {
                    if (innerIfCount == 0) {
                      break;
                    } else {
                      innerIfCount--;
                    }
                  }
                }
              }
            } else if (token.getUnderlyingType() == MatchClauseCheckExpr.class) {
              instanceDeque.pop();
              if ((Boolean) curr.getValue()) {
                //skip everything else after lambda
                skipMatchClauses = true;
              } else {
                while (it.hasNext()) {
                  Token<?> t = it.next();
                  if (t.getUnderlyingType() == MatchClauseEnd.class) {
                    break;
                  }
                }
              }
            }
          }
          if (token.getUnderlyingType() == DeferredFunction.class) {
            DeferredFunction func = (DeferredFunction) token.getValue();
            func.apply(instanceDeque, state);
          }
          else if(token.getUnderlyingType() != ShortCircuitFrame.class
               && !ShortCircuitOp.class.isAssignableFrom(token.getUnderlyingType())
                  ) {
            instanceDeque.push(token);
          }

        }
      }

      if (instanceDeque.isEmpty()) {
        throw new ParseException("Invalid predicate: Empty stack.");
      }
      Token<?> token = instanceDeque.pop();
      if (instanceDeque.isEmpty()) {
        return token.getValue();
      }
      if (instanceDeque.isEmpty()) {
        throw new ParseException("Invalid parse, stack not empty: " + Joiner.on(',').join(instanceDeque));
      } else {
        throw new ParseException("Invalid parse, found " + token);
      }
    }