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

Initialize partiql-parser package with partiql-ast IR #1142

Merged
merged 10 commits into from
Jul 13, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class KotlinUtilsPoem(symbols: KotlinSymbols) : KotlinPoem(symbols) {
private val suppressUnused = AnnotationSpec.builder(Suppress::class)
.useSiteTarget(AnnotationSpec.UseSiteTarget.FILE)
.addMember("%S", "UNUSED_PARAMETER")
.addMember("%S", "UNUSED_VARIABLE")
.build()

// Not taking a dep on builder or visitor poems, as this is temporary
Expand Down Expand Up @@ -107,8 +108,8 @@ class KotlinUtilsPoem(symbols: KotlinSymbols) : KotlinPoem(symbols) {
// Node N -> visitN(node.n, ctx) as N
// Node N? -> node.n?.let { visitN(it, ctx) as N }
// Collection<N> -> rewrite(node, ctx, ::method)
// Collection?<N> -> node.n?.let { rewrite(it, ctx, ::method) }
// Collection?<N?> -> node.n?.let { rewrite(it, ctx, ::method) }
// Collection<N>? -> node.n?.let { rewrite(it, ctx, ::method) }
// Collection<N?>? -> node.n?.let { rewrite(it, ctx, ::method) }
// Collection<N?> -> rewrite(node, ctx, ::method)

private fun KotlinNodeSpec.Product.rewriter(): FunSpec {
Expand Down Expand Up @@ -139,17 +140,25 @@ class KotlinUtilsPoem(symbols: KotlinSymbols) : KotlinPoem(symbols) {
(ref is TypeRef.List && isNode(ref.type)) -> {
// Collections
val method = (ref.type as TypeRef.Path).visitMethodName()
val helper = when (ref.type.nullable) {
true -> "_visitListNull"
else -> "_visitList"
}
when (ref.nullable) {
true -> addStatement("val $name = $child?.let { _visitListNull(it, ctx, ::$method) }")
false -> addStatement("val $name = _visitList($child, ctx, ::$method)")
true -> addStatement("val $name = $child?.let { $helper(it, ctx, ::$method) }")
false -> addStatement("val $name = $helper($child, ctx, ::$method)")
}
}
(ref is TypeRef.Set && isNode(ref.type)) -> {
// Collections
val method = (ref.type as TypeRef.Path).visitMethodName()
val helper = when (ref.type.nullable) {
true -> "_visitSetNull"
else -> "_visitSet"
}
when (ref.nullable) {
true -> addStatement("val $name = $child?.let { _visitSetNull(it, ctx, ::$method) }")
false -> addStatement("val $name = _visitSet($child, ctx, ::$method)")
true -> addStatement("val $name = $child?.let { $helper(it, ctx, ::$method) }")
false -> addStatement("val $name = $helper($child, ctx, ::$method)")
}
}
else -> {
Expand Down
29 changes: 25 additions & 4 deletions partiql-ast/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ plugins {
dependencies {
api(Deps.pigRuntime)
api(Deps.ionElement)
implementation(project(":partiql-types"))
RCHowell marked this conversation as resolved.
Show resolved Hide resolved
}

publish {
artifactId = "partiql-ast"
name = "PartiQL AST"
description = "PartiQL's Abstract Syntax Tree"
}

pig {
Expand All @@ -45,8 +52,22 @@ kotlin {
explicitApi = null
}

publish {
artifactId = "partiql-ast"
name = "PartiQL AST"
description = "PartiQL's Abstract Syntax Tree"
val generate = tasks.register<Exec>("generate") {
dependsOn(":lib:sprout:install")
workingDir(projectDir)
commandLine(
"../lib/sprout/build/install/sprout/bin/sprout", "generate", "kotlin",
"-o", "$buildDir/generated-src",
"-p", "org.partiql.ast",
"-u", "Ast",
"--poems", "visitor",
"--poems", "builder",
"--poems", "util",
"--opt-in", "org.partiql.value.PartiQLValueExperimental",
"./src/main/resources/partiql_ast.ion"
)
}

tasks.compileKotlin {
dependsOn(generate)
}
15 changes: 15 additions & 0 deletions partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.partiql.ast

import org.partiql.ast.builder.AstFactoryImpl

/**
* Singleton instance of the default factory; also accessible via `AstFactory.DEFAULT`.
*/
object Ast : AstBaseFactory()

/**
* AstBaseFactory can be used to create a factory which extends from the factory provided by AstFactory.DEFAULT.
*/
public abstract class AstBaseFactory : AstFactoryImpl() {
// internal default overrides here
}
114 changes: 114 additions & 0 deletions partiql-ast/src/main/kotlin/org/partiql/ast/helpers/ToIon.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.partiql.ast.helpers

import com.amazon.ion.Decimal
import com.amazon.ion.Timestamp
import com.amazon.ionelement.api.IonElement
import com.amazon.ionelement.api.field
import com.amazon.ionelement.api.ionBlob
import com.amazon.ionelement.api.ionBool
import com.amazon.ionelement.api.ionClob
import com.amazon.ionelement.api.ionDecimal
import com.amazon.ionelement.api.ionFloat
import com.amazon.ionelement.api.ionInt
import com.amazon.ionelement.api.ionListOf
import com.amazon.ionelement.api.ionNull
import com.amazon.ionelement.api.ionSexpOf
import com.amazon.ionelement.api.ionString
import com.amazon.ionelement.api.ionStructOf
import com.amazon.ionelement.api.ionSymbol
import com.amazon.ionelement.api.ionTimestamp
import org.partiql.value.BlobValue
import org.partiql.value.BoolValue
import org.partiql.value.ClobValue
import org.partiql.value.CollectionValue
import org.partiql.value.DecimalValue
import org.partiql.value.Float32Value
import org.partiql.value.Float64Value
import org.partiql.value.Int16Value
import org.partiql.value.Int32Value
import org.partiql.value.Int64Value
import org.partiql.value.Int8Value
import org.partiql.value.IntValue
import org.partiql.value.ListValue
import org.partiql.value.NullValue
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.ScalarValue
import org.partiql.value.SexpValue
import org.partiql.value.StringValue
import org.partiql.value.StructValue
import org.partiql.value.SymbolValue
import org.partiql.value.TimestampValue
import org.partiql.value.util.PartiQLValueBaseVisitor

/**
* PartiQL Value .toIon helper
*
* TODO add `lower` mode, this just errors
*/
@OptIn(PartiQLValueExperimental::class)
internal object ToIon : PartiQLValueBaseVisitor<IonElement, Unit>() {

private inline fun <T> ScalarValue<T>.toIon(block: ScalarValue<T>.() -> IonElement): IonElement {
val e = this.block()
return e.withAnnotations(this.annotations)
}

private inline fun CollectionValue<*>.toIon(block: CollectionValue<*>.(elements: List<IonElement>) -> IonElement): IonElement {
val elements = this.elements.map { it.accept(ToIon, Unit) }
val e = this.block(elements)
return e.withAnnotations(this.annotations)
}

override fun defaultVisit(v: PartiQLValue, ctx: Unit) = defaultReturn(v, ctx)

override fun defaultReturn(v: PartiQLValue, ctx: Unit) =
throw IllegalArgumentException("Cannot represent $v as Ion in strict mode")

override fun visitNull(v: NullValue, ctx: Unit) = ionNull().withAnnotations(v.annotations)

override fun visitBool(v: BoolValue, ctx: Unit) = v.toIon { ionBool(value) }

override fun visitInt8(v: Int8Value, ctx: Unit) = v.toIon { ionInt(value.toLong()) }

override fun visitInt16(v: Int16Value, ctx: Unit) = v.toIon { ionInt(value.toLong()) }

override fun visitInt32(v: Int32Value, ctx: Unit) = v.toIon { ionInt(value.toLong()) }

override fun visitInt64(v: Int64Value, ctx: Unit) = v.toIon { ionInt(value) }

// Call .toLong() because IonElement .equals() is failing with BigInteger (it's comparing by reference).
override fun visitInt(v: IntValue, ctx: Unit) = v.toIon { ionInt(value.toLong()) }

override fun visitDecimal(v: DecimalValue, ctx: Unit) = v.toIon { ionDecimal(Decimal.valueOf(value)) }

override fun visitFloat32(v: Float32Value, ctx: Unit) = v.toIon { ionFloat(value.toString().toDouble()) }

override fun visitFloat64(v: Float64Value, ctx: Unit) = v.toIon { ionFloat(value) }

override fun visitString(v: StringValue, ctx: Unit) = v.toIon { ionString(value) }

override fun visitSymbol(v: SymbolValue, ctx: Unit) = v.toIon { ionSymbol(value) }

override fun visitClob(v: ClobValue, ctx: Unit) = v.toIon { ionClob(value) }

override fun visitBlob(v: BlobValue, ctx: Unit) = v.toIon { ionBlob(value) }

override fun visitTimestamp(v: TimestampValue, ctx: Unit) = v.toIon {
val sql = java.sql.Timestamp.valueOf(value)
ionTimestamp(Timestamp.forSqlTimestampZ(sql))
}

override fun visitList(v: ListValue<*>, ctx: Unit) = v.toIon { elements -> ionListOf(elements) }

override fun visitSexp(v: SexpValue<*>, ctx: Unit) = v.toIon { elements -> ionSexpOf(elements) }

override fun visitStruct(v: StructValue<*>, ctx: Unit): IonElement {
val fields = v.fields.map {
val key = it.first
val value = it.second.accept(this, ctx)
field(key, value)
}
return ionStructOf(fields, v.annotations)
}
}
Loading