Example usage for org.antlr.v4.runtime.tree ParseTree toStringTree

List of usage examples for org.antlr.v4.runtime.tree ParseTree toStringTree

Introduction

In this page you can find the example usage for org.antlr.v4.runtime.tree ParseTree toStringTree.

Prototype

String toStringTree();

Source Link

Document

Print out a whole tree, not just a node, in LISP format (root child1 ..

Usage

From source file:annis.ql.parser.AnnisParserAntlr.java

License:Apache License

public String dumpTree(String aql) {
    AqlLexer lexer = new AqlLexer(new ANTLRInputStream(aql));
    AqlParser parser = new AqlParser(new CommonTokenStream(lexer));

    final List<AqlParseError> errors = new LinkedList<>();

    parser.removeErrorListeners();//w  ww  .  jav  a  2  s.c  om
    parser.addErrorListener(new AqlParseErrorListener(errors));

    ParseTree tree = parser.start();

    if (errors.isEmpty()) {
        return tree.toStringTree();
    } else {
        throw new AnnisQLSyntaxException(Joiner.on("\n").join(errors), errors);
    }
}

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

private OperatorNode<SequenceOperator> convertQuery(ParseTree node, Scope scope) {
    if (node instanceof Select_statementContext || node instanceof Insert_statementContext
            || node instanceof Update_statementContext || node instanceof Delete_statementContext) {
        return convertSelectOrInsertOrUpdateOrDelete(node, scope.getRoot());
    } else if (node instanceof Source_statementContext) { //for pipe
        Source_statementContext sourceStatementContext = (Source_statementContext) node;
        return convertPipe(sourceStatementContext.query_statement(), sourceStatementContext.pipeline_step(),
                scope);//from www .  jav  a 2 s.  c  om
    } else if (node instanceof Merge_statementContext) {
        return convertMerge(((Merge_statementContext) node).merge_component(), scope);
    } else if (node instanceof Execute_statementContext) {
        return convertExecute((Execute_statementContext) node, scope);
    } else {
        throw new IllegalArgumentException(
                "Unexpected argument type to convertQueryStatement: " + node.toStringTree());
    }

}

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

private OperatorNode<StatementOperator> convertProgram(ParserRuleContext program, yqlplusParser parser,
        String programName) {/*from  w w  w.  j  a v a  2  s .  co m*/
    Scope scope = new Scope(parser, programName);
    List<OperatorNode<StatementOperator>> stmts = Lists.newArrayList();
    int output = 0;
    for (ParseTree node : program.children) {
        if (!(node instanceof ParserRuleContext)) {
            continue;
        }
        ParserRuleContext ruleContext = (ParserRuleContext) node;
        switch (ruleContext.getRuleIndex()) {
        case yqlplusParser.RULE_params: {
            // ^(ARGUMENT ident typeref expression?)
            ParamsContext paramsContext = (ParamsContext) ruleContext;
            Program_arglistContext program_arglistContext = paramsContext.program_arglist();
            if (program_arglistContext != null) {
                List<Procedure_argumentContext> argList = program_arglistContext.procedure_argument();
                for (Procedure_argumentContext procedureArgumentContext : argList) {
                    if (procedureArgumentContext.array_eq_argument() != null) {
                        Array_eq_argumentContext arrayArgument = procedureArgumentContext.array_eq_argument();
                        String name = arrayArgument.ident().getText();
                        OperatorNode<TypeOperator> type = OperatorNode.create(TypeOperator.ARRAY,
                                decodeType(scope, arrayArgument.getChild(TypenameContext.class, 0)));
                        OperatorNode<ExpressionOperator> defaultValue = OperatorNode
                                .create(ExpressionOperator.NULL);
                        if (arrayArgument.expression() != null) {
                            defaultValue = convertExpr(arrayArgument.expression(), scope);
                        }
                        scope.defineVariable(toLocation(scope, arrayArgument), name);
                        scope.arrayArgument(name);
                        stmts.add(OperatorNode.create(StatementOperator.ARGUMENT, name, type, defaultValue));
                    } else {
                        String name = procedureArgumentContext.ident().getText();
                        OperatorNode<TypeOperator> type = decodeType(scope,
                                procedureArgumentContext.getChild(TypenameContext.class, 0));
                        OperatorNode<ExpressionOperator> defaultValue = OperatorNode
                                .create(ExpressionOperator.NULL);
                        if (procedureArgumentContext.expression() != null) {
                            defaultValue = convertExpr(procedureArgumentContext.expression(), scope);
                        }
                        scope.defineVariable(toLocation(scope, procedureArgumentContext), name);
                        if (type.getOperator() == TypeOperator.ARRAY) {
                            scope.arrayArgument(name);
                        }
                        stmts.add(OperatorNode.create(StatementOperator.ARGUMENT, name, type, defaultValue));
                    }
                }
            }
            break;
        }
        case yqlplusParser.RULE_import_statement: {
            Import_statementContext importContext = (Import_statementContext) ruleContext;
            if (null == importContext.import_list()) {
                List<String> name = createBindingName(node.getChild(1));
                String target;
                Location location = toLocation(scope, node.getChild(1));
                if (node.getChildCount() == 2) {
                    target = name.get(0);
                } else if (node.getChildCount() == 4) {
                    target = node.getChild(3).getText();
                } else {
                    throw new ProgramCompileException("Unknown node count for IMPORT: " + node.toStringTree());
                }
                scope.bindModule(location, name, target);
            } else {
                // | FROM moduleName IMPORT import_list -> ^(IMPORT_FROM
                // moduleName import_list+)
                Import_listContext importListContext = importContext.import_list();
                List<String> name = createBindingName(importContext.moduleName());
                Location location = toLocation(scope, importContext.moduleName());
                List<ModuleIdContext> moduleIds = importListContext.moduleId();
                List<String> symbols = Lists.newArrayListWithExpectedSize(moduleIds.size());
                for (ModuleIdContext cnode : moduleIds) {
                    symbols.add(cnode.ID().getText());
                }
                for (String sym : symbols) {
                    scope.bindModuleSymbol(location, name, sym, sym);
                }
            }
            break;
        }

        // DDL
        case yqlplusParser.RULE_ddl:
            ruleContext = (ParserRuleContext) ruleContext.getChild(0);
        case yqlplusParser.RULE_view: {
            // view and projection expansion now has to be done by the
            // execution engine
            // since views/projections, in order to be useful, have to
            // support being used from outside the same program
            ViewContext viewContext = (ViewContext) ruleContext;
            Location loc = toLocation(scope, viewContext);
            scope.getRoot().defineView(loc, viewContext.ID().getText());
            stmts.add(OperatorNode.create(loc, StatementOperator.DEFINE_VIEW, viewContext.ID().getText(),
                    convertQuery(viewContext.source_statement(), scope.getRoot())));
            break;
        }
        case yqlplusParser.RULE_statement: {
            // ^(STATEMENT_QUERY source_statement paged_clause?
            // output_spec?)
            StatementContext statementContext = (StatementContext) ruleContext;
            switch (getParseTreeIndex(ruleContext.getChild(0))) {
            case yqlplusParser.RULE_selectvar_statement: {
                // ^(STATEMENT_SELECTVAR ident source_statement)
                Selectvar_statementContext selectVarContext = (Selectvar_statementContext) ruleContext
                        .getChild(0);
                String variable = selectVarContext.ident().getText();
                OperatorNode<SequenceOperator> query = convertQuery(selectVarContext.source_statement(), scope);
                Location location = toLocation(scope, selectVarContext.ident());
                scope.defineVariable(location, variable);
                stmts.add(OperatorNode.create(location, StatementOperator.EXECUTE, query, variable));
                break;
            }
            case yqlplusParser.RULE_next_statement: {
                // NEXT^ literalString OUTPUT! AS! ident
                Next_statementContext nextStateContext = (Next_statementContext) ruleContext.getChild(0);
                String continuationValue = StringUnescaper.unquote(nextStateContext.literalString().getText());
                String variable = nextStateContext.ident().getText();
                Location location = toLocation(scope, node);
                OperatorNode<SequenceOperator> next = OperatorNode.create(location, SequenceOperator.NEXT,
                        continuationValue);
                stmts.add(OperatorNode.create(location, StatementOperator.EXECUTE, next, variable));
                stmts.add(OperatorNode.create(location, StatementOperator.OUTPUT, variable));
                scope.defineVariable(location, variable);
                break;
            }
            case yqlplusParser.RULE_output_statement:
                Source_statementContext source_statement = statementContext.output_statement()
                        .source_statement();
                OperatorNode<SequenceOperator> query;
                if (source_statement.getChildCount() == 1) {
                    query = convertQuery(source_statement.query_statement().getChild(0), scope);
                } else {
                    query = convertQuery(source_statement, scope);
                }
                String variable = "result" + (++output);
                boolean isCountVariable = false;
                OperatorNode<ExpressionOperator> pageSize = null;
                ParseTree outputStatement = node.getChild(0);
                Location location = toLocation(scope, outputStatement);
                for (int i = 1; i < outputStatement.getChildCount(); ++i) {
                    ParseTree child = outputStatement.getChild(i);
                    switch (getParseTreeIndex(child)) {
                    case yqlplusParser.RULE_paged_clause:
                        Paged_clauseContext pagedContext = (Paged_clauseContext) child;
                        pageSize = convertExpr(pagedContext.fixed_or_parameter(), scope);
                        break;
                    case yqlplusParser.RULE_output_spec:
                        Output_specContext outputSpecContext = (Output_specContext) child;
                        variable = outputSpecContext.ident().getText();
                        if (outputSpecContext.COUNT() != null) {
                            isCountVariable = true;
                        }
                        break;
                    default:
                        throw new ProgramCompileException(
                                "Unknown statement attribute: " + child.toStringTree());
                    }
                }
                scope.defineVariable(location, variable);
                if (pageSize != null) {
                    query = OperatorNode.create(SequenceOperator.PAGE, query, pageSize);
                }
                stmts.add(OperatorNode.create(location, StatementOperator.EXECUTE, query, variable));
                stmts.add(OperatorNode.create(location,
                        isCountVariable ? StatementOperator.COUNT : StatementOperator.OUTPUT, variable));
            }
            break;
        }
        default:
            throw new ProgramCompileException("Unknown program element: " + node.getText());
        }
    }
    // traverse the tree, find all of the namespaced calls not covered by
    // imports so we can
    // define "implicit" import statements for them (to make engine
    // implementation easier)
    return OperatorNode.create(new Location(programName, 0, 0), StatementOperator.PROGRAM, stmts);
}

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 {/*ww w. j  ava2 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());
}