Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Parser APIs in Java and allows for parsing multiple statements #1634

Merged
merged 12 commits into from
Nov 1, 2024
Merged
13 changes: 8 additions & 5 deletions partiql-cli/src/main/kotlin/org/partiql/cli/pipeline/Pipeline.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import org.partiql.ast.v1.Statement
import org.partiql.cli.ErrorCodeString
import org.partiql.eval.Mode
import org.partiql.eval.compiler.PartiQLCompiler
import org.partiql.parser.V1PartiQLParser
import org.partiql.parser.V1PartiQLParserBuilder
import org.partiql.parser.PartiQLParserBuilderV1
import org.partiql.parser.PartiQLParserV1
import org.partiql.plan.Plan
import org.partiql.planner.PartiQLPlanner
import org.partiql.spi.Context
Expand All @@ -15,7 +15,7 @@ import org.partiql.spi.value.Datum
import java.io.PrintStream

internal class Pipeline private constructor(
private val parser: V1PartiQLParser,
private val parser: PartiQLParserV1,
private val planner: PartiQLPlanner,
private val compiler: PartiQLCompiler,
private val ctx: Context,
Expand All @@ -37,7 +37,10 @@ internal class Pipeline private constructor(
val result = listen(ctx.errorListener as AppPErrorListener) {
parser.parse(source, ctx)
}
return result.root
if (result.statements.size != 1) {
throw PipelineException("Expected exactly one statement, got: ${result.statements.size}")
}
return result.statements[0]
johnedquinn marked this conversation as resolved.
Show resolved Hide resolved
}

private fun plan(statement: Statement, session: Session): Plan {
Expand Down Expand Up @@ -80,7 +83,7 @@ internal class Pipeline private constructor(
private fun create(mode: Mode, out: PrintStream, config: Config): Pipeline {
val listener = config.getErrorListener(out)
val ctx = Context.of(listener)
val parser = V1PartiQLParserBuilder().build()
val parser = PartiQLParserBuilderV1().build()
val planner = PartiQLPlanner.builder().build()
val compiler = PartiQLCompiler.builder().build()
return Pipeline(parser, planner, compiler, ctx, mode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal object ShellHighlighter : Highlighter {

// Parse and Replace Token Style if Failures
try {
parser.root()
parser.statements()
} catch (e: RethrowErrorListener.OffendingSymbolException) {
val offending = e.offendingSymbol
val prefix = builder.substring(0, offending.startIndex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.partiql.eval.Mode
import org.partiql.eval.compiler.PartiQLCompiler
import org.partiql.parser.V1PartiQLParser
import org.partiql.parser.PartiQLParserV1
import org.partiql.plan.Plan
import org.partiql.planner.PartiQLPlanner
import org.partiql.spi.catalog.Catalog
Expand Down Expand Up @@ -38,6 +38,7 @@ import org.partiql.value.symbolValue
import java.io.ByteArrayOutputStream
import java.math.BigDecimal
import java.math.BigInteger
import kotlin.test.assertEquals
import kotlin.test.assertNotNull

/**
Expand Down Expand Up @@ -1307,7 +1308,7 @@ class PartiQLEvaluatorTest {
) {

private val compiler = PartiQLCompiler.standard()
private val parser = V1PartiQLParser.standard()
private val parser = PartiQLParserV1.standard()
private val planner = PartiQLPlanner.standard()

/**
Expand All @@ -1320,7 +1321,9 @@ class PartiQLEvaluatorTest {
)

internal fun assert() {
val statement = parser.parse(input).root
val parseResult = parser.parse(input)
assertEquals(1, parseResult.statements.size)
val statement = parseResult.statements[0]
johnedquinn marked this conversation as resolved.
Show resolved Hide resolved
val catalog = Catalog.builder()
.name("memory")
.apply {
Expand Down Expand Up @@ -1373,7 +1376,7 @@ class PartiQLEvaluatorTest {
) {

private val compiler = PartiQLCompiler.standard()
private val parser = V1PartiQLParser.standard()
private val parser = PartiQLParserV1.standard()
private val planner = PartiQLPlanner.standard()

internal fun assert() {
Expand Down Expand Up @@ -1406,7 +1409,9 @@ class PartiQLEvaluatorTest {
}

private fun run(mode: Mode): Pair<Datum, Plan> {
val statement = parser.parse(input).root
val parseResult = parser.parse(input)
assertEquals(1, parseResult.statements.size)
val statement = parseResult.statements[0]
val catalog = Catalog.builder().name("memory").build()
val session = Session.builder()
.catalog("memory")
Expand Down
147 changes: 18 additions & 129 deletions partiql-parser/api/partiql-parser.api
Original file line number Diff line number Diff line change
@@ -1,147 +1,36 @@
public abstract interface class org/partiql/parser/PartiQLParser {
public static final field Companion Lorg/partiql/parser/PartiQLParser$Companion;
public static fun builder ()Lorg/partiql/parser/PartiQLParserBuilder;
public abstract fun parse (Ljava/lang/String;)Lorg/partiql/parser/PartiQLParser$Result;
public fun parse (Ljava/lang/String;)Lorg/partiql/parser/PartiQLParser$Result;
public abstract fun parse (Ljava/lang/String;Lorg/partiql/spi/Context;)Lorg/partiql/parser/PartiQLParser$Result;
public static fun standard ()Lorg/partiql/parser/PartiQLParser;
}

public final class org/partiql/parser/PartiQLParser$Companion {
public final fun builder ()Lorg/partiql/parser/PartiQLParserBuilder;
public final fun standard ()Lorg/partiql/parser/PartiQLParser;
}

public final class org/partiql/parser/PartiQLParser$DefaultImpls {
public static fun parse (Lorg/partiql/parser/PartiQLParser;Ljava/lang/String;)Lorg/partiql/parser/PartiQLParser$Result;
}

public final class org/partiql/parser/PartiQLParser$Result {
public static final field Companion Lorg/partiql/parser/PartiQLParser$Result$Companion;
public fun <init> (Ljava/lang/String;Lorg/partiql/ast/Statement;Lorg/partiql/parser/SourceLocations;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lorg/partiql/ast/Statement;
public final fun component3 ()Lorg/partiql/parser/SourceLocations;
public final fun copy (Ljava/lang/String;Lorg/partiql/ast/Statement;Lorg/partiql/parser/SourceLocations;)Lorg/partiql/parser/PartiQLParser$Result;
public static synthetic fun copy$default (Lorg/partiql/parser/PartiQLParser$Result;Ljava/lang/String;Lorg/partiql/ast/Statement;Lorg/partiql/parser/SourceLocations;ILjava/lang/Object;)Lorg/partiql/parser/PartiQLParser$Result;
public fun equals (Ljava/lang/Object;)Z
public final fun getLocations ()Lorg/partiql/parser/SourceLocations;
public final fun getRoot ()Lorg/partiql/ast/Statement;
public final fun getSource ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class org/partiql/parser/PartiQLParser$Result$Companion {
public field locations Lorg/partiql/spi/SourceLocations;
public field statements Ljava/util/List;
public fun <init> (Ljava/util/List;Lorg/partiql/spi/SourceLocations;)V
}

public final class org/partiql/parser/PartiQLParserBuilder {
public class org/partiql/parser/PartiQLParserBuilder {
public fun <init> ()V
public final fun build ()Lorg/partiql/parser/PartiQLParser;
}

public final class org/partiql/parser/SourceLocation {
public static final field Companion Lorg/partiql/parser/SourceLocation$Companion;
public fun <init> (IIII)V
public synthetic fun <init> (IIIIILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()I
public final fun component2 ()I
public final fun component3 ()I
public final fun component4 ()I
public final fun copy (IIII)Lorg/partiql/parser/SourceLocation;
public static synthetic fun copy$default (Lorg/partiql/parser/SourceLocation;IIIIILjava/lang/Object;)Lorg/partiql/parser/SourceLocation;
public fun equals (Ljava/lang/Object;)Z
public final fun getLength ()I
public final fun getLengthLegacy ()I
public final fun getLine ()I
public final fun getOffset ()I
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class org/partiql/parser/SourceLocation$Companion {
public final fun getUNKNOWN ()Lorg/partiql/parser/SourceLocation;
public fun build ()Lorg/partiql/parser/PartiQLParser;
}

public final class org/partiql/parser/SourceLocations : java/util/Map, kotlin/jvm/internal/markers/KMappedMarker {
public synthetic fun <init> (Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun clear ()V
public synthetic fun compute (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun compute (Ljava/lang/String;Ljava/util/function/BiFunction;)Lorg/partiql/parser/SourceLocation;
public synthetic fun computeIfAbsent (Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;
public fun computeIfAbsent (Ljava/lang/String;Ljava/util/function/Function;)Lorg/partiql/parser/SourceLocation;
public synthetic fun computeIfPresent (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun computeIfPresent (Ljava/lang/String;Ljava/util/function/BiFunction;)Lorg/partiql/parser/SourceLocation;
public final fun containsKey (Ljava/lang/Object;)Z
public fun containsKey (Ljava/lang/String;)Z
public final fun containsValue (Ljava/lang/Object;)Z
public fun containsValue (Lorg/partiql/parser/SourceLocation;)Z
public final fun entrySet ()Ljava/util/Set;
public final synthetic fun get (Ljava/lang/Object;)Ljava/lang/Object;
public final fun get (Ljava/lang/Object;)Lorg/partiql/parser/SourceLocation;
public fun get (Ljava/lang/String;)Lorg/partiql/parser/SourceLocation;
public fun getEntries ()Ljava/util/Set;
public fun getKeys ()Ljava/util/Set;
public fun getSize ()I
public fun getValues ()Ljava/util/Collection;
public fun isEmpty ()Z
public final fun keySet ()Ljava/util/Set;
public synthetic fun merge (Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun merge (Ljava/lang/String;Lorg/partiql/parser/SourceLocation;Ljava/util/function/BiFunction;)Lorg/partiql/parser/SourceLocation;
public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun put (Ljava/lang/String;Lorg/partiql/parser/SourceLocation;)Lorg/partiql/parser/SourceLocation;
public fun putAll (Ljava/util/Map;)V
public synthetic fun putIfAbsent (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun putIfAbsent (Ljava/lang/String;Lorg/partiql/parser/SourceLocation;)Lorg/partiql/parser/SourceLocation;
public synthetic fun remove (Ljava/lang/Object;)Ljava/lang/Object;
public fun remove (Ljava/lang/Object;)Lorg/partiql/parser/SourceLocation;
public fun remove (Ljava/lang/Object;Ljava/lang/Object;)Z
public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z
public fun replace (Ljava/lang/String;Lorg/partiql/parser/SourceLocation;)Lorg/partiql/parser/SourceLocation;
public fun replace (Ljava/lang/String;Lorg/partiql/parser/SourceLocation;Lorg/partiql/parser/SourceLocation;)Z
public fun replaceAll (Ljava/util/function/BiFunction;)V
public final fun size ()I
public final fun values ()Ljava/util/Collection;
}

public abstract interface class org/partiql/parser/V1PartiQLParser {
public static final field Companion Lorg/partiql/parser/V1PartiQLParser$Companion;
public static fun builder ()Lorg/partiql/parser/V1PartiQLParserBuilder;
public abstract fun parse (Ljava/lang/String;)Lorg/partiql/parser/V1PartiQLParser$Result;
public abstract fun parse (Ljava/lang/String;Lorg/partiql/spi/Context;)Lorg/partiql/parser/V1PartiQLParser$Result;
public static fun standard ()Lorg/partiql/parser/V1PartiQLParser;
}

public final class org/partiql/parser/V1PartiQLParser$Companion {
public final fun builder ()Lorg/partiql/parser/V1PartiQLParserBuilder;
public final fun standard ()Lorg/partiql/parser/V1PartiQLParser;
}

public final class org/partiql/parser/V1PartiQLParser$DefaultImpls {
public static fun parse (Lorg/partiql/parser/V1PartiQLParser;Ljava/lang/String;)Lorg/partiql/parser/V1PartiQLParser$Result;
}

public final class org/partiql/parser/V1PartiQLParser$Result {
public static final field Companion Lorg/partiql/parser/V1PartiQLParser$Result$Companion;
public fun <init> (Ljava/lang/String;Lorg/partiql/ast/v1/Statement;Lorg/partiql/parser/SourceLocations;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lorg/partiql/ast/v1/Statement;
public final fun component3 ()Lorg/partiql/parser/SourceLocations;
public final fun copy (Ljava/lang/String;Lorg/partiql/ast/v1/Statement;Lorg/partiql/parser/SourceLocations;)Lorg/partiql/parser/V1PartiQLParser$Result;
public static synthetic fun copy$default (Lorg/partiql/parser/V1PartiQLParser$Result;Ljava/lang/String;Lorg/partiql/ast/v1/Statement;Lorg/partiql/parser/SourceLocations;ILjava/lang/Object;)Lorg/partiql/parser/V1PartiQLParser$Result;
public fun equals (Ljava/lang/Object;)Z
public final fun getLocations ()Lorg/partiql/parser/SourceLocations;
public final fun getRoot ()Lorg/partiql/ast/v1/Statement;
public final fun getSource ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
public class org/partiql/parser/PartiQLParserBuilderV1 {
public fun <init> ()V
public fun build ()Lorg/partiql/parser/PartiQLParserV1;
}

public final class org/partiql/parser/V1PartiQLParser$Result$Companion {
public abstract interface class org/partiql/parser/PartiQLParserV1 {
public static fun builder ()Lorg/partiql/parser/PartiQLParserBuilderV1;
public fun parse (Ljava/lang/String;)Lorg/partiql/parser/PartiQLParserV1$Result;
public abstract fun parse (Ljava/lang/String;Lorg/partiql/spi/Context;)Lorg/partiql/parser/PartiQLParserV1$Result;
public static fun standard ()Lorg/partiql/parser/PartiQLParserV1;
}

public final class org/partiql/parser/V1PartiQLParserBuilder {
public fun <init> ()V
public final fun build ()Lorg/partiql/parser/V1PartiQLParser;
public final class org/partiql/parser/PartiQLParserV1$Result {
public field locations Lorg/partiql/spi/SourceLocations;
public field statements Ljava/util/List;
public fun <init> (Ljava/util/List;Lorg/partiql/spi/SourceLocations;)V
}

15 changes: 9 additions & 6 deletions partiql-parser/src/main/antlr/PartiQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ options {
*
*/

root
: (EXPLAIN (PAREN_LEFT explainOption (COMMA explainOption)* PAREN_RIGHT)? )? statement;
statements
: statement EOF
| statement COLON_SEMI (statement COLON_SEMI)* EOF
;

statement
: dql COLON_SEMI? EOF # QueryDql
| dml COLON_SEMI? EOF # QueryDml
| ddl COLON_SEMI? EOF # QueryDdl
| execCommand COLON_SEMI? EOF # QueryExec // TODO delete in `v1` release
: dql # QueryDql
| dml # QueryDml
| ddl # QueryDdl
| execCommand # QueryExec // TODO delete in `v1` release
| EXPLAIN (PAREN_LEFT explainOption (COMMA explainOption)* PAREN_RIGHT)? statement # Explain
;

/**
Expand Down
97 changes: 97 additions & 0 deletions partiql-parser/src/main/java/org/partiql/parser/PartiQLParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at:
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/

package org.partiql.parser;

import org.jetbrains.annotations.NotNull;
import org.partiql.ast.Statement;
import org.partiql.parser.internal.PartiQLParserDefault;
import org.partiql.spi.Context;
import org.partiql.spi.SourceLocations;
import org.partiql.spi.errors.PErrorListenerException;

import java.util.List;

/**
* TODO
*/
public interface PartiQLParser {

/**
* Parses the [source] into an AST.
* @param source the user's input
* @param ctx a configuration object for the parser
* @throws PErrorListenerException when the [org.partiql.spi.errors.PErrorListener] defined in the [ctx] throws an
* [PErrorListenerException], this method halts execution and propagates the exception.
*/
@NotNull
Result parse(@NotNull String source, @NotNull Context ctx) throws PErrorListenerException;

/**
* Parses the [source] into an AST.
* @param source the user's input
* @throws PErrorListenerException when the [org.partiql.spi.errors.PErrorListener] defined in the context throws an
* [PErrorListenerException], this method halts execution and propagates the exception.
*/
@NotNull
default Result parse(@NotNull String source) throws PErrorListenerException {
return parse(source, Context.standard());
}

/**
* TODO
*/
final class Result {

/**
* TODO
*/
@NotNull
public List<Statement> statements;

/**
* TODO
*/
@NotNull
public SourceLocations locations;

/**
* TODO
* @param statements TODO
* @param locations TODO
*/
public Result(@NotNull List<Statement> statements, @NotNull SourceLocations locations) {
this.statements = statements;
this.locations = locations;
}
}

/**
* TODO
* @return TODO
*/
@NotNull
public static PartiQLParserBuilder builder() {
return new PartiQLParserBuilder();
}

/**
* TODO
* @return TODO
*/
@NotNull
public static PartiQLParser standard() {
return new PartiQLParserDefault();
}
}
Loading
Loading