Example usage for org.antlr.v4.runtime ParserRuleContext getRuleContext

List of usage examples for org.antlr.v4.runtime ParserRuleContext getRuleContext

Introduction

In this page you can find the example usage for org.antlr.v4.runtime ParserRuleContext getRuleContext.

Prototype

public <T extends ParserRuleContext> T getRuleContext(Class<? extends T> ctxType, int i) 

Source Link

Usage

From source file:com.satisfyingstructures.J2S.J2SConverter.java

License:Open Source License

private void convertVariableDeclaration(ParserRuleContext declarationCtx) {
    // Read comments in exitVariableDeclaratorId just above!

    int declarationRuleIndex = declarationCtx.getRuleIndex();
    Class<? extends ParserRuleContext> modifierContextClass = Java8Parser.VariableModifierContext.class;
    Constness constness = Constness.unknown;
    boolean isOptional = false;
    boolean hasDeclaratorList = false;
    boolean enhancedFor = false;

    switch (declarationRuleIndex) {
    case Java8Parser.RULE_constantDeclaration:
        modifierContextClass = Java8Parser.ConstantModifierContext.class;
        hasDeclaratorList = true;//from   w w w. jav  a 2  s .  c o m
        constness = Constness.explicit;
        break;
    case Java8Parser.RULE_fieldDeclaration:
        modifierContextClass = Java8Parser.FieldModifierContext.class;
        hasDeclaratorList = true;
        break;
    case Java8Parser.RULE_localVariableDeclaration:
        hasDeclaratorList = true;
        break;
    case Java8Parser.RULE_resource:
        constness = Constness.explicit;
        break;
    case Java8Parser.RULE_formalParameter:
    case Java8Parser.RULE_lastFormalParameter:
        constness = Constness.implicit;
        break;
    case Java8Parser.RULE_catchFormalParameter:
        constness = Constness.explicit;
        break;
    case Java8Parser.RULE_enhancedForStatement:
    case Java8Parser.RULE_enhancedForStatementNoShortIf:
        enhancedFor = true;
        constness = Constness.implicit;
        break;
    default:
        return; // not our expected parameter type
    }

    // Look for and remove 'final', '@NonNull' and '@Nullable' in modifiers
    for (ParserRuleContext modifierCtx : declarationCtx.getRuleContexts(modifierContextClass)) {
        TerminalNode tn = modifierCtx.getChild(TerminalNode.class, 0);
        if (null == tn) {
            String annotationText = modifierCtx.getText();
            switch (annotationText) {
            // some spelling variations here...
            case "@Nonnull": // javax.annotation.NotNull
            case "@NonNull": // android.support.annotation.NonNull
                             // edu.umd.cs.findbugs.annotations.NonNull
            case "@NotNull": // org.jetbrains.annotations.NotNull
                isOptional = false;
                break;
            case "@Nullable":
                isOptional = true;
                break;
            default:
                continue;
            }
        } else {
            Token token = tn.getSymbol();
            mapModifierToken(token);
            switch (token.getType()) {
            case Java8Parser.FINAL:
                if (constness == Constness.unknown)
                    constness = Constness.explicit;
                break;
            default:
                continue;
            }
        }
        rewriter.deleteAndAdjustWhitespace(modifierCtx);
    }

    // Move trailing dimensions to wrap the type. First any dimensions binding to the declarator id and
    // then any dimensions binding to the right of the type.
    // a) start by finding the type context that will be wrapped.
    Java8Parser.UnannTypeContext unannTypeCtx = null;
    Java8Parser.UnannReferenceTypeContext unannReferenceTypeCtx = null;
    Java8Parser.UnannArrayTypeContext unannArrayTypeCtx = null;
    Java8Parser.DimsContext outerDimsCtx = null;
    ParserRuleContext typeCtx = null;
    if (declarationRuleIndex == Java8Parser.RULE_catchFormalParameter)
        typeCtx = declarationCtx.getChild(Java8Parser.CatchTypeContext.class, 0);
    else
        typeCtx = unannTypeCtx = declarationCtx.getChild(Java8Parser.UnannTypeContext.class, 0);
    if (null != unannTypeCtx)
        if (null != (unannReferenceTypeCtx = unannTypeCtx.unannReferenceType())
                && null != (unannArrayTypeCtx = unannReferenceTypeCtx.unannArrayType())) {
            typeCtx = unannArrayTypeCtx.getChild(ParserRuleContext.class, 0);
            outerDimsCtx = unannArrayTypeCtx.dims();
        }
    // b) process dimensions attached to declarator ids
    // ...process inside blocks below
    // c) process dimensions attached to type
    // ...process inside blocks below

    // Now insert unannTypeText at end of each variableDeclaratorId if necessary:
    ParserRuleContext ctx, varInitCtx;
    Java8Parser.VariableDeclaratorIdContext varIdCtx;
    Java8Parser.DimsContext innerDimsCtx = null;
    String unannTypeText;
    if (hasDeclaratorList) {
        // Iterate over the list of declarator-initialiser pairs backwards so that variable lists without
        // intialisers and with explicit enough types, just pick up the type from the end of the list, i.e.
        // so that we generate var a, b, c: Int, and not var a: Int, b: Int, c: Int.
        ListIterator<Java8Parser.VariableDeclaratorContext> iter;
        List<Java8Parser.VariableDeclaratorContext> list;
        String followingUnannTypeText = null;
        boolean followingVarHasExplicitType = false;
        boolean hasInitialiser;

        ctx = declarationCtx.getChild(Java8Parser.VariableDeclaratorListContext.class, 0);
        list = ctx.getRuleContexts(Java8Parser.VariableDeclaratorContext.class);
        iter = list.listIterator(list.size());
        unannTypeText = null;

        while (iter.hasPrevious()) {
            ctx = iter.previous();
            varIdCtx = ctx.getRuleContext(Java8Parser.VariableDeclaratorIdContext.class, 0);

            // Wrap the inner type string with array dimensions if we have them. Have to do this for each variable,
            // because they can have different dimensionality.
            followingUnannTypeText = unannTypeText;
            unannTypeText = rewriter.getText(typeCtx);
            if (null != (innerDimsCtx = varIdCtx.dims())) {
                unannTypeText = wrapTypeStringWithDims(unannTypeText, innerDimsCtx);
                rewriter.delete(innerDimsCtx);
            }
            if (null != outerDimsCtx)
                unannTypeText = wrapTypeStringWithDims(unannTypeText, outerDimsCtx);

            varInitCtx = ctx.getRuleContext(Java8Parser.VariableInitializerContext.class, 0);
            if (null != varInitCtx)
                varInitCtx = varInitCtx.getChild(ParserRuleContext.class, 0); // expression or arrayInitializer
            hasInitialiser = null != varInitCtx;

            // In the basic case, we have to qualify the variable with its type, but we can omit this if it has an
            // initialiser that completely implies the type, or it has no initialiser and has the same type as the
            // a contiguously following variable with explicit type.
            if (hasInitialiser
                    ? !isVariableTypeCompletelyImpliedByInitializer(unannTypeCtx, varInitCtx,
                            /*inEnhancedFor:*/false)
                    : !followingVarHasExplicitType || null == followingUnannTypeText
                            || !unannTypeText.equals(followingUnannTypeText)) {
                rewriter.insertAfter(varIdCtx, ": " + unannTypeText + (isOptional ? "?" : ""));
                followingVarHasExplicitType = !hasInitialiser;
            }
        }
    } else {
        varIdCtx = declarationCtx.getRuleContext(Java8Parser.VariableDeclaratorIdContext.class, 0);
        unannTypeText = rewriter.getText(typeCtx);
        if (null != (innerDimsCtx = varIdCtx.dims())) {
            unannTypeText = wrapTypeStringWithDims(unannTypeText, innerDimsCtx);
            rewriter.delete(innerDimsCtx);
        }
        if (null != outerDimsCtx)
            unannTypeText = wrapTypeStringWithDims(unannTypeText, outerDimsCtx);

        varInitCtx = null;
        if (declarationRuleIndex == Java8Parser.RULE_resource
                || declarationRuleIndex == Java8Parser.RULE_enhancedForStatement
                || declarationRuleIndex == Java8Parser.RULE_enhancedForStatementNoShortIf)
            varInitCtx = declarationCtx.getRuleContext(Java8Parser.ExpressionContext.class, 0);

        if (declarationRuleIndex == Java8Parser.RULE_catchFormalParameter)
            rewriter.insertAfter(varIdCtx, " as " + unannTypeText);
        else if (!isVariableTypeCompletelyImpliedByInitializer(unannTypeCtx, varInitCtx, enhancedFor))
            rewriter.insertAfter(varIdCtx, ": " + unannTypeText + (isOptional ? "?" : ""));

        // In parameter lists, add an anonymizing argument label, as argument labels not used in java method/function calls
        if (declarationRuleIndex == Java8Parser.RULE_formalParameter
                || declarationRuleIndex == Java8Parser.RULE_lastFormalParameter)
            rewriter.insertBefore(varIdCtx, "_ ");
    }

    // Finally replace the complete type context with let/var/-
    // in an enhancedForStatement, the loop var is implicitly const, but can be made variable with var if it is
    // to be modified inside the loop; we could check for this, but its a rare scenario, and a lot of work, so no.
    if (null != unannTypeCtx)
        typeCtx = unannTypeCtx;
    switch (constness) {
    case explicit:
        rewriter.replace(typeCtx, "let");
        break;
    case implicit:
        rewriter.deleteAndAdjustWhitespace(typeCtx);
        break;
    case variable:
        rewriter.replace(typeCtx, "var");
        break;
    // if still unknown, then assume variable...
    default:
        rewriter.replace(typeCtx, "var");
        break;
    }
}

From source file:com.yahoo.yqlplus.language.parser.ProgramParser.java

private OperatorNode<SequenceOperator> convertSource(ParserRuleContext sourceSpecNode, Scope scope) {

    // DataSources
    String alias;//from  w w  w  .  jav a2s . c  om
    OperatorNode<SequenceOperator> result;
    ParserRuleContext dataSourceNode = sourceSpecNode;
    ParserRuleContext aliasContext = null;
    //data_source
    //:   call_source
    //|   LPAREN source_statement RPAREN
    //|   sequence_source
    //;
    if (sourceSpecNode instanceof Source_specContext) {
        dataSourceNode = (ParserRuleContext) sourceSpecNode.getChild(0);
        if (sourceSpecNode.getChildCount() == 2) {
            aliasContext = (ParserRuleContext) sourceSpecNode.getChild(1);
        }
        if (dataSourceNode.getChild(0) instanceof Call_sourceContext
                || dataSourceNode.getChild(0) instanceof Sequence_sourceContext) {
            dataSourceNode = (ParserRuleContext) dataSourceNode.getChild(0);
        }
        //TODO double check whether comment out this is correct            
        //            else { //source_statement
        //                dataSourceNode = (ParserRuleContext)dataSourceNode.getChild(1); 
        //            }
    }
    switch (getParseTreeIndex(dataSourceNode)) {
    case yqlplusParser.RULE_write_data_source:
    case yqlplusParser.RULE_call_source: {
        List<String> names = readName(
                (Namespaced_nameContext) dataSourceNode.getChild(Namespaced_nameContext.class, 0));
        alias = assignAlias(names.get(names.size() - 1), aliasContext, scope);
        List<OperatorNode<ExpressionOperator>> arguments = ImmutableList.of();
        ArgumentsContext argumentsContext = dataSourceNode.getRuleContext(ArgumentsContext.class, 0);
        if (argumentsContext != null) {
            List<ArgumentContext> argumentContexts = argumentsContext.argument();
            arguments = Lists.newArrayListWithExpectedSize(argumentContexts.size());
            for (ArgumentContext argumentContext : argumentContexts) {
                arguments.add(convertExpr(argumentContext, scope));
            }
        }
        if (names.size() == 1 && scope.isVariable(names.get(0))) {
            String ident = names.get(0);
            if (arguments.size() > 0) {
                throw new ProgramCompileException(toLocation(scope, argumentsContext),
                        "Invalid call-with-arguments on local source '%s'", ident);
            }
            result = OperatorNode.create(toLocation(scope, dataSourceNode), SequenceOperator.EVALUATE,
                    OperatorNode.create(toLocation(scope, dataSourceNode), ExpressionOperator.VARREF, ident));
        } else {
            result = OperatorNode.create(toLocation(scope, dataSourceNode), SequenceOperator.SCAN,
                    scope.resolvePath(names), arguments);
        }
        break;
    }
    case yqlplusParser.RULE_sequence_source: {
        IdentContext identContext = dataSourceNode.getRuleContext(IdentContext.class, 0);
        String ident = identContext.getText();
        if (!scope.isVariable(ident)) {
            throw new ProgramCompileException(toLocation(scope, identContext),
                    "Unknown variable reference '%s'", ident);
        }
        alias = assignAlias(ident, aliasContext, scope);
        result = OperatorNode.create(toLocation(scope, dataSourceNode), SequenceOperator.EVALUATE,
                OperatorNode.create(toLocation(scope, dataSourceNode), ExpressionOperator.VARREF, ident));
        break;
    }
    case yqlplusParser.RULE_source_statement: {
        alias = assignAlias(null, dataSourceNode, scope);
        result = convertQuery(dataSourceNode, scope);
        break;
    }
    case yqlplusParser.RULE_data_source: {
        alias = assignAlias("source", aliasContext, scope);
        result = convertQuery(dataSourceNode.getChild(1), scope);
        break;
    }
    default:
        throw new IllegalArgumentException(
                "Unexpected argument type to convertSource: " + dataSourceNode.getText());
    }
    result.putAnnotation("alias", alias);
    return result;
}

From source file:com.yahoo.yqlplus.language.parser.ProgramParser.java

public OperatorNode<ExpressionOperator> convertExpr(ParseTree parseTree, Scope scope) {
    switch (getParseTreeIndex(parseTree)) {
    case yqlplusParser.RULE_nullOperator:
        return OperatorNode.create(ExpressionOperator.NULL);
    case yqlplusParser.RULE_argument:
        return convertExpr(parseTree.getChild(0), scope);
    case yqlplusParser.RULE_fixed_or_parameter: {
        ParseTree firstChild = parseTree.getChild(0);
        if (getParseTreeIndex(firstChild) == yqlplusParser.INT) {
            return OperatorNode.create(toLocation(scope, firstChild), ExpressionOperator.LITERAL,
                    new Integer(firstChild.getText()));
        } else {//from   ww w.ja  v  a  2  s.c om
            return convertExpr(firstChild, scope);
        }
    }
    case yqlplusParser.RULE_constantMapExpression: {
        List<ConstantPropertyNameAndValueContext> propertyList = ((ConstantMapExpressionContext) parseTree)
                .constantPropertyNameAndValue();
        List<String> names = Lists.newArrayListWithExpectedSize(propertyList.size());
        List<OperatorNode<ExpressionOperator>> exprs = Lists.newArrayListWithExpectedSize(propertyList.size());
        for (ConstantPropertyNameAndValueContext child : propertyList) {
            // : propertyName ':' expression[$expression::namespace] ->
            // ^(PROPERTY propertyName expression)
            names.add(StringUnescaper.unquote(child.getChild(0).getText()));
            exprs.add(convertExpr(child.getChild(2), scope));
        }
        return OperatorNode.create(toLocation(scope, parseTree), ExpressionOperator.MAP, names, exprs);
    }
    case yqlplusParser.RULE_mapExpression: {
        List<PropertyNameAndValueContext> propertyList = ((MapExpressionContext) parseTree)
                .propertyNameAndValue();
        List<String> names = Lists.newArrayListWithExpectedSize(propertyList.size());
        List<OperatorNode<ExpressionOperator>> exprs = Lists.newArrayListWithCapacity(propertyList.size());
        for (PropertyNameAndValueContext child : propertyList) {
            // : propertyName ':' expression[$expression::namespace] ->
            // ^(PROPERTY propertyName expression)
            names.add(StringUnescaper.unquote(child.getChild(0).getText()));
            exprs.add(convertExpr(child.getChild(2), scope));
        }
        return OperatorNode.create(toLocation(scope, parseTree), ExpressionOperator.MAP, names, exprs);
    }
    case yqlplusParser.RULE_constantArray: {
        List<ConstantExpressionContext> expressionList = ((ConstantArrayContext) parseTree)
                .constantExpression();
        List<OperatorNode<ExpressionOperator>> values = Lists
                .newArrayListWithExpectedSize(expressionList.size());
        for (ConstantExpressionContext expr : expressionList) {
            values.add(convertExpr(expr, scope));
        }
        return OperatorNode.create(
                toLocation(scope, expressionList.isEmpty() ? parseTree : expressionList.get(0)),
                ExpressionOperator.ARRAY, values);
    }
    case yqlplusParser.RULE_arrayLiteral: {
        List<ExpressionContext> expressionList = ((ArrayLiteralContext) parseTree).expression();
        List<OperatorNode<ExpressionOperator>> values = Lists
                .newArrayListWithExpectedSize(expressionList.size());
        for (ExpressionContext expr : expressionList) {
            values.add(convertExpr(expr, scope));
        }
        return OperatorNode.create(
                toLocation(scope, expressionList.isEmpty() ? parseTree : expressionList.get(0)),
                ExpressionOperator.ARRAY, values);
    }
    //dereferencedExpression: primaryExpression(indexref[in_select]| propertyref)*
    case yqlplusParser.RULE_dereferencedExpression: {
        DereferencedExpressionContext dereferencedExpression = (DereferencedExpressionContext) parseTree;
        Iterator<ParseTree> it = dereferencedExpression.children.iterator();
        OperatorNode<ExpressionOperator> result = convertExpr(it.next(), scope);
        while (it.hasNext()) {
            ParseTree defTree = it.next();
            if (getParseTreeIndex(defTree) == yqlplusParser.RULE_propertyref) {
                //DOT nm=ID
                result = OperatorNode.create(toLocation(scope, parseTree), ExpressionOperator.PROPREF, result,
                        defTree.getChild(1).getText());
            } else {
                //indexref
                result = OperatorNode.create(toLocation(scope, parseTree), ExpressionOperator.INDEX, result,
                        convertExpr(defTree.getChild(1), scope));
            }
        }
        return result;
    }
    case yqlplusParser.RULE_primaryExpression: {
        // ^(CALL namespaced_name arguments)
        ParseTree firstChild = parseTree.getChild(0);
        switch (getParseTreeIndex(firstChild)) {
        case yqlplusParser.RULE_fieldref: {
            return convertExpr(firstChild, scope);
        }
        case yqlplusParser.RULE_callExpresion: {
            List<ArgumentContext> args = ((ArgumentsContext) firstChild.getChild(1)).argument();
            List<OperatorNode<ExpressionOperator>> arguments = Lists.newArrayListWithExpectedSize(args.size());
            for (ArgumentContext argContext : args) {
                arguments.add(convertExpr(argContext.expression(), scope));
            }
            return OperatorNode.create(toLocation(scope, parseTree), ExpressionOperator.CALL,
                    scope.resolvePath(readName((Namespaced_nameContext) firstChild.getChild(0))), arguments);
        }
        // TODO add processing this is not implemented in V3
        // case yqlplusParser.APPLY:

        case yqlplusParser.RULE_parameter:
            // external variable reference
            return OperatorNode.create(toLocation(scope, firstChild), ExpressionOperator.VARREF,
                    firstChild.getChild(1).getText());
        case yqlplusParser.RULE_scalar_literal:
        case yqlplusParser.RULE_arrayLiteral:
        case yqlplusParser.RULE_mapExpression:
            return convertExpr(firstChild, scope);
        case yqlplusParser.LPAREN:
            return convertExpr(parseTree.getChild(1), scope);
        }
    }
    // TODO: Temporarily disable CAST - think through how types are named
    // case yqlplusParser.CAST: {
    //
    // return new Cast()
    // }
    // return new CastExpression(payload);
    case yqlplusParser.RULE_parameter: {
        // external variable reference
        ParserRuleContext parameterContext = (ParserRuleContext) parseTree;
        IdentContext identContext = parameterContext.getRuleContext(IdentContext.class, 0);
        return OperatorNode.create(toLocation(scope, identContext), ExpressionOperator.VARREF,
                identContext.getText());
    }
    case yqlplusParser.RULE_annotateExpression: {
        //annotation logicalORExpression
        AnnotationContext annotateExpressionContext = ((AnnotateExpressionContext) parseTree).annotation();
        OperatorNode<ExpressionOperator> annotation = convertExpr(
                annotateExpressionContext.constantMapExpression(), scope);
        OperatorNode<ExpressionOperator> expr = convertExpr(parseTree.getChild(1), scope);
        List<String> names = (List<String>) annotation.getArgument(0);
        List<OperatorNode<ExpressionOperator>> annotates = (List<OperatorNode<ExpressionOperator>>) annotation
                .getArgument(1);
        for (int i = 0; i < names.size(); ++i) {
            expr.putAnnotation(names.get(i), readConstantExpression(annotates.get(i)));
        }
        return expr;
    }
    case yqlplusParser.RULE_expression: {
        return convertExpr(parseTree.getChild(0), scope);
    }
    case yqlplusParser.RULE_logicalANDExpression:
        LogicalANDExpressionContext andExpressionContext = (LogicalANDExpressionContext) parseTree;
        return readConjOp(ExpressionOperator.AND, andExpressionContext.equalityExpression(), scope);
    case yqlplusParser.RULE_logicalORExpression: {
        int childCount = parseTree.getChildCount();
        LogicalORExpressionContext logicalORExpressionContext = (LogicalORExpressionContext) parseTree;
        if (childCount > 1) {
            return readConjOrOp(ExpressionOperator.OR, logicalORExpressionContext, scope);
        } else {
            List<EqualityExpressionContext> equalityExpressionList = ((LogicalANDExpressionContext) parseTree
                    .getChild(0)).equalityExpression();
            if (equalityExpressionList.size() > 1) {
                return readConjOp(ExpressionOperator.AND, equalityExpressionList, scope);
            } else {
                return convertExpr(equalityExpressionList.get(0), scope);
            }
        }
    }
    case yqlplusParser.RULE_equalityExpression: {
        EqualityExpressionContext equalityExpression = (EqualityExpressionContext) parseTree;
        RelationalExpressionContext relationalExpressionContext = equalityExpression.relationalExpression(0);
        OperatorNode<ExpressionOperator> expr = convertExpr(relationalExpressionContext, scope);
        InNotInTargetContext inNotInTarget = equalityExpression.inNotInTarget();
        int childCount = equalityExpression.getChildCount();
        if (childCount == 1) {
            return expr;
        }
        if (inNotInTarget != null) {
            Literal_listContext literalListContext = inNotInTarget.literal_list();
            boolean isIN = equalityExpression.IN() != null;
            if (literalListContext == null) {
                Select_statementContext selectStatementContext = inNotInTarget.select_statement();
                OperatorNode<SequenceOperator> query = convertQuery(selectStatementContext, scope);
                return OperatorNode.create(expr.getLocation(),
                        isIN ? ExpressionOperator.IN_QUERY : ExpressionOperator.NOT_IN_QUERY, expr, query);
            } else {
                // we need to identify the type of the target; if it's a
                // scalar we need to wrap it in a CREATE_ARRAY
                // if it's already a CREATE ARRAY then it's fine, otherwise
                // we need to know the variable type
                // return readBinOp(node.getType() == yqlplusParser.IN ?
                // ExpressionOperator.IN : ExpressionOperator.NOT_IN, node,
                // scope);
                return readBinOp(isIN ? ExpressionOperator.IN : ExpressionOperator.NOT_IN,
                        equalityExpression.getChild(0), literalListContext, scope);
            }

        } else {
            ParseTree firstChild = equalityExpression.getChild(1);
            if (equalityExpression.getChildCount() == 2) {
                switch (getParseTreeIndex(firstChild)) {
                case yqlplusParser.IS_NULL:
                    return readUnOp(ExpressionOperator.IS_NULL, relationalExpressionContext, scope);
                case yqlplusParser.IS_NOT_NULL:
                    return readUnOp(ExpressionOperator.IS_NOT_NULL, relationalExpressionContext, scope);
                }
            } else {
                switch (getParseTreeIndex(firstChild.getChild(0))) {
                case yqlplusParser.EQ:
                    return readBinOp(ExpressionOperator.EQ, equalityExpression.getChild(0),
                            equalityExpression.getChild(2), scope);
                case yqlplusParser.NEQ:
                    return readBinOp(ExpressionOperator.NEQ, equalityExpression.getChild(0),
                            equalityExpression.getChild(2), scope);
                case yqlplusParser.LIKE:
                    return readBinOp(ExpressionOperator.LIKE, equalityExpression.getChild(0),
                            equalityExpression.getChild(2), scope);
                case yqlplusParser.NOTLIKE:
                    return readBinOp(ExpressionOperator.NOT_LIKE, equalityExpression.getChild(0),
                            equalityExpression.getChild(2), scope);
                case yqlplusParser.MATCHES:
                    return readBinOp(ExpressionOperator.MATCHES, equalityExpression.getChild(0),
                            equalityExpression.getChild(2), scope);
                case yqlplusParser.NOTMATCHES:
                    return readBinOp(ExpressionOperator.NOT_MATCHES, equalityExpression.getChild(0),
                            equalityExpression.getChild(2), scope);
                case yqlplusParser.CONTAINS:
                    return readBinOp(ExpressionOperator.CONTAINS, equalityExpression.getChild(0),
                            equalityExpression.getChild(2), scope);
                }
            }

        }
        break;
    }
    case yqlplusParser.RULE_relationalExpression: {
        RelationalExpressionContext relationalExpressionContext = (RelationalExpressionContext) parseTree;
        RelationalOpContext opContext = relationalExpressionContext.relationalOp();
        if (opContext != null) {
            switch (getParseTreeIndex(relationalExpressionContext.relationalOp().getChild(0))) {
            case yqlplusParser.LT:
                return readBinOp(ExpressionOperator.LT, parseTree, scope);
            case yqlplusParser.LTEQ:
                return readBinOp(ExpressionOperator.LTEQ, parseTree, scope);
            case yqlplusParser.GT:
                return readBinOp(ExpressionOperator.GT, parseTree, scope);
            case yqlplusParser.GTEQ:
                return readBinOp(ExpressionOperator.GTEQ, parseTree, scope);
            }
        } else {
            return convertExpr(relationalExpressionContext.additiveExpression(0), scope);
        }
    }
        break;
    case yqlplusParser.RULE_additiveExpression:
    case yqlplusParser.RULE_multiplicativeExpression: {
        if (parseTree.getChildCount() > 1) {
            String opStr = parseTree.getChild(1).getText();
            switch (opStr) {
            case "+":
                return readBinOp(ExpressionOperator.ADD, parseTree, scope);
            case "-":
                return readBinOp(ExpressionOperator.SUB, parseTree, scope);
            case "/":
                return readBinOp(ExpressionOperator.DIV, parseTree, scope);
            case "*":
                return readBinOp(ExpressionOperator.MULT, parseTree, scope);
            case "%":
                return readBinOp(ExpressionOperator.MOD, parseTree, scope);
            default:
                if (parseTree.getChild(0) instanceof UnaryExpressionContext) {
                    return convertExpr(parseTree.getChild(0), scope);
                } else {
                    throw new ProgramCompileException(toLocation(scope, parseTree),
                            "Unknown expression type: " + parseTree.toStringTree());
                }
            }
        } else {
            if (parseTree.getChild(0) instanceof UnaryExpressionContext) {
                return convertExpr(parseTree.getChild(0), scope);
            } else if (parseTree.getChild(0) instanceof MultiplicativeExpressionContext) {
                return convertExpr(parseTree.getChild(0), scope);
            } else {
                throw new ProgramCompileException(toLocation(scope, parseTree),
                        "Unknown expression type: " + parseTree.getText());
            }
        }
    }
    case yqlplusParser.RULE_unaryExpression: {
        if (1 == parseTree.getChildCount()) {
            return convertExpr(parseTree.getChild(0), scope);
        } else if (2 == parseTree.getChildCount()) {
            if ("-".equals(parseTree.getChild(0).getText())) {
                return readUnOp(ExpressionOperator.NEGATE, parseTree, scope);
            } else if ("!".equals(parseTree.getChild(0).getText())) {
                return readUnOp(ExpressionOperator.NOT, parseTree, scope);
            }
            throw new ProgramCompileException(toLocation(scope, parseTree),
                    "Unknown unary operator " + parseTree.getText());
        } else {
            throw new ProgramCompileException(toLocation(scope, parseTree),
                    "Unknown child count " + parseTree.getChildCount() + " of " + parseTree.getText());
        }
    }
    case yqlplusParser.RULE_fieldref:
    case yqlplusParser.RULE_joinDereferencedExpression: {
        // all in-scope data sources should be defined in scope
        // the 'first' field in a namespaced reference must be:
        // - a field name if (and only if) there is exactly one data source
        // in scope OR
        // - an alias name, which will be followed by a field name
        // ^(FIELDREF<FieldReference>[$expression::namespace]
        // namespaced_name)
        List<String> path = readName((Namespaced_nameContext) parseTree.getChild(0));
        Location loc = toLocation(scope, parseTree.getChild(0));
        String alias = path.get(0);
        OperatorNode<ExpressionOperator> result;
        int start;
        if (scope.isCursor(alias)) {
            if (path.size() > 1) {
                result = OperatorNode.create(loc, ExpressionOperator.READ_FIELD, alias, path.get(1));
                start = 2;
            } else {
                if (scope.getCursors().size() > 1 || Boolean.TRUE.equals(scope.getCursors().get(alias))) {
                    result = OperatorNode.create(loc, ExpressionOperator.READ_RECORD, alias);
                } else {
                    result = OperatorNode.create(loc, ExpressionOperator.READ_FIELD, alias, alias);
                }
                start = 1;
            }
        } else if (scope.isBound(alias)) {
            return OperatorNode.create(loc, ExpressionOperator.READ_MODULE,
                    scope.getBinding(alias).toPathWith(path.subList(1, path.size())));
        } else if (scope.getCursors().size() == 1) {
            alias = scope.getCursors().keySet().iterator().next();
            result = OperatorNode.create(loc, ExpressionOperator.READ_FIELD, alias, path.get(0));
            start = 1;
        } else {
            // ah ha, we can't end up with a 'loose' UDF call because it
            // won't be a module or known alias
            // so we need not support implicit imports for constants used in
            // UDFs
            throw new ProgramCompileException(loc, "Unknown field or alias '%s'", alias);
        }
        for (int idx = start; idx < path.size(); ++idx) {
            result = OperatorNode.create(loc, ExpressionOperator.PROPREF, result, path.get(idx));
        }
        return result;
    }
    case yqlplusParser.RULE_scalar_literal:
        return OperatorNode.create(toLocation(scope, parseTree), ExpressionOperator.LITERAL,
                convertLiteral((Scalar_literalContext) parseTree));
    case yqlplusParser.RULE_insert_values:
        return readValues((Insert_valuesContext) parseTree, scope);
    case yqlplusParser.RULE_constantExpression:
        return convertExpr(parseTree.getChild(0), scope);
    case yqlplusParser.RULE_literal_list:
        List<Literal_elementContext> elements = ((Literal_listContext) parseTree).literal_element();
        if (elements.size() == 1) {
            Literal_elementContext child = elements.get(0);
            OperatorNode<ExpressionOperator> expr = convertExpr(child.getChild(0), scope);
            if (expr.getOperator() == ExpressionOperator.VARREF
                    && scope.isArrayArgument((String) expr.getArgument(0))) {
                return expr;
            }
            return OperatorNode.create(toLocation(scope, elements.get(0)), ExpressionOperator.ARRAY,
                    ImmutableList.of(expr));
        }
        List<OperatorNode<ExpressionOperator>> values = Lists.newArrayListWithExpectedSize(elements.size());
        for (Literal_elementContext child : elements) {
            values.add(convertExpr(child.getChild(0), scope));
        }
        return OperatorNode.create(toLocation(scope, elements.get(0)), ExpressionOperator.ARRAY, values);
    }
    throw new ProgramCompileException(toLocation(scope, parseTree),
            "Unknown expression type: " + parseTree.getText());
}