-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds configurable AST -> SQL printer (#1183)
- Loading branch information
Showing
9 changed files
with
2,738 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package org.partiql.ast.sql | ||
|
||
// a <> b <-> a concat b | ||
|
||
internal infix fun SqlBlock.concat(rhs: SqlBlock): SqlBlock = link(this, rhs) | ||
|
||
internal infix fun SqlBlock.concat(text: String): SqlBlock = link(this, text(text)) | ||
|
||
internal infix operator fun SqlBlock.plus(rhs: SqlBlock): SqlBlock = link(this, rhs) | ||
|
||
internal infix operator fun SqlBlock.plus(text: String): SqlBlock = link(this, text(text)) | ||
|
||
// Shorthand | ||
|
||
internal val NIL = SqlBlock.Nil | ||
|
||
internal val NL = SqlBlock.NL | ||
|
||
internal fun text(text: String) = SqlBlock.Text(text) | ||
|
||
internal fun link(lhs: SqlBlock, rhs: SqlBlock) = SqlBlock.Link(lhs, rhs) | ||
|
||
internal fun nest(block: () -> SqlBlock) = SqlBlock.Nest(block()) | ||
|
||
internal fun list(start: String?, end: String?, delimiter: String? = ",", items: () -> List<SqlBlock>): SqlBlock { | ||
var h: SqlBlock = NIL | ||
h = if (start != null) h + start else h | ||
h += nest { | ||
val kids = items() | ||
var list: SqlBlock = NIL | ||
kids.foldIndexed(list) { i, a, item -> | ||
list += item | ||
list = if (delimiter != null && (i + 1) < kids.size) a + delimiter else a | ||
list | ||
} | ||
} | ||
h = if (end != null) h + end else h | ||
return h | ||
} |
89 changes: 89 additions & 0 deletions
89
partiql-ast/src/main/kotlin/org/partiql/ast/sql/SqlBlock.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.partiql.ast.sql | ||
|
||
/** | ||
* Write this [SqlBlock] tree as SQL text with the given [SqlLayout]. | ||
* | ||
* @param layout SQL formatting ruleset | ||
* @return SQL text | ||
*/ | ||
public fun SqlBlock.sql(layout: SqlLayout = SqlLayout.DEFAULT): String = layout.format(this) | ||
|
||
/** | ||
* Representation of some textual corpus; akin to Wadler's "A prettier printer" Document type. | ||
*/ | ||
sealed interface SqlBlock { | ||
|
||
public override fun toString(): String | ||
|
||
public fun <R, C> accept(visitor: BlockVisitor<R, C>, ctx: C): R | ||
|
||
public object Nil : SqlBlock { | ||
|
||
override fun toString() = "" | ||
|
||
override fun <R, C> accept(visitor: BlockVisitor<R, C>, ctx: C): R = visitor.visitNil(this, ctx) | ||
} | ||
|
||
public object NL : SqlBlock { | ||
|
||
override fun toString() = "\n" | ||
|
||
override fun <R, C> accept(visitor: BlockVisitor<R, C>, ctx: C): R = visitor.visitNewline(this, ctx) | ||
} | ||
|
||
public class Text(val text: String) : SqlBlock { | ||
|
||
override fun toString() = text | ||
|
||
override fun <R, C> accept(visitor: BlockVisitor<R, C>, ctx: C): R = visitor.visitText(this, ctx) | ||
} | ||
|
||
public class Nest(val child: SqlBlock) : SqlBlock { | ||
|
||
override fun toString() = child.toString() | ||
|
||
override fun <R, C> accept(visitor: BlockVisitor<R, C>, ctx: C): R = visitor.visitNest(this, ctx) | ||
} | ||
|
||
// Use link block rather than linked-list block.next as it makes pre-order traversal trivial | ||
public class Link(val lhs: SqlBlock, val rhs: SqlBlock) : SqlBlock { | ||
|
||
override fun toString() = lhs.toString() + rhs.toString() | ||
|
||
override fun <R, C> accept(visitor: BlockVisitor<R, C>, ctx: C): R = visitor.visitLink(this, ctx) | ||
} | ||
} | ||
|
||
public interface BlockVisitor<R, C> { | ||
|
||
public fun visit(block: SqlBlock, ctx: C): R | ||
|
||
public fun visitNil(block: SqlBlock.Nil, ctx: C): R | ||
|
||
public fun visitNewline(block: SqlBlock.NL, ctx: C): R | ||
|
||
public fun visitText(block: SqlBlock.Text, ctx: C): R | ||
|
||
public fun visitNest(block: SqlBlock.Nest, ctx: C): R | ||
|
||
public fun visitLink(block: SqlBlock.Link, ctx: C): R | ||
} | ||
|
||
public abstract class BlockBaseVisitor<R, C> : BlockVisitor<R, C> { | ||
|
||
public abstract fun defaultReturn(block: SqlBlock, ctx: C): R | ||
|
||
public open fun defaultVisit(block: SqlBlock, ctx: C) = defaultReturn(block, ctx) | ||
|
||
public override fun visit(block: SqlBlock, ctx: C): R = block.accept(this, ctx) | ||
|
||
public override fun visitNil(block: SqlBlock.Nil, ctx: C): R = defaultVisit(block, ctx) | ||
|
||
public override fun visitNewline(block: SqlBlock.NL, ctx: C): R = defaultVisit(block, ctx) | ||
|
||
public override fun visitText(block: SqlBlock.Text, ctx: C): R = defaultVisit(block, ctx) | ||
|
||
public override fun visitNest(block: SqlBlock.Nest, ctx: C): R = defaultVisit(block, ctx) | ||
|
||
public override fun visitLink(block: SqlBlock.Link, ctx: C): R = defaultVisit(block, ctx) | ||
} |
Oops, something went wrong.