@Override
    protected Traverser.Admin<Double> processNextStart() {
        final Traverser.Admin traverser = this.starts.next();

        final Expression localExpression = new Expression(this.expression.getExpression());
        boolean productive = true;
        for (final String var : this.expression.getVariables()) {
            final TraversalProduct product = var.equals(CURRENT) ?
                    TraversalUtil.produce(traverser, this.traversalRing.next()) :
                    TraversalUtil.produce((S) this.getNullableScopeValue(Pop.last, var, traverser), this.traversalRing.next());

            if (!product.isProductive()) {
                productive = false;
                break;
            }

            final Object o = product.get();

            // it's possible for ElementValueTraversal to return null or something that is possibly not a Number.
            // worth a check to try to return a nice error message. The TraversalRing<S, Number> is a bit optimistic
            // given type erasure. It could easily end up otherwise.
            if (!(o instanceof Number))
                throw new IllegalStateException(String.format(
                        "The variable %s for math() step must resolve to a Number - it is instead of type %s with value %s",
                        var, Objects.isNull(o) ? "null" : o.getClass().getName(), o));

            localExpression.setVariable(var, ((Number) o).doubleValue());
        }
        this.traversalRing.reset();

        // if at least one of the traversals wasnt productive it will filter
        return productive ?
                PathProcessor.processTraverserPathLabels(traverser.split(localExpression.evaluate(), this), this.keepLabels) :
                EmptyTraverser.instance();
    }
@author Marko A. Rodriguez (http://markorodriguez.com)
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java