public static MVELAnalysisResult analyzeExpression()

in drools-mvel/src/main/java/org/drools/mvel/builder/MVELExprAnalyzer.java [86:236]


    public static MVELAnalysisResult analyzeExpression(final PackageBuildContext context,
                                                       final String expr,
                                                       final BoundIdentifiers availableIdentifiers,
                                                       final Map<String, Class< ? >> localTypes,
                                                       String contextIdentifier,
                                                       Class kcontextClass) {
        if ( expr.trim().length() <= 0 ) {
            MVELAnalysisResult result = analyze( (Set<String>) Collections.EMPTY_SET, availableIdentifiers );
            result.setMvelVariables( new HashMap<>() );
            result.setTypesafe( true );
            return result;
        }

        MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;
        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;
        MVEL.COMPILER_OPT_ALLOW_RESOLVE_INNERCLASSES_WITH_DOTNOTATION = true;
        MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS = true;

        MVELDialect dialect = (MVELDialect) context.getDialect( "mvel" );

        ParserConfiguration conf = getMVELDialectRuntimeData(context).getParserConfiguration();

        conf.setClassLoader( context.getKnowledgeBuilder().getRootClassLoader() );

        // first compilation is for verification only
        // @todo proper source file name
        final ParserContext parserContext1 = new ParserContext( conf );
        if ( localTypes != null ) {
            for ( Entry entry : localTypes.entrySet() ) {
                parserContext1.addInput( (String) entry.getKey(),
                                         (Class) entry.getValue() );
            }
        }
        if ( availableIdentifiers.getThisClass() != null ) {
            parserContext1.addInput( "this",
                                     availableIdentifiers.getThisClass() );
        }

        if ( availableIdentifiers.getOperators() != null ) {
            for ( Entry<String, EvaluatorWrapper> opEntry : availableIdentifiers.getOperators().entrySet() ) {
                parserContext1.addInput( opEntry.getKey(), opEntry.getValue().getClass() );
            }
        }

        parserContext1.setStrictTypeEnforcement( false );
        parserContext1.setStrongTyping( false );
        Class< ? > returnType;

        try {
            returnType = MVEL.analyze( expr,
                                       parserContext1 );
        } catch ( Exception e ) {
            BaseDescr base = (context instanceof RuleBuildContext) ? ((RuleBuildContext)context).getRuleDescr() : context.getParentDescr();
            if ( e instanceof CompileException && e.getCause() != null && e.getMessage().startsWith( "[Error: null]" )) {
                // rewrite error message in cause original message is null
                e = new CompileException(e.getCause().toString(), ( (CompileException) e ).getExpr(), ( (CompileException) e ).getCursor(), e.getCause());
            }
            AsmUtil.copyErrorLocation(e, context.getParentDescr());
            context.addError( new DescrBuildError( base,
                                                   context.getParentDescr(),
                                                   null,
                                                   "Unable to Analyse Expression " + expr + ":\n" + e.getMessage() ) );
            return null;
        }

        Set<String> requiredInputs = new HashSet<>();
        requiredInputs.addAll( parserContext1.getInputs().keySet() );
        HashMap<String, Class< ? >> variables = (HashMap<String, Class< ? >>) ((Map) parserContext1.getVariables());
        if ( localTypes != null ) {
            for ( String str : localTypes.keySet() ) {
                // we have to do this due to mvel regressions on detecting true local vars
                variables.remove( str );
            }
        }

        // MVEL includes direct fields of context object in non-strict mode. so we need to strip those
        if ( availableIdentifiers.getThisClass() != null ) {
            requiredInputs.removeIf( s -> PropertyTools.getFieldOrAccessor( availableIdentifiers.getThisClass(), s ) != null );
        }

        // now, set the required input types and compile again
        final ParserContext parserContext2 = new ParserContext( conf );
        parserContext2.setStrictTypeEnforcement( true );
        parserContext2.setStrongTyping( true );

        for ( String input : requiredInputs ) {
            if ("this".equals( input )) {
                continue;
            }
            if (WM_ARGUMENT.equals( input )) {
                parserContext2.addInput( input, InternalWorkingMemory.class );
                continue;
            }

            Class< ? > cls = availableIdentifiers.resolveType( input );
            if ( cls == null ) {
                if ( input.equals( contextIdentifier ) || input.equals( "kcontext" ) ) {
                    cls = kcontextClass;
                } else if ( input.equals( "rule" ) ) {
                    cls = Rule.class;
                } else if ( localTypes != null ) {
                    cls = localTypes.get( input );
                }
            }
            if ( cls != null ) {
                parserContext2.addInput( input, cls );
            }
        }

        if ( availableIdentifiers.getThisClass() != null ) {
            parserContext2.addInput( "this", availableIdentifiers.getThisClass() );
        }

        boolean typesafe = context.isTypesafe();

        try {
            returnType = MVEL.analyze( expr,
                                       parserContext2 );
            typesafe = true;
        } catch ( Exception e ) {
            // is this an error, or can we fall back to non-typesafe mode?
            if ( typesafe ) {
                BaseDescr base = (context instanceof RuleBuildContext) ? ((RuleBuildContext)context).getRuleDescr() : context.getParentDescr();
                AsmUtil.copyErrorLocation(e, context.getParentDescr());
                context.addError( new DescrBuildError( base,
                                                       context.getParentDescr(),
                                                       null,
                                                       "Unable to Analyse Expression " + expr + ":\n" + e.getMessage() ) );
                return null;
            }
        }

        if ( typesafe ) {
            requiredInputs = new HashSet<>();
            requiredInputs.addAll( parserContext2.getInputs().keySet() );
            requiredInputs.addAll( variables.keySet() );
            variables = (HashMap<String, Class< ? >>) ((Map) parserContext2.getVariables());
            if ( localTypes != null ) {
                for ( String str : localTypes.keySet() ) {
                    // we have to do this due to mvel regressions on detecting true local vars
                    variables.remove( str );
                }
            }
        }

        MVELAnalysisResult result = analyze( requiredInputs, availableIdentifiers );
        result.setReturnType( returnType );
        result.setMvelVariables( variables );
        result.setTypesafe( typesafe );
        return result;
    }