Search in sources :

Example 1 with Union

use of org.mvel2.optimizers.impl.refl.nodes.Union in project mvel by mikebrock.

the class AbstractParser method nextToken.

/**
   * Retrieve the next token in the expression.
   *
   * @return -
   */
protected ASTNode nextToken() {
    try {
        /**
       * If the cursor is at the end of the expression, we have nothing more to do:
       * return null.
       */
        if (!splitAccumulator.isEmpty()) {
            lastNode = (ASTNode) splitAccumulator.pop();
            if (cursor >= end && lastNode instanceof EndOfStatement) {
                return nextToken();
            } else {
                return lastNode;
            }
        } else if (cursor >= end) {
            return null;
        }
        int brace, idx;
        int tmpStart;
        String name;
        /**
       * Because of parser recursion for sub-expression parsing, we sometimes need to remain
       * certain field states.  We do not reset for assignments, boolean mode, list creation or
       * a capture only mode.
       */
        boolean capture = false, union = false;
        if ((fields & ASTNode.COMPILE_IMMEDIATE) != 0 && pCtx == null) {
            debugSymbols = (pCtx = getParserContext()).isDebugSymbols();
        }
        if (debugSymbols) {
            if (!lastWasLineLabel) {
                if (pCtx.getSourceFile() == null) {
                    throw new CompileException("unable to produce debugging symbols: source name must be provided.", expr, st);
                }
                if (!pCtx.isLineMapped(pCtx.getSourceFile())) {
                    pCtx.initLineMapping(pCtx.getSourceFile(), expr);
                }
                skipWhitespace();
                if (cursor >= end) {
                    return null;
                }
                int line = pCtx.getLineFor(pCtx.getSourceFile(), cursor);
                if (!pCtx.isVisitedLine(pCtx.getSourceFile(), pCtx.setLineCount(line)) && !pCtx.isBlockSymbols()) {
                    lastWasLineLabel = true;
                    pCtx.visitLine(pCtx.getSourceFile(), line);
                    return lastNode = pCtx.setLastLineLabel(new LineLabel(pCtx.getSourceFile(), line));
                }
            } else {
                lastWasComment = lastWasLineLabel = false;
            }
        }
        /**
       * Skip any whitespace currently under the starting point.
       */
        skipWhitespace();
        /**
       * From here to the end of the method is the core MVEL parsing code.  Fiddling around here is asking for
       * trouble unless you really know what you're doing.
       */
        st = cursor;
        Mainloop: while (cursor != end) {
            if (isIdentifierPart(expr[cursor])) {
                capture = true;
                cursor++;
                while (cursor != end && isIdentifierPart(expr[cursor])) cursor++;
            }
            if (capture) {
                String t;
                if (OPERATORS.containsKey(t = new String(expr, st, cursor - st))) {
                    switch(OPERATORS.get(t)) {
                        case NEW:
                            if (!isIdentifierPart(expr[st = cursor = trimRight(cursor)])) {
                                throw new CompileException("unexpected character (expected identifier): " + expr[cursor], expr, st);
                            }
                            /**
                 * Capture the beginning part of the token.
                 */
                            do {
                                captureToNextTokenJunction();
                                skipWhitespace();
                            } while (cursor < end && expr[cursor] == '[');
                            /**
                 * If it's not a dimentioned array, continue capturing if necessary.
                 */
                            if (cursor < end && !lastNonWhite(']'))
                                captureToEOT();
                            TypeDescriptor descr = new TypeDescriptor(expr, st, trimLeft(cursor) - st, fields);
                            if (pCtx == null)
                                pCtx = getParserContext();
                            if (pCtx.hasProtoImport(descr.getClassName())) {
                                return lastNode = new NewPrototypeNode(descr);
                            }
                            lastNode = new NewObjectNode(descr, fields, pCtx);
                            skipWhitespace();
                            if (cursor != end && expr[cursor] == '{') {
                                if (!((NewObjectNode) lastNode).getTypeDescr().isUndimensionedArray()) {
                                    throw new CompileException("conflicting syntax: dimensioned array with initializer block", expr, st);
                                }
                                st = cursor;
                                Class egressType = lastNode.getEgressType();
                                if (egressType == null) {
                                    try {
                                        egressType = getClassReference(pCtx, descr);
                                    } catch (ClassNotFoundException e) {
                                        throw new CompileException("could not instantiate class", expr, st, e);
                                    }
                                }
                                cursor = balancedCaptureWithLineAccounting(expr, st, end, expr[cursor], pCtx) + 1;
                                if (tokenContinues()) {
                                    lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, egressType, pCtx);
                                    st = cursor;
                                    captureToEOT();
                                    return lastNode = new Union(expr, st + 1, cursor, fields, lastNode);
                                } else {
                                    return lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, egressType, pCtx);
                                }
                            } else if (((NewObjectNode) lastNode).getTypeDescr().isUndimensionedArray()) {
                                throw new CompileException("array initializer expected", expr, st);
                            }
                            st = cursor;
                            return lastNode;
                        case ASSERT:
                            st = cursor = trimRight(cursor);
                            captureToEOS();
                            return lastNode = new AssertNode(expr, st, cursor-- - st, fields, pCtx);
                        case RETURN:
                            st = cursor = trimRight(cursor);
                            captureToEOS();
                            return lastNode = new ReturnNode(expr, st, cursor - st, fields, pCtx);
                        case IF:
                            return captureCodeBlock(ASTNode.BLOCK_IF);
                        case ELSE:
                            throw new CompileException("else without if", expr, st);
                        case FOREACH:
                            return captureCodeBlock(ASTNode.BLOCK_FOREACH);
                        case WHILE:
                            return captureCodeBlock(ASTNode.BLOCK_WHILE);
                        case UNTIL:
                            return captureCodeBlock(ASTNode.BLOCK_UNTIL);
                        case FOR:
                            return captureCodeBlock(ASTNode.BLOCK_FOR);
                        case WITH:
                            return captureCodeBlock(ASTNode.BLOCK_WITH);
                        case DO:
                            return captureCodeBlock(ASTNode.BLOCK_DO);
                        case PROTO:
                            return captureCodeBlock(PROTO);
                        case ISDEF:
                            st = cursor = trimRight(cursor);
                            captureToNextTokenJunction();
                            return lastNode = new IsDef(expr, st, cursor - st);
                        case IMPORT:
                            st = cursor = trimRight(cursor);
                            captureToEOS();
                            ImportNode importNode = new ImportNode(expr, st, cursor - st);
                            if (pCtx == null)
                                pCtx = getParserContext();
                            if (importNode.isPackageImport()) {
                                pCtx.addPackageImport(importNode.getPackageImport());
                            } else {
                                pCtx.addImport(importNode.getImportClass().getSimpleName(), importNode.getImportClass());
                            }
                            return lastNode = importNode;
                        case IMPORT_STATIC:
                            st = cursor = trimRight(cursor);
                            captureToEOS();
                            return lastNode = new StaticImportNode(expr, st, trimLeft(cursor) - st);
                        case FUNCTION:
                            lastNode = captureCodeBlock(FUNCTION);
                            st = cursor + 1;
                            return lastNode;
                        case UNTYPED_VAR:
                            int end;
                            st = cursor + 1;
                            while (true) {
                                captureToEOT();
                                end = cursor;
                                skipWhitespace();
                                if (cursor != end && expr[cursor] == '=') {
                                    if (end == (cursor = st))
                                        throw new CompileException("illegal use of reserved word: var", expr, st);
                                    continue Mainloop;
                                } else {
                                    name = new String(expr, st, end - st);
                                    if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                        splitAccumulator.add(lastNode = new IndexedDeclTypedVarNode(idx, st, end - st, Object.class));
                                    } else {
                                        splitAccumulator.add(lastNode = new DeclTypedVarNode(name, expr, st, end - st, Object.class, fields, pCtx));
                                    }
                                }
                                if (cursor == this.end || expr[cursor] != ',')
                                    break;
                                else {
                                    cursor++;
                                    skipWhitespace();
                                    st = cursor;
                                }
                            }
                            return (ASTNode) splitAccumulator.pop();
                    }
                }
                skipWhitespace();
                /**
           * If we *were* capturing a token, and we just hit a non-identifier
           * character, we stop and figure out what to do.
           */
                if (cursor != end && expr[cursor] == '(') {
                    cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx) + 1;
                }
                /**
           * If we encounter any of the following cases, we are still dealing with
           * a contiguous token.
           */
                CaptureLoop: while (cursor != end) {
                    switch(expr[cursor]) {
                        case '.':
                            union = true;
                            cursor++;
                            skipWhitespace();
                            continue;
                        case '?':
                            if (lookToLast() == '.') {
                                union = true;
                                cursor++;
                                continue;
                            } else {
                                break CaptureLoop;
                            }
                        case '+':
                            switch(lookAhead()) {
                                case '+':
                                    name = new String(subArray(st, trimLeft(cursor)));
                                    if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                        lastNode = new IndexedPostFixIncNode(idx, pCtx);
                                    } else {
                                        lastNode = new PostFixIncNode(name, pCtx);
                                    }
                                    cursor += 2;
                                    expectEOS();
                                    return lastNode;
                                case '=':
                                    name = createStringTrimmed(expr, st, cursor - st);
                                    st = cursor += 2;
                                    captureToEOS();
                                    if (union) {
                                        return lastNode = new DeepAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, fields, ADD, name, pCtx);
                                    } else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                        return lastNode = new IndexedAssignmentNode(expr, st, cursor - st, fields, ADD, name, idx, pCtx);
                                    } else {
                                        return lastNode = new OperativeAssign(name, expr, st = trimRight(st), trimLeft(cursor) - st, ADD, fields, pCtx);
                                    }
                            }
                            if (isDigit(lookAhead()) && cursor > 1 && (expr[cursor - 1] == 'E' || expr[cursor - 1] == 'e') && isDigit(expr[cursor - 2])) {
                                cursor++;
                                //     capture = true;
                                continue Mainloop;
                            }
                            break CaptureLoop;
                        case '-':
                            switch(lookAhead()) {
                                case '-':
                                    name = new String(subArray(st, trimLeft(cursor)));
                                    if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                        lastNode = new IndexedPostFixDecNode(idx, pCtx);
                                    } else {
                                        lastNode = new PostFixDecNode(name, pCtx);
                                    }
                                    cursor += 2;
                                    expectEOS();
                                    return lastNode;
                                case '=':
                                    name = new String(expr, st, trimLeft(cursor) - st);
                                    st = cursor += 2;
                                    captureToEOS();
                                    if (union) {
                                        return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, SUB, t, pCtx);
                                    } else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                        return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, SUB, idx, fields, pCtx);
                                    } else {
                                        return lastNode = new OperativeAssign(name, expr, st, cursor - st, SUB, fields, pCtx);
                                    }
                            }
                            if (isDigit(lookAhead()) && cursor > 1 && (expr[cursor - 1] == 'E' || expr[cursor - 1] == 'e') && isDigit(expr[cursor - 2])) {
                                cursor++;
                                capture = true;
                                continue Mainloop;
                            }
                            break CaptureLoop;
                        /**
               * Exit immediately for any of these cases.
               */
                        case '!':
                        case ',':
                        case '"':
                        case '\'':
                        case ';':
                        case ':':
                            break CaptureLoop;
                        // special compact code for recursive parses
                        case '«':
                        case '»':
                        case '¬':
                        case '&':
                        case '^':
                        case '|':
                        case '*':
                        case '/':
                        case '%':
                            char op = expr[cursor];
                            if (lookAhead() == '=') {
                                name = new String(expr, st, trimLeft(cursor) - st);
                                st = cursor += 2;
                                captureToEOS();
                                if (union) {
                                    return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, opLookup(op), t, pCtx);
                                } else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                    return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, opLookup(op), idx, fields, pCtx);
                                } else {
                                    return lastNode = new OperativeAssign(name, expr, st, cursor - st, opLookup(op), fields, pCtx);
                                }
                            }
                            break CaptureLoop;
                        case '<':
                            if ((lookAhead() == '<' && lookAhead(2) == '=')) {
                                name = new String(expr, st, trimLeft(cursor) - st);
                                st = cursor += 3;
                                captureToEOS();
                                if (union) {
                                    return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_SHIFT_LEFT, t, pCtx);
                                } else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                    return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_SHIFT_LEFT, idx, fields, pCtx);
                                } else {
                                    return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_SHIFT_LEFT, fields, pCtx);
                                }
                            }
                            break CaptureLoop;
                        case '>':
                            if (lookAhead() == '>') {
                                if (lookAhead(2) == '=') {
                                    name = new String(expr, st, trimLeft(cursor) - st);
                                    st = cursor += 3;
                                    captureToEOS();
                                    if (union) {
                                        return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_SHIFT_RIGHT, t, pCtx);
                                    } else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                        return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_SHIFT_RIGHT, idx, fields, pCtx);
                                    } else {
                                        return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_SHIFT_RIGHT, fields, pCtx);
                                    }
                                } else if ((lookAhead(2) == '>' && lookAhead(3) == '=')) {
                                    name = new String(expr, st, trimLeft(cursor) - st);
                                    st = cursor += 4;
                                    captureToEOS();
                                    if (union) {
                                        return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields, BW_USHIFT_RIGHT, t, pCtx);
                                    } else if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                        return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, BW_USHIFT_RIGHT, idx, fields, pCtx);
                                    } else {
                                        return lastNode = new OperativeAssign(name, expr, st, cursor - st, BW_USHIFT_RIGHT, fields, pCtx);
                                    }
                                }
                            }
                            break CaptureLoop;
                        case '(':
                            cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '(', pCtx) + 1;
                            continue;
                        case '[':
                            cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '[', pCtx) + 1;
                            continue;
                        case '{':
                            if (!union)
                                break CaptureLoop;
                            cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx) + 1;
                            continue;
                        case '~':
                            if (lookAhead() == '=') {
                                // tmp = subArray(start, trimLeft(cursor));
                                tmpStart = st;
                                int tmpOffset = cursor - st;
                                st = cursor += 2;
                                captureToEOT();
                                return lastNode = new RegExMatch(expr, tmpStart, tmpOffset, fields, st, cursor - st, pCtx);
                            }
                            break CaptureLoop;
                        case '=':
                            if (lookAhead() == '+') {
                                name = new String(expr, st, trimLeft(cursor) - st);
                                st = cursor += 2;
                                if (!isNextIdentifierOrLiteral()) {
                                    throw new CompileException("unexpected symbol '" + expr[cursor] + "'", expr, st);
                                }
                                captureToEOS();
                                if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                    return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, ADD, idx, fields, pCtx);
                                } else {
                                    return lastNode = new OperativeAssign(name, expr, st, cursor - st, ADD, fields, pCtx);
                                }
                            } else if (lookAhead() == '-') {
                                name = new String(expr, st, trimLeft(cursor) - st);
                                st = cursor += 2;
                                if (!isNextIdentifierOrLiteral()) {
                                    throw new CompileException("unexpected symbol '" + expr[cursor] + "'", expr, st);
                                }
                                captureToEOS();
                                if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                    return lastNode = new IndexedOperativeAssign(expr, st, cursor - st, SUB, idx, fields, pCtx);
                                } else {
                                    return lastNode = new OperativeAssign(name, expr, st, cursor - st, SUB, fields, pCtx);
                                }
                            }
                            if (greedy && lookAhead() != '=') {
                                cursor++;
                                if (union) {
                                    captureToEOS();
                                    return lastNode = new DeepAssignmentNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, pCtx);
                                } else if (lastWasIdentifier) {
                                    return procTypedNode(false);
                                } else if (pCtx != null && ((idx = pCtx.variableIndexOf(t)) != -1 && (pCtx.isIndexAllocation()))) {
                                    captureToEOS();
                                    IndexedAssignmentNode ian = new IndexedAssignmentNode(expr, st = trimRight(st), trimLeft(cursor) - st, ASTNode.ASSIGN, idx, pCtx);
                                    if (idx == -1) {
                                        pCtx.addIndexedInput(t = ian.getAssignmentVar());
                                        ian.setRegister(pCtx.variableIndexOf(t));
                                    }
                                    return lastNode = ian;
                                } else {
                                    captureToEOS();
                                    return lastNode = new AssignmentNode(expr, st, cursor - st, fields | ASTNode.ASSIGN, pCtx);
                                }
                            }
                            break CaptureLoop;
                        default:
                            if (cursor != end) {
                                if (isIdentifierPart(expr[cursor])) {
                                    if (!union) {
                                        break CaptureLoop;
                                    }
                                    cursor++;
                                    while (cursor != end && isIdentifierPart(expr[cursor])) cursor++;
                                } else if ((cursor + 1) != end && isIdentifierPart(expr[cursor + 1])) {
                                    break CaptureLoop;
                                } else {
                                    cursor++;
                                }
                            } else {
                                break CaptureLoop;
                            }
                    }
                }
                /**
           * Produce the token.
           */
                trimWhitespace();
                return createPropertyToken(st, cursor);
            } else {
                switch(expr[cursor]) {
                    case '.':
                        {
                            cursor++;
                            if (isDigit(expr[cursor])) {
                                capture = true;
                                continue;
                            }
                            expectNextChar_IW('{');
                            return lastNode = new ThisWithNode(expr, st, cursor - st - 1, cursor + 1, (cursor = balancedCaptureWithLineAccounting(expr, cursor, end, '{', pCtx) + 1) - 3, fields, pCtx);
                        }
                    case '@':
                        {
                            st++;
                            captureToEOT();
                            if (pCtx == null || (pCtx.getInterceptors() == null || !pCtx.getInterceptors().containsKey(name = new String(expr, st, cursor - st)))) {
                                throw new CompileException("reference to undefined interceptor: " + new String(expr, st, cursor - st), expr, st);
                            }
                            return lastNode = new InterceptorWrapper(pCtx.getInterceptors().get(name), nextToken());
                        }
                    case '=':
                        return createOperator(expr, st, (cursor += 2));
                    case '-':
                        if (lookAhead() == '-') {
                            cursor += 2;
                            skipWhitespace();
                            st = cursor;
                            captureIdentifier();
                            name = new String(subArray(st, cursor));
                            if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                return lastNode = new IndexedPreFixDecNode(idx, pCtx);
                            } else {
                                return lastNode = new PreFixDecNode(name, pCtx);
                            }
                        } else if ((cursor == start || (lastNode != null && (lastNode instanceof BooleanNode || lastNode.isOperator()))) && !isDigit(lookAhead())) {
                            captureToEOT();
                            return new Sign(expr, st, cursor - st, fields, pCtx);
                        } else if ((cursor != start && !isWhitespace(expr[cursor - 1]) && (!(lastNode != null && (lastNode instanceof BooleanNode || lastNode.isOperator())))) || !isDigit(lookAhead())) {
                            return createOperator(expr, st, cursor++ + 1);
                        } else if ((cursor - 1) != start || (!isDigit(expr[cursor - 1])) && isDigit(lookAhead())) {
                            cursor++;
                            break;
                        } else {
                            throw new CompileException("not a statement", expr, st);
                        }
                    case '+':
                        if (lookAhead() == '+') {
                            cursor += 2;
                            skipWhitespace();
                            st = cursor;
                            captureIdentifier();
                            name = new String(subArray(st, cursor));
                            if (pCtx != null && (idx = pCtx.variableIndexOf(name)) != -1) {
                                return lastNode = new IndexedPreFixIncNode(idx, pCtx);
                            } else {
                                return lastNode = new PreFixIncNode(name, pCtx);
                            }
                        }
                        return createOperator(expr, st, cursor++ + 1);
                    case '*':
                        if (lookAhead() == '*') {
                            cursor++;
                        }
                        return createOperator(expr, st, cursor++ + 1);
                    case ';':
                        cursor++;
                        lastWasIdentifier = false;
                        return lastNode = new EndOfStatement();
                    case '#':
                    case '/':
                    case '?':
                    case ':':
                    case '^':
                    case '%':
                        {
                            return createOperator(expr, st, cursor++ + 1);
                        }
                    case '(':
                        {
                            cursor++;
                            boolean singleToken = true;
                            skipWhitespace();
                            for (brace = 1; cursor != end && brace != 0; cursor++) {
                                switch(expr[cursor]) {
                                    case '(':
                                        brace++;
                                        break;
                                    case ')':
                                        brace--;
                                        break;
                                    case '\'':
                                        cursor = captureStringLiteral('\'', expr, cursor, end);
                                        break;
                                    case '"':
                                        cursor = captureStringLiteral('"', expr, cursor, end);
                                        break;
                                    case 'i':
                                        if (brace == 1 && isWhitespace(lookBehind()) && lookAhead() == 'n' && isWhitespace(lookAhead(2))) {
                                            for (int level = brace; cursor != end; cursor++) {
                                                switch(expr[cursor]) {
                                                    case '(':
                                                        brace++;
                                                        break;
                                                    case ')':
                                                        if (--brace < level) {
                                                            cursor++;
                                                            if (tokenContinues()) {
                                                                lastNode = new Fold(expr, trimRight(st + 1), cursor - st - 2, fields, pCtx);
                                                                if (expr[st = cursor] == '.')
                                                                    st++;
                                                                captureToEOT();
                                                                return lastNode = new Union(expr, st = trimRight(st), cursor - st, fields, lastNode);
                                                            } else {
                                                                return lastNode = new Fold(expr, trimRight(st + 1), cursor - st - 2, fields, pCtx);
                                                            }
                                                        }
                                                        break;
                                                    case '\'':
                                                        cursor = captureStringLiteral('\'', expr, cursor, end);
                                                        break;
                                                    case '"':
                                                        cursor = captureStringLiteral('\"', expr, cursor, end);
                                                        break;
                                                }
                                            }
                                            throw new CompileException("unterminated projection; closing parathesis required", expr, st);
                                        }
                                        break;
                                    default:
                                        if (expr[cursor] != '.') {
                                            switch(expr[cursor]) {
                                                case '[':
                                                case ']':
                                                    break;
                                                default:
                                                    if (!(isIdentifierPart(expr[cursor]) || expr[cursor] == '.')) {
                                                        singleToken = false;
                                                    }
                                            }
                                        }
                                }
                            }
                            if (brace != 0) {
                                throw new CompileException("unbalanced braces in expression: (" + brace + "):", expr, st);
                            }
                            tmpStart = -1;
                            if (singleToken) {
                                int _st;
                                TypeDescriptor tDescr = new TypeDescriptor(expr, _st = trimRight(st + 1), trimLeft(cursor - 1) - _st, fields);
                                Class cls;
                                try {
                                    if (tDescr.isClass() && (cls = getClassReference(pCtx, tDescr)) != null) {
                                        st = cursor;
                                        captureToEOS();
                                        return lastNode = new TypeCast(expr, st, cursor - st, cls, fields, pCtx);
                                    }
                                } catch (ClassNotFoundException e) {
                                // fallthrough
                                }
                            }
                            if (tmpStart != -1) {
                                return handleUnion(handleSubstatement(new Substatement(expr, tmpStart, cursor - tmpStart, fields, pCtx)));
                            } else {
                                return handleUnion(handleSubstatement(new Substatement(expr, st = trimRight(st + 1), trimLeft(cursor - 1) - st, fields, pCtx)));
                            }
                        }
                    case '}':
                    case ']':
                    case ')':
                        {
                            throw new CompileException("unbalanced braces", expr, st);
                        }
                    case '>':
                        {
                            switch(expr[cursor + 1]) {
                                case '>':
                                    if (expr[cursor += 2] == '>')
                                        cursor++;
                                    return createOperator(expr, st, cursor);
                                case '=':
                                    return createOperator(expr, st, cursor += 2);
                                default:
                                    return createOperator(expr, st, ++cursor);
                            }
                        }
                    case '<':
                        {
                            if (expr[++cursor] == '<') {
                                if (expr[++cursor] == '<')
                                    cursor++;
                                return createOperator(expr, st, cursor);
                            } else if (expr[cursor] == '=') {
                                return createOperator(expr, st, ++cursor);
                            } else {
                                return createOperator(expr, st, cursor);
                            }
                        }
                    case '\'':
                    case '"':
                        lastNode = new LiteralNode(handleStringEscapes(subset(expr, st + 1, (cursor = captureStringLiteral(expr[cursor], expr, cursor, end)) - st - 1)), String.class);
                        cursor++;
                        if (tokenContinues()) {
                            return lastNode = handleUnion(lastNode);
                        }
                        return lastNode;
                    case '&':
                        {
                            if (expr[cursor++ + 1] == '&') {
                                return createOperator(expr, st, ++cursor);
                            } else {
                                return createOperator(expr, st, cursor);
                            }
                        }
                    case '|':
                        {
                            if (expr[cursor++ + 1] == '|') {
                                return createOperator(expr, st, ++cursor);
                            } else {
                                return createOperator(expr, st, cursor);
                            }
                        }
                    case '~':
                        if ((cursor++ - 1 != 0 || !isIdentifierPart(lookBehind())) && isDigit(expr[cursor])) {
                            st = cursor;
                            captureToEOT();
                            return lastNode = new Invert(expr, st, cursor - st, fields, pCtx);
                        } else if (expr[cursor] == '(') {
                            st = cursor--;
                            captureToEOT();
                            return lastNode = new Invert(expr, st, cursor - st, fields, pCtx);
                        } else {
                            if (expr[cursor] == '=')
                                cursor++;
                            return createOperator(expr, st, cursor);
                        }
                    case '!':
                        {
                            ++cursor;
                            if (isNextIdentifier()) {
                                if (lastNode != null && !lastNode.isOperator()) {
                                    throw new CompileException("unexpected operator '!'", expr, st);
                                }
                                st = cursor;
                                captureToEOT();
                                if ("new".equals(name = new String(expr, st, cursor - st)) || "isdef".equals(name)) {
                                    captureToEOT();
                                    return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
                                } else {
                                    return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
                                }
                            } else if (expr[cursor] == '(') {
                                st = cursor--;
                                captureToEOT();
                                return lastNode = new Negation(expr, st, cursor - st, fields, pCtx);
                            } else if (expr[cursor] != '=')
                                throw new CompileException("unexpected operator '!'", expr, st, null);
                            else {
                                return createOperator(expr, st, ++cursor);
                            }
                        }
                    case '[':
                    case '{':
                        cursor = balancedCaptureWithLineAccounting(expr, cursor, end, expr[cursor], pCtx) + 1;
                        if (tokenContinues()) {
                            lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, pCtx);
                            st = cursor;
                            captureToEOT();
                            if (expr[st] == '.')
                                st++;
                            return lastNode = new Union(expr, st, cursor - st, fields, lastNode);
                        } else {
                            return lastNode = new InlineCollectionNode(expr, st, cursor - st, fields, pCtx);
                        }
                    default:
                        cursor++;
                }
            }
        }
        if (st == cursor)
            return null;
        else
            return createPropertyToken(st, cursor);
    } catch (RedundantCodeException e) {
        return nextToken();
    } catch (NumberFormatException e) {
        throw new CompileException("badly formatted number: " + e.getMessage(), expr, st, e);
    } catch (StringIndexOutOfBoundsException e) {
        throw new CompileException("unexpected end of statement", expr, cursor, e);
    } catch (ArrayIndexOutOfBoundsException e) {
        throw new CompileException("unexpected end of statement", expr, cursor, e);
    } catch (CompileException e) {
        throw ErrorUtil.rewriteIfNeeded(e, expr, cursor);
    }
}
Also used : CompileException(org.mvel2.CompileException)

Example 2 with Union

use of org.mvel2.optimizers.impl.refl.nodes.Union in project mvel by mikebrock.

the class ASMAccessorOptimizer method optimizeCollection.

public Accessor optimizeCollection(ParserContext pCtx, Object o, Class type, char[] property, int start, int offset, Object ctx, Object thisRef, VariableResolverFactory factory) {
    this.expr = property;
    this.cursor = this.start = start;
    this.end = start + offset;
    this.length = offset;
    this.returnType = type;
    this.compiledInputs = new ArrayList<ExecutableStatement>();
    this.ctx = ctx;
    this.thisRef = thisRef;
    this.variableFactory = factory;
    _initJIT();
    literal = true;
    _getAccessor(o, type);
    _finishJIT();
    try {
        Accessor compiledAccessor = _initializeAccessor();
        if (property != null && length > start) {
            return new Union(compiledAccessor, property, start, length);
        } else {
            return compiledAccessor;
        }
    } catch (Exception e) {
        throw new OptimizationFailure("could not optimize collection", e);
    }
}
Also used : PropertyTools.getFieldOrWriteAccessor(org.mvel2.util.PropertyTools.getFieldOrWriteAccessor) PropertyTools.getFieldOrAccessor(org.mvel2.util.PropertyTools.getFieldOrAccessor) Union(org.mvel2.optimizers.impl.refl.nodes.Union) IOException(java.io.IOException)

Example 3 with Union

use of org.mvel2.optimizers.impl.refl.nodes.Union in project mvel by mikebrock.

the class ASMAccessorOptimizer method optimizeObjectCreation.

public Accessor optimizeObjectCreation(ParserContext pCtx, char[] property, int start, int offset, Object ctx, Object thisRef, VariableResolverFactory factory) {
    _initJIT();
    compiledInputs = new ArrayList<ExecutableStatement>();
    this.start = cursor = start;
    this.end = start + offset;
    this.length = this.end - this.start;
    this.ctx = ctx;
    this.thisRef = thisRef;
    this.variableFactory = factory;
    this.pCtx = pCtx;
    String[] cnsRes = captureContructorAndResidual(property, start, offset);
    List<char[]> constructorParms = parseMethodOrConstructor(cnsRes[0].toCharArray());
    try {
        if (constructorParms != null) {
            for (char[] constructorParm : constructorParms) {
                compiledInputs.add((ExecutableStatement) subCompileExpression(constructorParm, pCtx));
            }
            Class cls = findClass(factory, new String(subset(property, 0, findFirst('(', start, length, property))), pCtx);
            assert debug("NEW " + getInternalName(cls));
            mv.visitTypeInsn(NEW, getInternalName(cls));
            assert debug("DUP");
            mv.visitInsn(DUP);
            Object[] parms = new Object[constructorParms.size()];
            int i = 0;
            for (ExecutableStatement es : compiledInputs) {
                parms[i++] = es.getValue(ctx, factory);
            }
            Constructor cns = getBestConstructorCandidate(parms, cls, pCtx.isStrongTyping());
            if (cns == null) {
                StringBuilder error = new StringBuilder();
                for (int x = 0; x < parms.length; x++) {
                    error.append(parms[x].getClass().getName());
                    if (x + 1 < parms.length)
                        error.append(", ");
                }
                throw new CompileException("unable to find constructor: " + cls.getName() + "(" + error.toString() + ")", expr, st);
            }
            this.returnType = cns.getDeclaringClass();
            Class tg;
            for (i = 0; i < constructorParms.size(); i++) {
                assert debug("ALOAD 0");
                mv.visitVarInsn(ALOAD, 0);
                assert debug("GETFIELD p" + i);
                mv.visitFieldInsn(GETFIELD, className, "p" + i, "L" + NAMESPACE + "compiler/ExecutableStatement;");
                assert debug("ALOAD 2");
                mv.visitVarInsn(ALOAD, 2);
                assert debug("ALOAD 3");
                mv.visitVarInsn(ALOAD, 3);
                assert debug("INVOKEINTERFACE " + NAMESPACE + "compiler/ExecutableStatement.getValue");
                mv.visitMethodInsn(INVOKEINTERFACE, "" + NAMESPACE + "compiler/ExecutableStatement", "getValue", "(Ljava/lang/Object;L" + NAMESPACE + "integration/VariableResolverFactory;)Ljava/lang/Object;");
                tg = cns.getParameterTypes()[i].isPrimitive() ? getWrapperClass(cns.getParameterTypes()[i]) : cns.getParameterTypes()[i];
                if (parms[i] != null && !parms[i].getClass().isAssignableFrom(cns.getParameterTypes()[i])) {
                    ldcClassConstant(tg);
                    assert debug("INVOKESTATIC " + NAMESPACE + "DataConversion.convert");
                    mv.visitMethodInsn(INVOKESTATIC, "" + NAMESPACE + "DataConversion", "convert", "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
                    if (cns.getParameterTypes()[i].isPrimitive()) {
                        unwrapPrimitive(cns.getParameterTypes()[i]);
                    } else {
                        assert debug("CHECKCAST " + getInternalName(tg));
                        mv.visitTypeInsn(CHECKCAST, getInternalName(tg));
                    }
                } else {
                    assert debug("CHECKCAST " + getInternalName(cns.getParameterTypes()[i]));
                    mv.visitTypeInsn(CHECKCAST, getInternalName(cns.getParameterTypes()[i]));
                }
            }
            assert debug("INVOKESPECIAL " + getInternalName(cls) + ".<init> : " + getConstructorDescriptor(cns));
            mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls), "<init>", getConstructorDescriptor(cns));
            _finishJIT();
            Accessor acc = _initializeAccessor();
            if (cnsRes.length > 1 && cnsRes[1] != null && !cnsRes[1].trim().equals("")) {
                return new Union(acc, cnsRes[1].toCharArray(), 0, cnsRes[1].length());
            }
            return acc;
        } else {
            Class cls = findClass(factory, new String(property), pCtx);
            assert debug("NEW " + getInternalName(cls));
            mv.visitTypeInsn(NEW, getInternalName(cls));
            assert debug("DUP");
            mv.visitInsn(DUP);
            Constructor cns = cls.getConstructor(EMPTYCLS);
            assert debug("INVOKESPECIAL <init>");
            mv.visitMethodInsn(INVOKESPECIAL, getInternalName(cls), "<init>", getConstructorDescriptor(cns));
            _finishJIT();
            Accessor acc = _initializeAccessor();
            if (cnsRes.length > 1 && cnsRes[1] != null && !cnsRes[1].trim().equals("")) {
                return new Union(acc, cnsRes[1].toCharArray(), 0, cnsRes[1].length());
            }
            return acc;
        }
    } catch (ClassNotFoundException e) {
        throw new CompileException("class or class reference not found: " + new String(property), property, st);
    } catch (Exception e) {
        throw new OptimizationFailure("could not optimize construtor: " + new String(property), e);
    }
}
Also used : PropertyTools.getFieldOrWriteAccessor(org.mvel2.util.PropertyTools.getFieldOrWriteAccessor) PropertyTools.getFieldOrAccessor(org.mvel2.util.PropertyTools.getFieldOrAccessor) Union(org.mvel2.optimizers.impl.refl.nodes.Union) IOException(java.io.IOException)

Example 4 with Union

use of org.mvel2.optimizers.impl.refl.nodes.Union in project mvel by mikebrock.

the class AbstractOptimizer method tryStaticAccess.

/**
   * Try static access of the property, and return an instance of the Field, Method of Class if successful.
   *
   * @return - Field, Method or Class instance.
   */
protected Object tryStaticAccess() {
    int begin = cursor;
    try {
        /**
       * Try to resolve this *smartly* as a static class reference.
       *
       * This starts at the end of the token and starts to step backwards to figure out whether
       * or not this may be a static class reference.  We search for method calls simply by
       * inspecting for ()'s.  The first union area we come to where no brackets are present is our
       * test-point for a class reference.  If we find a class, we pass the reference to the
       * property accessor along  with trailing methods (if any).
       *
       */
        boolean meth = false;
        // int end = start + length;
        int last = end;
        for (int i = end - 1; i > start; i--) {
            switch(expr[i]) {
                case '.':
                    if (!meth) {
                        try {
                            String test = new String(expr, start, (cursor = last) - start);
                            return Class.forName(test, true, pCtx != null ? pCtx.getParserConfiguration().getClassLoader() : currentThread().getContextClassLoader());
                        } catch (ClassNotFoundException e) {
                            Class cls = Class.forName(new String(expr, start, i - start), true, pCtx != null ? pCtx.getParserConfiguration().getClassLoader() : currentThread().getContextClassLoader());
                            String name = new String(expr, i + 1, end - i - 1);
                            try {
                                return cls.getField(name);
                            } catch (NoSuchFieldException nfe) {
                                for (Method m : cls.getMethods()) {
                                    if (name.equals(m.getName()))
                                        return m;
                                }
                                return null;
                            }
                        }
                    }
                    meth = false;
                    last = i;
                    break;
                case '}':
                    i--;
                    for (int d = 1; i > start && d != 0; i--) {
                        switch(expr[i]) {
                            case '}':
                                d++;
                                break;
                            case '{':
                                d--;
                                break;
                            case '"':
                            case '\'':
                                char s = expr[i];
                                while (i > start && (expr[i] != s && expr[i - 1] != '\\')) i--;
                        }
                    }
                    break;
                case ')':
                    i--;
                    for (int d = 1; i > start && d != 0; i--) {
                        switch(expr[i]) {
                            case ')':
                                d++;
                                break;
                            case '(':
                                d--;
                                break;
                            case '"':
                            case '\'':
                                char s = expr[i];
                                while (i > start && (expr[i] != s && expr[i - 1] != '\\')) i--;
                        }
                    }
                    meth = true;
                    last = i++;
                    break;
                case '\'':
                    while (--i > start) {
                        if (expr[i] == '\'' && expr[i - 1] != '\\') {
                            break;
                        }
                    }
                    break;
                case '"':
                    while (--i > start) {
                        if (expr[i] == '"' && expr[i - 1] != '\\') {
                            break;
                        }
                    }
                    break;
            }
        }
    } catch (Exception cnfe) {
        cursor = begin;
    }
    return null;
}
Also used : Method(java.lang.reflect.Method) CompileException(org.mvel2.CompileException)

Example 5 with Union

use of org.mvel2.optimizers.impl.refl.nodes.Union in project mvel by mikebrock.

the class ReflectiveAccessorOptimizer method optimizeCollection.

public Accessor optimizeCollection(ParserContext pCtx, Object o, Class type, char[] property, int start, int offset, Object ctx, Object thisRef, VariableResolverFactory factory) {
    this.start = this.cursor = start;
    this.length = start + offset;
    this.returnType = type;
    this.ctx = ctx;
    this.variableFactory = factory;
    this.pCtx = pCtx;
    Accessor root = _getAccessor(o, returnType);
    if (property != null && length > start) {
        return new Union(root, property, cursor, offset);
    } else {
        return root;
    }
}
Also used : PropertyTools.getFieldOrWriteAccessor(org.mvel2.util.PropertyTools.getFieldOrWriteAccessor) ExprValueAccessor(org.mvel2.optimizers.impl.refl.collection.ExprValueAccessor) PropertyTools.getFieldOrAccessor(org.mvel2.util.PropertyTools.getFieldOrAccessor) Accessor(org.mvel2.compiler.Accessor)

Aggregations

PropertyTools.getFieldOrAccessor (org.mvel2.util.PropertyTools.getFieldOrAccessor)3 PropertyTools.getFieldOrWriteAccessor (org.mvel2.util.PropertyTools.getFieldOrWriteAccessor)3 IOException (java.io.IOException)2 CompileException (org.mvel2.CompileException)2 Union (org.mvel2.optimizers.impl.refl.nodes.Union)2 Method (java.lang.reflect.Method)1 Accessor (org.mvel2.compiler.Accessor)1 ExprValueAccessor (org.mvel2.optimizers.impl.refl.collection.ExprValueAccessor)1