diff --git a/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt b/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt index 9a21e6d890..9eefa4fccc 100644 --- a/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt +++ b/partiql-lang/src/main/kotlin/org/partiql/lang/syntax/impl/PartiQLPigVisitor.kt @@ -198,6 +198,7 @@ internal class PartiQLPigVisitor( override fun visitByIdent(ctx: PartiQLParser.ByIdentContext) = visitSymbolPrimitive(ctx.symbolPrimitive()) + /* override fun visitSymbolPrimitive(ctx: PartiQLParser.SymbolPrimitiveContext) = PartiqlAst.build { val metas = ctx.ident.getSourceMetaContainer() when (ctx.ident.type) { @@ -211,6 +212,24 @@ internal class PartiQLPigVisitor( PartiQLParser.IDENTIFIER -> id(ctx.IDENTIFIER().getStringValue(), caseInsensitive(), unqualified(), metas) else -> throw ParserException("Invalid symbol reference.", ErrorCode.PARSE_INVALID_QUERY) } + }*/ + + fun visitSymbolPrimitive(ctx: PartiQLParser.SymbolPrimitiveContext) = PartiqlAst.build { + when (ctx) { + is PartiQLParser.QuotedIdentifierContext -> id( + ctx.IDENTIFIER_QUOTED().getStringValue(), + caseSensitive(), + unqualified(), + ctx.IDENTIFIER_QUOTED().getSourceMetaContainer() + ) + is PartiQLParser.UnquotedIdentifierContext -> id( + ctx.text, + caseInsensitive(), + unqualified(), + ctx.IDENTIFIER().getSourceMetaContainer() + ) + else -> throw ParserException("Invalid symbol reference.", ErrorCode.PARSE_INVALID_QUERY) + } } /** @@ -660,9 +679,9 @@ internal class PartiQLPigVisitor( override fun visitExcludeExprTupleAttr(ctx: PartiQLParser.ExcludeExprTupleAttrContext) = PartiqlAst.build { val attr = ctx.symbolPrimitive().getString() - val caseSensitivity = when (ctx.symbolPrimitive().ident.type) { - PartiQLParser.IDENTIFIER_QUOTED -> caseSensitive() - PartiQLParser.IDENTIFIER -> caseInsensitive() + val caseSensitivity = when (ctx.symbolPrimitive()) { + is PartiQLParser.QuotedIdentifierContext -> caseSensitive() + is PartiQLParser.UnquotedIdentifierContext -> caseInsensitive() else -> throw ParserException("Invalid symbol reference.", ErrorCode.PARSE_INVALID_QUERY) } excludeTupleAttr(identifier(attr, caseSensitivity)) @@ -1192,7 +1211,7 @@ internal class PartiQLPigVisitor( override fun visitVariableKeyword(ctx: PartiQLParser.VariableKeywordContext): PartiqlAst.PartiqlAstNode = PartiqlAst.build { - val keyword = ctx.nonReservedKeywords().start.text + val keyword = ctx.nonReserved().start.text val metas = ctx.start.getSourceMetaContainer() val qualifier = ctx.qualifier?.let { localsFirst() } ?: unqualified() id(keyword, caseInsensitive(), qualifier, metas) @@ -1819,9 +1838,9 @@ internal class PartiQLPigVisitor( } } - private fun PartiQLParser.SymbolPrimitiveContext.getSourceMetaContainer() = when (this.ident.type) { - PartiQLParser.IDENTIFIER -> this.IDENTIFIER().getSourceMetaContainer() - PartiQLParser.IDENTIFIER_QUOTED -> this.IDENTIFIER_QUOTED().getSourceMetaContainer() + private fun PartiQLParser.SymbolPrimitiveContext.getSourceMetaContainer() = when (this) { + is PartiQLParser.QuotedIdentifierContext -> this.IDENTIFIER_QUOTED().getSourceMetaContainer() + is PartiQLParser.UnquotedIdentifierContext -> this.start.getSourceMetaContainer() // TODO ALAN check for unreserved keywords else -> throw ParserException( "Unable to get identifier's source meta-container.", ErrorCode.PARSE_INVALID_QUERY @@ -2125,25 +2144,23 @@ internal class PartiQLPigVisitor( } private fun PartiQLParser.SymbolPrimitiveContext.getString(): String { - return when { - this.IDENTIFIER_QUOTED() != null -> this.IDENTIFIER_QUOTED().getStringValue() - this.IDENTIFIER() != null -> this.IDENTIFIER().text + return when (this) { + is PartiQLParser.QuotedIdentifierContext -> this.IDENTIFIER_QUOTED().getStringValue() + is PartiQLParser.UnquotedIdentifierContext -> this.text else -> throw ParserException("Unable to get symbol's text.", ErrorCode.PARSE_INVALID_QUERY) } } private fun getSymbolPathExpr(ctx: PartiQLParser.SymbolPrimitiveContext) = PartiqlAst.build { - when { - ctx.IDENTIFIER_QUOTED() != null -> pathExpr( + when (ctx) { + is PartiQLParser.QuotedIdentifierContext -> pathExpr( lit(ionString(ctx.IDENTIFIER_QUOTED().getStringValue())), caseSensitive(), - metas = ctx.IDENTIFIER_QUOTED().getSourceMetaContainer() + metas = ctx.getSourceMetaContainer() ) - - ctx.IDENTIFIER() != null -> pathExpr( - lit(ionString(ctx.IDENTIFIER().text)), caseInsensitive(), - metas = ctx.IDENTIFIER().getSourceMetaContainer() + is PartiQLParser.UnquotedIdentifierContext -> pathExpr( + lit(ionString(ctx.text)), caseInsensitive(), + metas = ctx.getSourceMetaContainer() ) - else -> throw ParserException("Unable to get symbol's text.", ErrorCode.PARSE_INVALID_QUERY) } } diff --git a/partiql-parser/src/main/antlr/PartiQL.g4 b/partiql-parser/src/main/antlr/PartiQL.g4 index e08b512716..b5b1389805 100644 --- a/partiql-parser/src/main/antlr/PartiQL.g4 +++ b/partiql-parser/src/main/antlr/PartiQL.g4 @@ -40,7 +40,9 @@ byIdent : BY symbolPrimitive; symbolPrimitive - : ident=( IDENTIFIER | IDENTIFIER_QUOTED ) + : IDENTIFIER # UnquotedIdentifier + | IDENTIFIER_QUOTED # QuotedIdentifier + | nonReserved # UnquotedIdentifier ; /** @@ -766,8 +768,8 @@ functionCall // SQL-99 10.4 — ::= [ ] functionName - : (qualifier+=symbolPrimitive PERIOD)* name=( CHAR_LENGTH | CHARACTER_LENGTH | OCTET_LENGTH | BIT_LENGTH | UPPER | LOWER | SIZE | EXISTS | COUNT | MOD ) # FunctionNameReserved - | (qualifier+=symbolPrimitive PERIOD)* name=symbolPrimitive # FunctionNameSymbol + : (qualifier+=symbolPrimitive PERIOD)* name=( CHAR_LENGTH | CHARACTER_LENGTH | MOD ) # FunctionNameReserved + | (qualifier+=symbolPrimitive PERIOD)* name=symbolPrimitive # FunctionNameSymbol ; pathStep @@ -789,11 +791,15 @@ parameter varRefExpr : qualifier=AT_SIGN? ident=(IDENTIFIER|IDENTIFIER_QUOTED) # VariableIdentifier - | qualifier=AT_SIGN? key=nonReservedKeywords # VariableKeyword + | qualifier=AT_SIGN? key=nonReserved # VariableKeyword ; -nonReservedKeywords +nonReserved : EXCLUDED + | LOWER + | UPPER + | EXISTS + | SIZE ; /** diff --git a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt index 0f633cf8ae..5997f2eb94 100644 --- a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt +++ b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt @@ -563,15 +563,29 @@ internal class PartiQLParserDefault : PartiQLParser { override fun visitByIdent(ctx: GeneratedParser.ByIdentContext) = visitSymbolPrimitive(ctx.symbolPrimitive()) - override fun visitSymbolPrimitive(ctx: GeneratedParser.SymbolPrimitiveContext) = translate(ctx) { - when (ctx.ident.type) { - GeneratedParser.IDENTIFIER_QUOTED -> identifierSymbol( + override fun visitQuotedIdentifier(ctx: org.partiql.parser.internal.antlr.PartiQLParser.QuotedIdentifierContext): Identifier.Symbol = translate(ctx) { + identifierSymbol( + ctx.IDENTIFIER_QUOTED().getStringValue(), + Identifier.CaseSensitivity.SENSITIVE + ) + } + + override fun visitUnquotedIdentifier(ctx: org.partiql.parser.internal.antlr.PartiQLParser.UnquotedIdentifierContext): Identifier.Symbol = translate(ctx) { + identifierSymbol( + ctx.text, + Identifier.CaseSensitivity.INSENSITIVE + ) + } + + fun visitSymbolPrimitive(ctx: GeneratedParser.SymbolPrimitiveContext): Identifier.Symbol = translate(ctx) { + when (ctx) { + is GeneratedParser.QuotedIdentifierContext -> identifierSymbol( ctx.IDENTIFIER_QUOTED().getStringValue(), - Identifier.CaseSensitivity.SENSITIVE, + Identifier.CaseSensitivity.SENSITIVE ) - GeneratedParser.IDENTIFIER -> identifierSymbol( - ctx.IDENTIFIER().getStringValue(), - Identifier.CaseSensitivity.INSENSITIVE, + is GeneratedParser.UnquotedIdentifierContext -> identifierSymbol( + ctx.text, + Identifier.CaseSensitivity.INSENSITIVE ) else -> throw error(ctx, "Invalid symbol reference.") } @@ -2313,9 +2327,9 @@ internal class PartiQLParserDefault : PartiQLParser { /** * Visiting a symbol to get a string, skip the wrapping, unwrapping, and location tracking. */ - private fun symbolToString(ctx: GeneratedParser.SymbolPrimitiveContext) = when (ctx.ident.type) { - GeneratedParser.IDENTIFIER_QUOTED -> ctx.IDENTIFIER_QUOTED().getStringValue() - GeneratedParser.IDENTIFIER -> ctx.IDENTIFIER().getStringValue() + private fun symbolToString(ctx: GeneratedParser.SymbolPrimitiveContext) = when (ctx) { + is GeneratedParser.QuotedIdentifierContext -> ctx.IDENTIFIER_QUOTED().getStringValue() + is GeneratedParser.UnquotedIdentifierContext -> ctx.text else -> throw error(ctx, "Invalid symbol reference.") } diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserFunctionCallTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserFunctionCallTests.kt index a562805895..8ddd2eb1dd 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserFunctionCallTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserFunctionCallTests.kt @@ -49,6 +49,17 @@ class PartiQLParserFunctionCallTests { } ) + @Test + fun foo() = assertExpression( + "EXI(true)", + query { + exprCall( + function = identifierSymbol("upper", Identifier.CaseSensitivity.INSENSITIVE), + args = emptyList() + ) + } + ) + @Test fun callUnqualifiedReservedSensitive() = assertExpression( "\"upper\"()",