mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 13:11:32 +00:00
ast: utilize extension functions to prevent larger stack frames from default interface methods
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class Block(val expressions: List<Expression>) : Node() {
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitAll(expressions)
|
visitor.visitAll(expressions)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitBlock(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Block) return false
|
if (other !is Block) return false
|
||||||
return other.expressions == expressions
|
return other.expressions == expressions
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -8,6 +9,9 @@ import kotlinx.serialization.Serializable
|
|||||||
class BooleanLiteral(val value: Boolean) : Expression() {
|
class BooleanLiteral(val value: Boolean) : Expression() {
|
||||||
override val type: NodeType = NodeType.BooleanLiteral
|
override val type: NodeType = NodeType.BooleanLiteral
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitBooleanLiteral(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is BooleanLiteral) return false
|
if (other !is BooleanLiteral) return false
|
||||||
return other.value == value
|
return other.value == value
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class CompilationUnit(val declarations: List<Declaration>, val definitions: List
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitAll(declarations, definitions)
|
visitor.visitAll(declarations, definitions)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitCompilationUnit(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is CompilationUnit) return false
|
if (other !is CompilationUnit) return false
|
||||||
return other.declarations == declarations && other.definitions == definitions
|
return other.declarations == declarations && other.definitions == definitions
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class FunctionCall(val symbol: Symbol, val arguments: List<Expression>) : Expres
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitAll(listOf(symbol), arguments)
|
visitor.visitAll(listOf(symbol), arguments)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitFunctionCall(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is FunctionCall) return false
|
if (other !is FunctionCall) return false
|
||||||
return other.symbol == symbol && other.arguments == arguments
|
return other.symbol == symbol && other.arguments == arguments
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class FunctionDefinition(override val modifiers: DefinitionModifiers, override v
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitAll(listOf(symbol), arguments, listOf(block))
|
visitor.visitAll(listOf(symbol), arguments, listOf(block))
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitFunctionDefinition(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is FunctionDefinition) return false
|
if (other !is FunctionDefinition) return false
|
||||||
return other.modifiers == modifiers && other.symbol == symbol && other.arguments == arguments && other.block == block
|
return other.modifiers == modifiers && other.symbol == symbol && other.arguments == arguments && other.block == block
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class If(val condition: Expression, val thenExpression: Expression, val elseExpr
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(condition, thenExpression, elseExpression)
|
visitor.visitNodes(condition, thenExpression, elseExpression)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitIf(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is If) return false
|
if (other !is If) return false
|
||||||
return other.condition == condition && other.thenExpression == thenExpression && other.elseExpression == elseExpression
|
return other.condition == condition && other.thenExpression == thenExpression && other.elseExpression == elseExpression
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class ImportDeclaration(val path: StringLiteral) : Declaration() {
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(path)
|
visitor.visitNodes(path)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitImportDeclaration(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is ImportDeclaration) return false
|
if (other !is ImportDeclaration) return false
|
||||||
return other.path == path
|
return other.path == path
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class InfixOperation(val left: Expression, val op: InfixOperator, val right: Exp
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(left, right)
|
visitor.visitNodes(left, right)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitInfixOperation(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is InfixOperation) return false
|
if (other !is InfixOperation) return false
|
||||||
return other.left == left && other.op == op && other.right == right
|
return other.left == left && other.op == op && other.right == right
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -8,6 +9,9 @@ import kotlinx.serialization.Serializable
|
|||||||
class IntLiteral(val value: Int) : Expression() {
|
class IntLiteral(val value: Int) : Expression() {
|
||||||
override val type: NodeType = NodeType.IntLiteral
|
override val type: NodeType = NodeType.IntLiteral
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitIntLiteral(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is IntLiteral) return false
|
if (other !is IntLiteral) return false
|
||||||
return other.value == value
|
return other.value == value
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class Lambda(val arguments: List<Symbol>, val expressions: List<Expression>) : E
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitAll(arguments, expressions)
|
visitor.visitAll(arguments, expressions)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitLambda(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Lambda) return false
|
if (other !is Lambda) return false
|
||||||
return other.arguments == arguments && other.expressions == expressions
|
return other.arguments == arguments && other.expressions == expressions
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class LetAssignment(val symbol: Symbol, val value: Expression) : Expression() {
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(symbol, value)
|
visitor.visitNodes(symbol, value)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitLetAssignment(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is LetAssignment) return false
|
if (other !is LetAssignment) return false
|
||||||
return other.symbol == symbol && other.value == value
|
return other.symbol == symbol && other.value == value
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class ListLiteral(val items: List<Expression>) : Expression() {
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitAll(items)
|
visitor.visitAll(items)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitListLiteral(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is ListLiteral) return false
|
if (other !is ListLiteral) return false
|
||||||
return other.items == items
|
return other.items == items
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -10,4 +11,7 @@ sealed class Node {
|
|||||||
|
|
||||||
open fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
open fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
emptyList()
|
emptyList()
|
||||||
|
|
||||||
|
open fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visit(this)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
enum class NodeType(val parent: NodeType? = null) {
|
enum class NodeType(val parent: NodeType? = null) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
interface NodeVisitor<T> {
|
interface NodeVisitor<T> {
|
||||||
@ -34,31 +35,4 @@ interface NodeVisitor<T> {
|
|||||||
fun visitSymbol(node: Symbol): T
|
fun visitSymbol(node: Symbol): T
|
||||||
|
|
||||||
fun visitSymbolReference(node: SymbolReference): T
|
fun visitSymbolReference(node: SymbolReference): T
|
||||||
|
|
||||||
fun visitNodes(vararg nodes: Node?): List<T> =
|
|
||||||
nodes.asSequence().filterNotNull().map { visit(it) }.toList()
|
|
||||||
|
|
||||||
fun visitAll(vararg nodeLists: List<Node>): List<T> =
|
|
||||||
nodeLists.asSequence().flatten().map { visit(it) }.toList()
|
|
||||||
|
|
||||||
fun visit(node: Node): T =
|
|
||||||
when (node) {
|
|
||||||
is Symbol -> visitSymbol(node)
|
|
||||||
is Block -> visitBlock(node)
|
|
||||||
is CompilationUnit -> visitCompilationUnit(node)
|
|
||||||
is LetAssignment -> visitLetAssignment(node)
|
|
||||||
is InfixOperation -> visitInfixOperation(node)
|
|
||||||
is BooleanLiteral -> visitBooleanLiteral(node)
|
|
||||||
is FunctionCall -> visitFunctionCall(node)
|
|
||||||
is FunctionDefinition -> visitFunctionDefinition(node)
|
|
||||||
is If -> visitIf(node)
|
|
||||||
is ImportDeclaration -> visitImportDeclaration(node)
|
|
||||||
is IntLiteral -> visitIntLiteral(node)
|
|
||||||
is Lambda -> visitLambda(node)
|
|
||||||
is ListLiteral -> visitListLiteral(node)
|
|
||||||
is Parentheses -> visitParentheses(node)
|
|
||||||
is PrefixOperation -> visitPrefixOperation(node)
|
|
||||||
is StringLiteral -> visitStringLiteral(node)
|
|
||||||
is SymbolReference -> visitSymbolReference(node)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
|
fun <T> NodeVisitor<T>.visit(node: Node): T =
|
||||||
|
when (node) {
|
||||||
|
is Symbol -> visitSymbol(node)
|
||||||
|
is Block -> visitBlock(node)
|
||||||
|
is CompilationUnit -> visitCompilationUnit(node)
|
||||||
|
is LetAssignment -> visitLetAssignment(node)
|
||||||
|
is InfixOperation -> visitInfixOperation(node)
|
||||||
|
is BooleanLiteral -> visitBooleanLiteral(node)
|
||||||
|
is FunctionCall -> visitFunctionCall(node)
|
||||||
|
is FunctionDefinition -> visitFunctionDefinition(node)
|
||||||
|
is If -> visitIf(node)
|
||||||
|
is ImportDeclaration -> visitImportDeclaration(node)
|
||||||
|
is IntLiteral -> visitIntLiteral(node)
|
||||||
|
is Lambda -> visitLambda(node)
|
||||||
|
is ListLiteral -> visitListLiteral(node)
|
||||||
|
is Parentheses -> visitParentheses(node)
|
||||||
|
is PrefixOperation -> visitPrefixOperation(node)
|
||||||
|
is StringLiteral -> visitStringLiteral(node)
|
||||||
|
is SymbolReference -> visitSymbolReference(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> NodeVisitor<T>.visitNodes(vararg nodes: Node?): List<T> =
|
||||||
|
nodes.asSequence().filterNotNull().map { visit(it) }.toList()
|
||||||
|
|
||||||
|
fun <T> NodeVisitor<T>.visitAll(vararg nodeLists: List<Node>): List<T> =
|
||||||
|
nodeLists.asSequence().flatten().map { visit(it) }.toList()
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class Parentheses(val expression: Expression) : Expression() {
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(expression)
|
visitor.visitNodes(expression)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitParentheses(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Parentheses) return false
|
if (other !is Parentheses) return false
|
||||||
return other.expression == expression
|
return other.expression == expression
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class PrefixOperation(val op: PrefixOperator, val expression: Expression) : Expr
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(expression)
|
visitor.visitNodes(expression)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitPrefixOperation(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is PrefixOperation) return false
|
if (other !is PrefixOperation) return false
|
||||||
return other.op == op && other.expression == expression
|
return other.op == op && other.expression == expression
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -8,6 +9,9 @@ import kotlinx.serialization.Serializable
|
|||||||
class StringLiteral(val text: String) : Expression() {
|
class StringLiteral(val text: String) : Expression() {
|
||||||
override val type: NodeType = NodeType.StringLiteral
|
override val type: NodeType = NodeType.StringLiteral
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitStringLiteral(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is StringLiteral) return false
|
if (other !is StringLiteral) return false
|
||||||
return other.text == text
|
return other.text == text
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -8,6 +9,9 @@ import kotlinx.serialization.Serializable
|
|||||||
class Symbol(val id: String) : Node() {
|
class Symbol(val id: String) : Node() {
|
||||||
override val type: NodeType = NodeType.Symbol
|
override val type: NodeType = NodeType.Symbol
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitSymbol(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Symbol) return false
|
if (other !is Symbol) return false
|
||||||
return other.id == id
|
return other.id == id
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -11,6 +12,9 @@ class SymbolReference(val symbol: Symbol) : Expression() {
|
|||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
visitor.visitNodes(symbol)
|
visitor.visitNodes(symbol)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitSymbolReference(this)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is SymbolReference) return false
|
if (other !is SymbolReference) return false
|
||||||
return other.symbol == symbol
|
return other.symbol == symbol
|
||||||
|
@ -4,10 +4,7 @@ import org.gradle.api.JavaVersion
|
|||||||
import org.gradle.api.Plugin
|
import org.gradle.api.Plugin
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.plugins.JavaPluginExtension
|
import org.gradle.api.plugins.JavaPluginExtension
|
||||||
import org.gradle.kotlin.dsl.apply
|
import org.gradle.kotlin.dsl.*
|
||||||
import org.gradle.kotlin.dsl.dependencies
|
|
||||||
import org.gradle.kotlin.dsl.getByType
|
|
||||||
import org.gradle.kotlin.dsl.withType
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
open class PorkModulePlugin : Plugin<Project> {
|
open class PorkModulePlugin : Plugin<Project> {
|
||||||
@ -16,6 +13,7 @@ open class PorkModulePlugin : Plugin<Project> {
|
|||||||
target.apply(plugin = "org.jetbrains.kotlin.plugin.serialization")
|
target.apply(plugin = "org.jetbrains.kotlin.plugin.serialization")
|
||||||
|
|
||||||
target.repositories.mavenCentral()
|
target.repositories.mavenCentral()
|
||||||
|
target.repositories.maven(url = "https://gitlab.com/api/v4/projects/49101454/packages/maven")
|
||||||
|
|
||||||
target.extensions.getByType<JavaPluginExtension>().apply {
|
target.extensions.getByType<JavaPluginExtension>().apply {
|
||||||
val javaVersion = JavaVersion.toVersion(17)
|
val javaVersion = JavaVersion.toVersion(17)
|
||||||
@ -30,6 +28,8 @@ open class PorkModulePlugin : Plugin<Project> {
|
|||||||
target.dependencies {
|
target.dependencies {
|
||||||
add("implementation", "org.jetbrains.kotlin:kotlin-bom")
|
add("implementation", "org.jetbrains.kotlin:kotlin-bom")
|
||||||
add("implementation", "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
|
add("implementation", "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
|
||||||
|
add("api", "gay.pizza.dough:dough-core:0.1.0-SNAPSHOT")
|
||||||
|
add("api", "gay.pizza.dough:dough-fs:0.1.0-SNAPSHOT")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,9 +72,32 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
)
|
)
|
||||||
visitorInterface.functions.add(visitFunction)
|
visitorInterface.functions.add(visitFunction)
|
||||||
}
|
}
|
||||||
|
write("NodeVisitor.kt", KotlinWriter(visitorInterface))
|
||||||
|
|
||||||
|
val visitorExtensionSet = KotlinFunctionSet(pkg)
|
||||||
|
val visitAnyFunction = KotlinFunction(
|
||||||
|
"visit",
|
||||||
|
typeParameters = mutableListOf("T"),
|
||||||
|
extensionOf = "NodeVisitor<T>",
|
||||||
|
returnType = "T",
|
||||||
|
parameters = mutableListOf(
|
||||||
|
KotlinParameter("node", type = "Node")
|
||||||
|
),
|
||||||
|
isImmediateExpression = true
|
||||||
|
)
|
||||||
|
visitAnyFunction.body.add("when (node) {")
|
||||||
|
for (type in world.typeRegistry.types.filter {
|
||||||
|
world.typeRegistry.roleOfType(it) == AstTypeRole.AstNode
|
||||||
|
}) {
|
||||||
|
visitAnyFunction.body.add(" is ${type.name} -> visit${type.name}(node)")
|
||||||
|
}
|
||||||
|
visitAnyFunction.body.add("}")
|
||||||
|
visitorExtensionSet.functions.add(visitAnyFunction)
|
||||||
|
|
||||||
val visitNodesFunction = KotlinFunction(
|
val visitNodesFunction = KotlinFunction(
|
||||||
"visitNodes",
|
"visitNodes",
|
||||||
|
typeParameters = mutableListOf("T"),
|
||||||
|
extensionOf = "NodeVisitor<T>",
|
||||||
returnType = "List<T>",
|
returnType = "List<T>",
|
||||||
parameters = mutableListOf(
|
parameters = mutableListOf(
|
||||||
KotlinParameter("nodes", type = "Node?", vararg = true)
|
KotlinParameter("nodes", type = "Node?", vararg = true)
|
||||||
@ -82,10 +105,12 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
isImmediateExpression = true
|
isImmediateExpression = true
|
||||||
)
|
)
|
||||||
visitNodesFunction.body.add("nodes.asSequence().filterNotNull().map { visit(it) }.toList()")
|
visitNodesFunction.body.add("nodes.asSequence().filterNotNull().map { visit(it) }.toList()")
|
||||||
visitorInterface.functions.add(visitNodesFunction)
|
visitorExtensionSet.functions.add(visitNodesFunction)
|
||||||
|
|
||||||
val visitAllFunction = KotlinFunction(
|
val visitAllFunction = KotlinFunction(
|
||||||
"visitAll",
|
"visitAll",
|
||||||
|
typeParameters = mutableListOf("T"),
|
||||||
|
extensionOf = "NodeVisitor<T>",
|
||||||
returnType = "List<T>",
|
returnType = "List<T>",
|
||||||
parameters = mutableListOf(
|
parameters = mutableListOf(
|
||||||
KotlinParameter("nodeLists", type = "List<Node>", vararg = true)
|
KotlinParameter("nodeLists", type = "List<Node>", vararg = true)
|
||||||
@ -93,25 +118,9 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
isImmediateExpression = true
|
isImmediateExpression = true
|
||||||
)
|
)
|
||||||
visitAllFunction.body.add("nodeLists.asSequence().flatten().map { visit(it) }.toList()")
|
visitAllFunction.body.add("nodeLists.asSequence().flatten().map { visit(it) }.toList()")
|
||||||
visitorInterface.functions.add(visitAllFunction)
|
visitorExtensionSet.functions.add(visitAllFunction)
|
||||||
|
|
||||||
val visitFunction = KotlinFunction(
|
write("NodeVisitorExtensions.kt", KotlinWriter(visitorExtensionSet))
|
||||||
"visit",
|
|
||||||
returnType = "T",
|
|
||||||
parameters = mutableListOf(
|
|
||||||
KotlinParameter("node", type = "Node")
|
|
||||||
),
|
|
||||||
isImmediateExpression = true
|
|
||||||
)
|
|
||||||
|
|
||||||
visitFunction.body.add("when (node) {")
|
|
||||||
for (type in world.typeRegistry.types.filter { world.typeRegistry.roleOfType(it) == AstTypeRole.AstNode }) {
|
|
||||||
visitFunction.body.add(" is ${type.name} -> visit${type.name}(node)")
|
|
||||||
}
|
|
||||||
visitFunction.body.add("}")
|
|
||||||
visitorInterface.functions.add(visitFunction)
|
|
||||||
|
|
||||||
write("NodeVisitor.kt", KotlinWriter(visitorInterface))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeNodeCoalescer() {
|
private fun writeNodeCoalescer() {
|
||||||
@ -193,10 +202,21 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
),
|
),
|
||||||
isImmediateExpression = true
|
isImmediateExpression = true
|
||||||
)
|
)
|
||||||
|
|
||||||
abstractVisitChildrenFunction.body.add("emptyList()")
|
abstractVisitChildrenFunction.body.add("emptyList()")
|
||||||
|
|
||||||
kotlinClassLike.functions.add(abstractVisitChildrenFunction)
|
kotlinClassLike.functions.add(abstractVisitChildrenFunction)
|
||||||
|
|
||||||
|
val abstractVisitSelfFunction = KotlinFunction(
|
||||||
|
"visit",
|
||||||
|
returnType = "T",
|
||||||
|
open = true,
|
||||||
|
typeParameters = mutableListOf("T"),
|
||||||
|
parameters = mutableListOf(
|
||||||
|
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||||
|
),
|
||||||
|
isImmediateExpression = true
|
||||||
|
)
|
||||||
|
abstractVisitSelfFunction.body.add("visitor.visit(this)")
|
||||||
|
kotlinClassLike.functions.add(abstractVisitSelfFunction)
|
||||||
} else if (role == AstTypeRole.AstNode) {
|
} else if (role == AstTypeRole.AstNode) {
|
||||||
val typeMember = KotlinMember(
|
val typeMember = KotlinMember(
|
||||||
"type",
|
"type",
|
||||||
@ -245,21 +265,21 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
val visitChildrenFunction = KotlinFunction(
|
val visitChildrenFunction = KotlinFunction(
|
||||||
"visitChildren",
|
"visitChildren",
|
||||||
returnType = "List<T>",
|
returnType = "List<T>",
|
||||||
typeParameters = mutableListOf("T")
|
typeParameters = mutableListOf("T"),
|
||||||
|
overridden = true,
|
||||||
|
parameters = mutableListOf(
|
||||||
|
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||||
|
),
|
||||||
|
isImmediateExpression = true
|
||||||
)
|
)
|
||||||
visitChildrenFunction.overridden = true
|
|
||||||
val visitorParameter = KotlinParameter("visitor", "NodeVisitor<T>")
|
|
||||||
visitChildrenFunction.parameters.add(visitorParameter)
|
|
||||||
|
|
||||||
visitChildrenFunction.isImmediateExpression = true
|
|
||||||
|
|
||||||
val anyListMembers = type.values.any { it.typeRef.form == AstTypeRefForm.List }
|
val anyListMembers = type.values.any { it.typeRef.form == AstTypeRefForm.List }
|
||||||
val elideVisitChildren: Boolean
|
val elideVisitChildren: Boolean
|
||||||
if (anyListMembers) {
|
if (anyListMembers) {
|
||||||
val visitParameters = type.values.mapNotNull {
|
val visitParameters = type.values.mapNotNull {
|
||||||
if (it.typeRef.primitive != null) {
|
if (it.typeRef.primitive != null) {
|
||||||
null
|
null
|
||||||
} else if (it.typeRef.type != null && !world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
} else if (it.typeRef.type != null &&
|
||||||
|
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
||||||
null
|
null
|
||||||
} else if (it.typeRef.form == AstTypeRefForm.Single) {
|
} else if (it.typeRef.form == AstTypeRefForm.Single) {
|
||||||
"listOf(${it.name})"
|
"listOf(${it.name})"
|
||||||
@ -273,7 +293,8 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
val visitParameters = type.values.mapNotNull {
|
val visitParameters = type.values.mapNotNull {
|
||||||
if (it.typeRef.primitive != null) {
|
if (it.typeRef.primitive != null) {
|
||||||
null
|
null
|
||||||
} else if (it.typeRef.type != null && !world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
} else if (it.typeRef.type != null &&
|
||||||
|
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
it.name
|
it.name
|
||||||
@ -287,7 +308,22 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
kotlinClassLike.functions.add(visitChildrenFunction)
|
kotlinClassLike.functions.add(visitChildrenFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
val equalsAndHashCodeMembers = kotlinClassLike.members.map { it.name }.sortedBy { it == "type" }
|
val visitSelfFunction = KotlinFunction(
|
||||||
|
"visit",
|
||||||
|
returnType = "T",
|
||||||
|
typeParameters = mutableListOf("T"),
|
||||||
|
overridden = true,
|
||||||
|
parameters = mutableListOf(
|
||||||
|
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||||
|
),
|
||||||
|
isImmediateExpression = true
|
||||||
|
)
|
||||||
|
visitSelfFunction.body.add("visitor.visit${type.name}(this)")
|
||||||
|
kotlinClassLike.functions.add(visitSelfFunction)
|
||||||
|
|
||||||
|
val equalsAndHashCodeMembers = kotlinClassLike.members.map {
|
||||||
|
it.name
|
||||||
|
}.sortedBy { it == "type" }
|
||||||
val equalsFunction = KotlinFunction(
|
val equalsFunction = KotlinFunction(
|
||||||
"equals",
|
"equals",
|
||||||
returnType = "Boolean",
|
returnType = "Boolean",
|
||||||
@ -348,9 +384,10 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun write(fileName: String, writer: KotlinWriter) {
|
private fun write(fileName: String, writer: KotlinWriter) {
|
||||||
|
val content = "// GENERATED CODE FROM PORK AST CODEGEN\n$writer"
|
||||||
val path = outputDirectory.resolve(fileName)
|
val path = outputDirectory.resolve(fileName)
|
||||||
path.deleteIfExists()
|
path.deleteIfExists()
|
||||||
path.writeText(writer.toString(), StandardCharsets.UTF_8)
|
path.writeText(content, StandardCharsets.UTF_8)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -3,6 +3,7 @@ package gay.pizza.pork.buildext.codegen
|
|||||||
class KotlinFunction(
|
class KotlinFunction(
|
||||||
val name: String,
|
val name: String,
|
||||||
var typeParameters: MutableList<String> = mutableListOf(),
|
var typeParameters: MutableList<String> = mutableListOf(),
|
||||||
|
var extensionOf: String? = null,
|
||||||
var parameters: MutableList<KotlinParameter> = mutableListOf(),
|
var parameters: MutableList<KotlinParameter> = mutableListOf(),
|
||||||
var returnType: String? = null,
|
var returnType: String? = null,
|
||||||
var abstract: Boolean = false,
|
var abstract: Boolean = false,
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.buildext.codegen
|
||||||
|
|
||||||
|
class KotlinFunctionSet(
|
||||||
|
val pkg: String,
|
||||||
|
var imports: MutableList<String> = mutableListOf(),
|
||||||
|
var functions: MutableList<KotlinFunction> = mutableListOf()
|
||||||
|
)
|
@ -3,8 +3,8 @@ package gay.pizza.pork.buildext.codegen
|
|||||||
class KotlinWriter() {
|
class KotlinWriter() {
|
||||||
private val buffer = StringBuilder()
|
private val buffer = StringBuilder()
|
||||||
|
|
||||||
constructor(kotlinClassLike: KotlinClassLike) : this() {
|
constructor(writable: Any) : this() {
|
||||||
write(kotlinClassLike)
|
write(writable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeClass(kotlinClass: KotlinClass): Unit = buffer.run {
|
fun writeClass(kotlinClass: KotlinClass): Unit = buffer.run {
|
||||||
@ -96,16 +96,7 @@ class KotlinWriter() {
|
|||||||
classType: String,
|
classType: String,
|
||||||
kotlinClass: KotlinClassLike
|
kotlinClass: KotlinClassLike
|
||||||
): Unit = buffer.run {
|
): Unit = buffer.run {
|
||||||
appendLine("package ${kotlinClass.pkg}")
|
writeHeader(kotlinClass.pkg, kotlinClass.imports)
|
||||||
appendLine()
|
|
||||||
|
|
||||||
for (import in kotlinClass.imports) {
|
|
||||||
appendLine("import $import")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kotlinClass.imports.isNotEmpty()) {
|
|
||||||
appendLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (annotation in kotlinClass.annotations) {
|
for (annotation in kotlinClass.annotations) {
|
||||||
appendLine("@${annotation}")
|
appendLine("@${annotation}")
|
||||||
@ -138,76 +129,110 @@ class KotlinWriter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeFunctions(kotlinClassLike: KotlinClassLike): Unit = buffer.run {
|
private fun writeHeader(pkg: String, imports: List<String>): Unit = buffer.run {
|
||||||
for ((index, function) in kotlinClassLike.functions.withIndex()) {
|
appendLine("package $pkg")
|
||||||
append(" ")
|
appendLine()
|
||||||
|
|
||||||
if (function.overridden) {
|
for (import in imports) {
|
||||||
append("override ")
|
appendLine("import $import")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (function.abstract) {
|
if (imports.isNotEmpty()) {
|
||||||
append("abstract ")
|
appendLine()
|
||||||
}
|
|
||||||
|
|
||||||
if (function.open) {
|
|
||||||
append("open ")
|
|
||||||
}
|
|
||||||
|
|
||||||
append("fun ")
|
|
||||||
if (function.typeParameters.isNotEmpty()) {
|
|
||||||
append("<${function.typeParameters.joinToString(", ")}> ")
|
|
||||||
}
|
|
||||||
append("${function.name}(")
|
|
||||||
append(function.parameters.joinToString(", ") {
|
|
||||||
var start = "${it.name}: ${it.type}"
|
|
||||||
if (it.vararg) {
|
|
||||||
start = "vararg $start"
|
|
||||||
}
|
|
||||||
if (it.defaultValue != null) {
|
|
||||||
start + " = ${it.defaultValue}"
|
|
||||||
} else start
|
|
||||||
})
|
|
||||||
append(")")
|
|
||||||
if (function.returnType != null) {
|
|
||||||
append(": ${function.returnType}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function.isImmediateExpression && !function.abstract && !function.isInterfaceMethod) {
|
|
||||||
append(" {")
|
|
||||||
} else if (!function.abstract && !function.isInterfaceMethod) {
|
|
||||||
append(" =")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (function.body.isNotEmpty()) {
|
|
||||||
appendLine()
|
|
||||||
|
|
||||||
for (item in function.body) {
|
|
||||||
appendLine(" $item")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function.isImmediateExpression && !function.abstract && !function.isInterfaceMethod) {
|
|
||||||
if (function.body.isNotEmpty()) {
|
|
||||||
append(" ")
|
|
||||||
}
|
|
||||||
appendLine("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (function.abstract || function.isInterfaceMethod) {
|
|
||||||
appendLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < kotlinClassLike.functions.size - 1) {
|
|
||||||
appendLine()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun write(input: KotlinClassLike): Unit = when (input) {
|
fun writeFunction(function: KotlinFunction, index: Int = 0, functionCount: Int = 1, indent: String = ""): Unit = buffer.run {
|
||||||
|
append(indent)
|
||||||
|
|
||||||
|
if (function.overridden) {
|
||||||
|
append("override ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function.abstract) {
|
||||||
|
append("abstract ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function.open) {
|
||||||
|
append("open ")
|
||||||
|
}
|
||||||
|
|
||||||
|
append("fun ")
|
||||||
|
if (function.typeParameters.isNotEmpty()) {
|
||||||
|
append("<${function.typeParameters.joinToString(", ")}> ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function.extensionOf != null) {
|
||||||
|
append("${function.extensionOf}.")
|
||||||
|
}
|
||||||
|
|
||||||
|
append("${function.name}(")
|
||||||
|
append(function.parameters.joinToString(", ") {
|
||||||
|
var start = "${it.name}: ${it.type}"
|
||||||
|
if (it.vararg) {
|
||||||
|
start = "vararg $start"
|
||||||
|
}
|
||||||
|
if (it.defaultValue != null) {
|
||||||
|
start + " = ${it.defaultValue}"
|
||||||
|
} else start
|
||||||
|
})
|
||||||
|
append(")")
|
||||||
|
if (function.returnType != null) {
|
||||||
|
append(": ${function.returnType}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function.isImmediateExpression && !function.abstract && !function.isInterfaceMethod) {
|
||||||
|
append(" {")
|
||||||
|
} else if (!function.abstract && !function.isInterfaceMethod) {
|
||||||
|
append(" =")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function.body.isNotEmpty()) {
|
||||||
|
appendLine()
|
||||||
|
|
||||||
|
for (item in function.body) {
|
||||||
|
appendLine("$indent $item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function.isImmediateExpression && !function.abstract && !function.isInterfaceMethod) {
|
||||||
|
if (function.body.isNotEmpty()) {
|
||||||
|
append(indent)
|
||||||
|
}
|
||||||
|
appendLine("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function.abstract || function.isInterfaceMethod) {
|
||||||
|
appendLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < functionCount - 1) {
|
||||||
|
appendLine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeFunctions(kotlinClassLike: KotlinClassLike): Unit = buffer.run {
|
||||||
|
for ((index, function) in kotlinClassLike.functions.withIndex()) {
|
||||||
|
writeFunction(function, index = index, functionCount = kotlinClassLike.functions.size, indent = " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeFunctionSet(functionSet: KotlinFunctionSet) {
|
||||||
|
writeHeader(functionSet.pkg, functionSet.imports)
|
||||||
|
for ((index, function) in functionSet.functions.withIndex()) {
|
||||||
|
writeFunction(
|
||||||
|
function,
|
||||||
|
index = index,
|
||||||
|
functionCount = functionSet.functions.size
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun write(input: Any): Unit = when (input) {
|
||||||
is KotlinClass -> writeClass(input)
|
is KotlinClass -> writeClass(input)
|
||||||
is KotlinEnum -> writeEnum(input)
|
is KotlinEnum -> writeEnum(input)
|
||||||
else -> throw RuntimeException("Unknown Kotlin Class Type")
|
is KotlinFunctionSet -> writeFunctionSet(input)
|
||||||
|
else -> throw RuntimeException("Unknown Kotlin Type")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String = buffer.toString()
|
override fun toString(): String = buffer.toString()
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.CompilationUnit
|
||||||
|
import gay.pizza.pork.ast.Definition
|
||||||
|
import gay.pizza.pork.ast.FunctionDefinition
|
||||||
|
import gay.pizza.pork.ast.ImportDeclaration
|
||||||
|
|
||||||
|
class CompilationUnitContext(
|
||||||
|
val compilationUnit: CompilationUnit,
|
||||||
|
val evaluator: Evaluator,
|
||||||
|
rootScope: Scope
|
||||||
|
) {
|
||||||
|
val internalScope = rootScope.fork()
|
||||||
|
val externalScope = rootScope.fork()
|
||||||
|
|
||||||
|
private var initialized = false
|
||||||
|
|
||||||
|
fun initIfNeeded() {
|
||||||
|
if (initialized) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
initialized = true
|
||||||
|
processAllImports()
|
||||||
|
processAllDefinitions()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processAllDefinitions() {
|
||||||
|
for (definition in compilationUnit.definitions) {
|
||||||
|
processDefinition(definition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processDefinition(definition: Definition) {
|
||||||
|
val internalValue = definitionValue(definition)
|
||||||
|
internalScope.define(definition.symbol.id, internalValue)
|
||||||
|
if (definition.modifiers.export) {
|
||||||
|
externalScope.define(definition.symbol.id, internalValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun definitionValue(definition: Definition): Any = when (definition) {
|
||||||
|
is FunctionDefinition -> FunctionContext(definition, internalScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processAllImports() {
|
||||||
|
val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>()
|
||||||
|
for (import in imports) {
|
||||||
|
processImport(import)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processImport(import: ImportDeclaration) {
|
||||||
|
val path = import.path.text
|
||||||
|
val evaluationContext = evaluator.context(path)
|
||||||
|
internalScope.inherit(evaluationContext.externalScope)
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
package gay.pizza.pork.evaluator
|
|
||||||
|
|
||||||
import gay.pizza.pork.ast.CompilationUnit
|
|
||||||
import gay.pizza.pork.ast.ImportDeclaration
|
|
||||||
|
|
||||||
class EvaluationContext(
|
|
||||||
val compilationUnit: CompilationUnit,
|
|
||||||
val evaluationContextProvider: EvaluationContextProvider,
|
|
||||||
rootScope: Scope
|
|
||||||
) {
|
|
||||||
val internalRootScope = rootScope.fork()
|
|
||||||
val externalRootScope = rootScope.fork()
|
|
||||||
|
|
||||||
private var initialized = false
|
|
||||||
|
|
||||||
fun init() {
|
|
||||||
if (initialized) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
initialized = true
|
|
||||||
val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>()
|
|
||||||
for (import in imports) {
|
|
||||||
val evaluationContext = evaluationContextProvider.provideEvaluationContext(import.path.text)
|
|
||||||
internalRootScope.inherit(evaluationContext.externalRootScope)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (definition in compilationUnit.definitions) {
|
|
||||||
val evaluationVisitor = EvaluationVisitor(internalRootScope)
|
|
||||||
evaluationVisitor.visit(definition)
|
|
||||||
if (!definition.modifiers.export) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val internalValue = internalRootScope.value(definition.symbol.id)
|
|
||||||
externalRootScope.define(definition.symbol.id, internalValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package gay.pizza.pork.evaluator
|
|
||||||
|
|
||||||
interface EvaluationContextProvider {
|
|
||||||
fun provideEvaluationContext(path: String): EvaluationContext
|
|
||||||
}
|
|
@ -2,23 +2,24 @@ package gay.pizza.pork.evaluator
|
|||||||
|
|
||||||
import gay.pizza.pork.ast.*
|
import gay.pizza.pork.ast.*
|
||||||
|
|
||||||
class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
||||||
private var currentScope: Scope = root
|
private var currentScope: Scope = root
|
||||||
|
|
||||||
override fun visitIntLiteral(node: IntLiteral): Any = node.value
|
override fun visitIntLiteral(node: IntLiteral): Any = node.value
|
||||||
override fun visitStringLiteral(node: StringLiteral): Any = node.text
|
override fun visitStringLiteral(node: StringLiteral): Any = node.text
|
||||||
override fun visitBooleanLiteral(node: BooleanLiteral): Any = node.value
|
override fun visitBooleanLiteral(node: BooleanLiteral): Any = node.value
|
||||||
override fun visitListLiteral(node: ListLiteral): Any = node.items.map { visit(it) }
|
override fun visitListLiteral(node: ListLiteral): Any =
|
||||||
|
node.items.map { it.visit(this) }
|
||||||
|
|
||||||
override fun visitSymbol(node: Symbol): Any = None
|
override fun visitSymbol(node: Symbol): Any = None
|
||||||
|
|
||||||
override fun visitFunctionCall(node: FunctionCall): Any {
|
override fun visitFunctionCall(node: FunctionCall): Any {
|
||||||
val arguments = node.arguments.map { visit(it) }
|
val arguments = node.arguments.map { it.visit(this) }
|
||||||
return currentScope.call(node.symbol.id, Arguments(arguments))
|
return currentScope.call(node.symbol.id, Arguments(arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLetAssignment(node: LetAssignment): Any {
|
override fun visitLetAssignment(node: LetAssignment): Any {
|
||||||
val value = visit(node.value)
|
val value = node.value.visit(this)
|
||||||
currentScope.define(node.symbol.id, value)
|
currentScope.define(node.symbol.id, value)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@ -35,7 +36,7 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
|||||||
try {
|
try {
|
||||||
var value: Any? = null
|
var value: Any? = null
|
||||||
for (expression in node.expressions) {
|
for (expression in node.expressions) {
|
||||||
value = visit(expression)
|
value = expression.visit(this)
|
||||||
}
|
}
|
||||||
value ?: None
|
value ?: None
|
||||||
} finally {
|
} finally {
|
||||||
@ -44,10 +45,11 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitParentheses(node: Parentheses): Any = visit(node.expression)
|
override fun visitParentheses(node: Parentheses): Any =
|
||||||
|
node.expression.visit(this)
|
||||||
|
|
||||||
override fun visitPrefixOperation(node: PrefixOperation): Any {
|
override fun visitPrefixOperation(node: PrefixOperation): Any {
|
||||||
val value = visit(node.expression)
|
val value = node.expression.visit(this)
|
||||||
return when (node.op) {
|
return when (node.op) {
|
||||||
PrefixOperator.Negate -> {
|
PrefixOperator.Negate -> {
|
||||||
if (value !is Boolean) {
|
if (value !is Boolean) {
|
||||||
@ -59,21 +61,18 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitIf(node: If): Any {
|
override fun visitIf(node: If): Any {
|
||||||
val condition = visit(node.condition)
|
val condition = node.condition.visit(this)
|
||||||
return if (condition == true) {
|
return if (condition == true) {
|
||||||
visit(node.thenExpression)
|
node.thenExpression.visit(this)
|
||||||
} else {
|
} else {
|
||||||
if (node.elseExpression != null) {
|
val elseExpression = node.elseExpression
|
||||||
visit(node.elseExpression!!)
|
elseExpression?.visit(this) ?: None
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitInfixOperation(node: InfixOperation): Any {
|
override fun visitInfixOperation(node: InfixOperation): Any {
|
||||||
val left = visit(node.left)
|
val left = node.left.visit(this)
|
||||||
val right = visit(node.right)
|
val right = node.right.visit(this)
|
||||||
|
|
||||||
when (node.op) {
|
when (node.op) {
|
||||||
InfixOperator.Equals -> {
|
InfixOperator.Equals -> {
|
||||||
@ -101,28 +100,21 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
override fun visitBlock(node: Block): BlockFunction = BlockFunction {
|
||||||
val function = CallableFunction { arguments ->
|
|
||||||
currentScope = root.fork()
|
|
||||||
for ((index, argumentSymbol) in node.arguments.withIndex()) {
|
|
||||||
currentScope.define(argumentSymbol.id, arguments.values[index])
|
|
||||||
}
|
|
||||||
val visitor = EvaluationVisitor(currentScope)
|
|
||||||
val blockFunction = visitor.visitBlock(node.block) as BlockFunction
|
|
||||||
return@CallableFunction blockFunction.call()
|
|
||||||
}
|
|
||||||
currentScope.define(node.symbol.id, function)
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBlock(node: Block): Any = BlockFunction {
|
|
||||||
var value: Any? = null
|
var value: Any? = null
|
||||||
for (expression in node.expressions) {
|
for (expression in node.expressions) {
|
||||||
value = visit(expression)
|
value = expression.visit(this)
|
||||||
}
|
}
|
||||||
value ?: None
|
value ?: None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
||||||
|
throw RuntimeException(
|
||||||
|
"Function declarations cannot be visited in an EvaluationVisitor. " +
|
||||||
|
"Utilize a FunctionContext."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitImportDeclaration(node: ImportDeclaration): Any {
|
override fun visitImportDeclaration(node: ImportDeclaration): Any {
|
||||||
throw RuntimeException(
|
throw RuntimeException(
|
||||||
"Import declarations cannot be visited in an EvaluationVisitor. " +
|
"Import declarations cannot be visited in an EvaluationVisitor. " +
|
||||||
|
@ -2,21 +2,19 @@ package gay.pizza.pork.evaluator
|
|||||||
|
|
||||||
import gay.pizza.pork.frontend.World
|
import gay.pizza.pork.frontend.World
|
||||||
|
|
||||||
class Evaluator(val world: World, val scope: Scope) : EvaluationContextProvider {
|
class Evaluator(val world: World, val scope: Scope) {
|
||||||
private val contexts = mutableMapOf<String, EvaluationContext>()
|
private val contexts = mutableMapOf<String, CompilationUnitContext>()
|
||||||
|
|
||||||
fun evaluate(path: String): Scope {
|
fun evaluate(path: String): Scope =
|
||||||
val context = provideEvaluationContext(path)
|
context(path).externalScope
|
||||||
return context.externalRootScope
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun provideEvaluationContext(path: String): EvaluationContext {
|
fun context(path: String): CompilationUnitContext {
|
||||||
val unit = world.load(path)
|
val unit = world.load(path)
|
||||||
val identity = world.contentSource.stableContentIdentity(path)
|
val identity = world.contentSource.stableContentIdentity(path)
|
||||||
val context = contexts.computeIfAbsent(identity) {
|
val context = contexts.computeIfAbsent(identity) {
|
||||||
EvaluationContext(unit, this, scope)
|
CompilationUnitContext(unit, this, scope)
|
||||||
}
|
}
|
||||||
context.init()
|
context.initIfNeeded()
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.FunctionDefinition
|
||||||
|
|
||||||
|
class FunctionContext(val node: FunctionDefinition, val internalScope: Scope) : CallableFunction {
|
||||||
|
override fun call(arguments: Arguments): Any {
|
||||||
|
val scope = internalScope.fork()
|
||||||
|
for ((index, argumentSymbol) in node.arguments.withIndex()) {
|
||||||
|
scope.define(argumentSymbol.id, arguments.values[index])
|
||||||
|
}
|
||||||
|
val visitor = EvaluationVisitor(scope)
|
||||||
|
val blockFunction = visitor.visitBlock(node.block)
|
||||||
|
return blockFunction.call()
|
||||||
|
}
|
||||||
|
}
|
@ -14,8 +14,8 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
|
|||||||
|
|
||||||
fun value(name: String): Any {
|
fun value(name: String): Any {
|
||||||
val value = valueOrNotFound(name)
|
val value = valueOrNotFound(name)
|
||||||
if (value == NotFound) {
|
if (value === NotFound) {
|
||||||
throw RuntimeException("Variable '${name}' not defined.")
|
throw RuntimeException("Variable '${name}' not defined")
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@ -25,14 +25,14 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
|
|||||||
if (value == null) {
|
if (value == null) {
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
val parentMaybeFound = parent.valueOrNotFound(name)
|
val parentMaybeFound = parent.valueOrNotFound(name)
|
||||||
if (parentMaybeFound != NotFound) {
|
if (parentMaybeFound !== NotFound) {
|
||||||
return parentMaybeFound
|
return parentMaybeFound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (inherit in inherited) {
|
for (inherit in inherited) {
|
||||||
val inheritMaybeFound = inherit.valueOrNotFound(name)
|
val inheritMaybeFound = inherit.valueOrNotFound(name)
|
||||||
if (inheritMaybeFound != NotFound) {
|
if (inheritMaybeFound !== NotFound) {
|
||||||
return inheritMaybeFound
|
return inheritMaybeFound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package gay.pizza.pork.frontend
|
package gay.pizza.pork.frontend
|
||||||
|
|
||||||
|
import gay.pizza.dough.fs.FsPath
|
||||||
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
|
import gay.pizza.dough.fs.readString
|
||||||
import gay.pizza.pork.parser.CharSource
|
import gay.pizza.pork.parser.CharSource
|
||||||
import gay.pizza.pork.parser.StringCharSource
|
import gay.pizza.pork.parser.StringCharSource
|
||||||
import java.nio.file.Path
|
|
||||||
import kotlin.io.path.absolutePathString
|
|
||||||
import kotlin.io.path.readText
|
|
||||||
|
|
||||||
class FsContentSource(val root: Path) : ContentSource {
|
class FsContentSource(val root: FsPath) : ContentSource {
|
||||||
override fun loadAsCharSource(path: String): CharSource =
|
override fun loadAsCharSource(path: String): CharSource =
|
||||||
StringCharSource(asFsPath(path).readText())
|
StringCharSource(asFsPath(path).readString())
|
||||||
|
|
||||||
override fun stableContentIdentity(path: String): String =
|
override fun stableContentIdentity(path: String): String =
|
||||||
asFsPath(path).absolutePathString()
|
asFsPath(path).fullPathString
|
||||||
|
|
||||||
private fun asFsPath(path: String): Path {
|
private fun asFsPath(path: String): FsPath {
|
||||||
val fsPath = root.resolve(path)
|
val fsPath = root.resolve(path)
|
||||||
val absoluteRootPath = root.absolutePathString() + root.fileSystem.separator
|
val rootPathWithSeparator = root.fullPathString + PlatformFsProvider.separator
|
||||||
if (!fsPath.absolutePathString().startsWith(absoluteRootPath)) {
|
if (!fsPath.fullPathString.startsWith(rootPathWithSeparator)) {
|
||||||
throw RuntimeException("Unable to load path outside of the root: $fsPath (root is ${root})")
|
throw RuntimeException("Unable to load path outside of the root: $fsPath (root is ${root})")
|
||||||
}
|
}
|
||||||
return fsPath
|
return fsPath
|
||||||
|
@ -2,6 +2,7 @@ package gay.pizza.pork.parser
|
|||||||
|
|
||||||
import gay.pizza.pork.ast.NodeCoalescer
|
import gay.pizza.pork.ast.NodeCoalescer
|
||||||
import gay.pizza.pork.ast.Node
|
import gay.pizza.pork.ast.Node
|
||||||
|
import gay.pizza.pork.ast.visit
|
||||||
import java.util.IdentityHashMap
|
import java.util.IdentityHashMap
|
||||||
|
|
||||||
class TokenNodeAttribution : NodeAttribution {
|
class TokenNodeAttribution : NodeAttribution {
|
||||||
|
@ -2,14 +2,14 @@ package gay.pizza.pork.tool
|
|||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
import gay.pizza.pork.ast.Node
|
import gay.pizza.pork.ast.Node
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
class AstCommand : CliktCommand(help = "Print AST", name = "ast") {
|
class AstCommand : CliktCommand(help = "Print AST", name = "ast") {
|
||||||
val path by argument("file").path(mustExist = true, canBeDir = false)
|
val path by argument("file")
|
||||||
|
|
||||||
private val json = Json {
|
private val json = Json {
|
||||||
prettyPrint = true
|
prettyPrint = true
|
||||||
@ -18,7 +18,7 @@ class AstCommand : CliktCommand(help = "Print AST", name = "ast") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val tool = FileTool(path)
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
println(json.encodeToString(Node.serializer(), tool.parse()))
|
println(json.encodeToString(Node.serializer(), tool.parse()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,16 @@ package gay.pizza.pork.tool
|
|||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
import gay.pizza.pork.ast.NodeCoalescer
|
import gay.pizza.pork.ast.NodeCoalescer
|
||||||
|
import gay.pizza.pork.ast.visit
|
||||||
import gay.pizza.pork.parser.TokenNodeAttribution
|
import gay.pizza.pork.parser.TokenNodeAttribution
|
||||||
|
|
||||||
class AttributeCommand : CliktCommand(help = "Attribute AST", name = "attribute") {
|
class AttributeCommand : CliktCommand(help = "Attribute AST", name = "attribute") {
|
||||||
val path by argument("file").path(mustExist = true, canBeDir = false)
|
val path by argument("file")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val tool = FileTool(path)
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
val attribution = TokenNodeAttribution()
|
val attribution = TokenNodeAttribution()
|
||||||
val compilationUnit = tool.parse(attribution)
|
val compilationUnit = tool.parse(attribution)
|
||||||
|
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package gay.pizza.pork.tool
|
package gay.pizza.pork.tool
|
||||||
|
|
||||||
|
import gay.pizza.dough.fs.FsPath
|
||||||
|
import gay.pizza.dough.fs.readString
|
||||||
import gay.pizza.pork.frontend.ContentSource
|
import gay.pizza.pork.frontend.ContentSource
|
||||||
import gay.pizza.pork.frontend.FsContentSource
|
import gay.pizza.pork.frontend.FsContentSource
|
||||||
import gay.pizza.pork.parser.CharSource
|
import gay.pizza.pork.parser.CharSource
|
||||||
import gay.pizza.pork.parser.StringCharSource
|
import gay.pizza.pork.parser.StringCharSource
|
||||||
import java.nio.file.Path
|
|
||||||
import kotlin.io.path.absolute
|
|
||||||
import kotlin.io.path.readText
|
|
||||||
|
|
||||||
class FileTool(val path: Path) : Tool() {
|
class FileTool(val path: FsPath) : Tool() {
|
||||||
override fun createCharSource(): CharSource = StringCharSource(path.readText())
|
override fun createCharSource(): CharSource =
|
||||||
override fun createContentSource(): ContentSource = FsContentSource(path.absolute().parent)
|
StringCharSource(path.readString())
|
||||||
override fun rootFilePath(): String = path.fileName.toString()
|
override fun createContentSource(): ContentSource =
|
||||||
|
FsContentSource(path.parent!!)
|
||||||
|
override fun rootFilePath(): String = path.fullPathString
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ package gay.pizza.pork.tool
|
|||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
import gay.pizza.pork.parser.AnsiHighlightScheme
|
import gay.pizza.pork.parser.AnsiHighlightScheme
|
||||||
|
|
||||||
class HighlightCommand : CliktCommand(help = "Syntax Highlighter", name = "highlight") {
|
class HighlightCommand : CliktCommand(help = "Syntax Highlighter", name = "highlight") {
|
||||||
val path by argument("file").path(mustExist = true, canBeDir = false)
|
val path by argument("file")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val tool = FileTool(path)
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
print(tool.highlight(AnsiHighlightScheme()).joinToString(""))
|
print(tool.highlight(AnsiHighlightScheme()).joinToString(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
tool/src/main/kotlin/gay/pizza/pork/tool/LoopAndMeasure.kt
Normal file
23
tool/src/main/kotlin/gay/pizza/pork/tool/LoopAndMeasure.kt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package gay.pizza.pork.tool
|
||||||
|
|
||||||
|
import kotlin.system.measureNanoTime
|
||||||
|
|
||||||
|
fun maybeLoopAndMeasure(loop: Boolean, measure: Boolean, block: () -> Unit) {
|
||||||
|
fun withMaybeMeasurement() {
|
||||||
|
if (measure) {
|
||||||
|
val nanos = measureNanoTime(block)
|
||||||
|
val millis = nanos / 1000000.0
|
||||||
|
System.err.println("time taken: $millis ms (${nanos} ns)")
|
||||||
|
} else {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
while (true) {
|
||||||
|
withMaybeMeasurement()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
withMaybeMeasurement()
|
||||||
|
}
|
||||||
|
}
|
21
tool/src/main/kotlin/gay/pizza/pork/tool/ParseCommand.kt
Normal file
21
tool/src/main/kotlin/gay/pizza/pork/tool/ParseCommand.kt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package gay.pizza.pork.tool
|
||||||
|
|
||||||
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
|
import com.github.ajalt.clikt.parameters.options.flag
|
||||||
|
import com.github.ajalt.clikt.parameters.options.option
|
||||||
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
|
|
||||||
|
class ParseCommand : CliktCommand(help = "Parse Compilation Unit", name = "parse") {
|
||||||
|
val loop by option("--loop", help = "Loop Parsing").flag()
|
||||||
|
val measure by option("--measure", help = "Measure Time").flag()
|
||||||
|
val path by argument("file")
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
|
|
||||||
|
maybeLoopAndMeasure(loop, measure) {
|
||||||
|
tool.parse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,13 @@ package gay.pizza.pork.tool
|
|||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
|
|
||||||
class ReprintCommand : CliktCommand(help = "Reprint Parsed Compilation Unit", name = "reprint") {
|
class ReprintCommand : CliktCommand(help = "Reprint Parsed Compilation Unit", name = "reprint") {
|
||||||
val path by argument("file").path(mustExist = true, canBeDir = false)
|
val path by argument("file")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val tool = FileTool(path)
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
print(tool.reprint())
|
print(tool.reprint())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ class RootCommand : CliktCommand(
|
|||||||
HighlightCommand(),
|
HighlightCommand(),
|
||||||
TokenizeCommand(),
|
TokenizeCommand(),
|
||||||
ReprintCommand(),
|
ReprintCommand(),
|
||||||
|
ParseCommand(),
|
||||||
AstCommand(),
|
AstCommand(),
|
||||||
AttributeCommand()
|
AttributeCommand()
|
||||||
)
|
)
|
||||||
|
@ -4,45 +4,32 @@ import com.github.ajalt.clikt.core.CliktCommand
|
|||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
import com.github.ajalt.clikt.parameters.options.flag
|
import com.github.ajalt.clikt.parameters.options.flag
|
||||||
import com.github.ajalt.clikt.parameters.options.option
|
import com.github.ajalt.clikt.parameters.options.option
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
import gay.pizza.pork.evaluator.CallableFunction
|
import gay.pizza.pork.evaluator.CallableFunction
|
||||||
|
import gay.pizza.pork.evaluator.None
|
||||||
import gay.pizza.pork.evaluator.Scope
|
import gay.pizza.pork.evaluator.Scope
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
|
|
||||||
class RunCommand : CliktCommand(help = "Run Program", name = "run") {
|
class RunCommand : CliktCommand(help = "Run Program", name = "run") {
|
||||||
val loop by option("--loop", help = "Loop Program").flag()
|
val loop by option("--loop", help = "Loop Program").flag()
|
||||||
val measure by option("--measure", help = "Measure Time").flag()
|
val measure by option("--measure", help = "Measure Time").flag()
|
||||||
val path by argument("file").path(mustExist = true, canBeDir = false)
|
val quiet by option("--quiet", help = "Silence Prints").flag()
|
||||||
|
val path by argument("file")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (loop) {
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
while (true) {
|
|
||||||
runProgramMaybeMeasure()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
runProgramMaybeMeasure()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun runProgramMaybeMeasure() {
|
|
||||||
if (measure) {
|
|
||||||
val time = measureTimeMillis {
|
|
||||||
runProgramOnce()
|
|
||||||
}
|
|
||||||
println("time taken: $time ms")
|
|
||||||
} else {
|
|
||||||
runProgramOnce()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun runProgramOnce() {
|
|
||||||
val tool = FileTool(path)
|
|
||||||
val scope = Scope()
|
val scope = Scope()
|
||||||
scope.define("println", CallableFunction { arguments ->
|
scope.define("println", CallableFunction { arguments ->
|
||||||
|
if (quiet) {
|
||||||
|
return@CallableFunction None
|
||||||
|
}
|
||||||
for (argument in arguments.values) {
|
for (argument in arguments.values) {
|
||||||
println(argument)
|
println(argument)
|
||||||
}
|
}
|
||||||
|
None
|
||||||
})
|
})
|
||||||
tool.evaluate(scope)
|
|
||||||
|
maybeLoopAndMeasure(loop, measure) {
|
||||||
|
tool.evaluate(scope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,13 @@ package gay.pizza.pork.tool
|
|||||||
|
|
||||||
import com.github.ajalt.clikt.core.CliktCommand
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
|
|
||||||
class TokenizeCommand : CliktCommand(help = "Tokenize Compilation Unit", name = "tokenize") {
|
class TokenizeCommand : CliktCommand(help = "Tokenize Compilation Unit", name = "tokenize") {
|
||||||
val path by argument("file").path(mustExist = true, canBeDir = false)
|
val path by argument("file")
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val tool = FileTool(path)
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
val tokenStream = tool.tokenize()
|
val tokenStream = tool.tokenize()
|
||||||
for (token in tokenStream.tokens) {
|
for (token in tokenStream.tokens) {
|
||||||
println("${token.start} ${token.type.name} '${sanitize(token.text)}'")
|
println("${token.start} ${token.type.name} '${sanitize(token.text)}'")
|
||||||
|
@ -3,6 +3,7 @@ package gay.pizza.pork.tool
|
|||||||
import gay.pizza.pork.ast.NodeVisitor
|
import gay.pizza.pork.ast.NodeVisitor
|
||||||
import gay.pizza.pork.parser.Printer
|
import gay.pizza.pork.parser.Printer
|
||||||
import gay.pizza.pork.ast.CompilationUnit
|
import gay.pizza.pork.ast.CompilationUnit
|
||||||
|
import gay.pizza.pork.ast.visit
|
||||||
import gay.pizza.pork.evaluator.Arguments
|
import gay.pizza.pork.evaluator.Arguments
|
||||||
import gay.pizza.pork.evaluator.Evaluator
|
import gay.pizza.pork.evaluator.Evaluator
|
||||||
import gay.pizza.pork.evaluator.Scope
|
import gay.pizza.pork.evaluator.Scope
|
||||||
|
Reference in New Issue
Block a user