mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 21:00:56 +00:00
while loop support, and native functions (including ffi!)
This commit is contained in:
parent
ddff6cb365
commit
236f812caf
@ -95,16 +95,18 @@ types:
|
|||||||
- name: arguments
|
- name: arguments
|
||||||
type: List<Symbol>
|
type: List<Symbol>
|
||||||
- name: block
|
- name: block
|
||||||
type: Block
|
type: Block?
|
||||||
|
- name: native
|
||||||
|
type: Native?
|
||||||
If:
|
If:
|
||||||
parent: Expression
|
parent: Expression
|
||||||
values:
|
values:
|
||||||
- name: condition
|
- name: condition
|
||||||
type: Expression
|
type: Expression
|
||||||
- name: thenExpression
|
- name: thenBlock
|
||||||
type: Expression
|
type: Block
|
||||||
- name: elseExpression
|
- name: elseBlock
|
||||||
type: Expression?
|
type: Block?
|
||||||
ImportDeclaration:
|
ImportDeclaration:
|
||||||
parent: Declaration
|
parent: Declaration
|
||||||
values:
|
values:
|
||||||
@ -150,3 +152,23 @@ types:
|
|||||||
values:
|
values:
|
||||||
- name: symbol
|
- name: symbol
|
||||||
type: Symbol
|
type: Symbol
|
||||||
|
While:
|
||||||
|
parent: Expression
|
||||||
|
values:
|
||||||
|
- name: condition
|
||||||
|
type: Expression
|
||||||
|
- name: block
|
||||||
|
type: Block
|
||||||
|
Break:
|
||||||
|
parent: Expression
|
||||||
|
values: []
|
||||||
|
Continue:
|
||||||
|
parent: Expression
|
||||||
|
values: []
|
||||||
|
Native:
|
||||||
|
parent: Node
|
||||||
|
values:
|
||||||
|
- name: form
|
||||||
|
type: Symbol
|
||||||
|
- name: definition
|
||||||
|
type: StringLiteral
|
||||||
|
22
ast/src/main/kotlin/gay/pizza/pork/ast/Break.kt
Normal file
22
ast/src/main/kotlin/gay/pizza/pork/ast/Break.kt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("break")
|
||||||
|
class Break : Expression() {
|
||||||
|
override val type: NodeType = NodeType.Break
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitBreak(this)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is Break) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int =
|
||||||
|
31 * type.hashCode()
|
||||||
|
}
|
22
ast/src/main/kotlin/gay/pizza/pork/ast/Continue.kt
Normal file
22
ast/src/main/kotlin/gay/pizza/pork/ast/Continue.kt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("continue")
|
||||||
|
class Continue : Expression() {
|
||||||
|
override val type: NodeType = NodeType.Continue
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitContinue(this)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is Continue) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int =
|
||||||
|
31 * type.hashCode()
|
||||||
|
}
|
@ -6,18 +6,18 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("functionDefinition")
|
@SerialName("functionDefinition")
|
||||||
class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List<Symbol>, val block: Block) : Definition() {
|
class FunctionDefinition(override val modifiers: DefinitionModifiers, override val symbol: Symbol, val arguments: List<Symbol>, val block: Block?, val native: Native?) : Definition() {
|
||||||
override val type: NodeType = NodeType.FunctionDefinition
|
override val type: NodeType = NodeType.FunctionDefinition
|
||||||
|
|
||||||
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), listOf(native))
|
||||||
|
|
||||||
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
visitor.visitFunctionDefinition(this)
|
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 && other.native == native
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
@ -25,6 +25,7 @@ class FunctionDefinition(override val modifiers: DefinitionModifiers, override v
|
|||||||
result = 31 * result + symbol.hashCode()
|
result = 31 * result + symbol.hashCode()
|
||||||
result = 31 * result + arguments.hashCode()
|
result = 31 * result + arguments.hashCode()
|
||||||
result = 31 * result + block.hashCode()
|
result = 31 * result + block.hashCode()
|
||||||
|
result = 31 * result + native.hashCode()
|
||||||
result = 31 * result + type.hashCode()
|
result = 31 * result + type.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -6,24 +6,24 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("if")
|
@SerialName("if")
|
||||||
class If(val condition: Expression, val thenExpression: Expression, val elseExpression: Expression?) : Expression() {
|
class If(val condition: Expression, val thenBlock: Block, val elseBlock: Block?) : Expression() {
|
||||||
override val type: NodeType = NodeType.If
|
override val type: NodeType = NodeType.If
|
||||||
|
|
||||||
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, thenBlock, elseBlock)
|
||||||
|
|
||||||
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
visitor.visitIf(this)
|
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.thenBlock == thenBlock && other.elseBlock == elseBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = condition.hashCode()
|
var result = condition.hashCode()
|
||||||
result = 31 * result + thenExpression.hashCode()
|
result = 31 * result + thenBlock.hashCode()
|
||||||
result = 31 * result + elseExpression.hashCode()
|
result = 31 * result + elseBlock.hashCode()
|
||||||
result = 31 * result + type.hashCode()
|
result = 31 * result + type.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
29
ast/src/main/kotlin/gay/pizza/pork/ast/Native.kt
Normal file
29
ast/src/main/kotlin/gay/pizza/pork/ast/Native.kt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("native")
|
||||||
|
class Native(val form: Symbol, val definition: StringLiteral) : Node() {
|
||||||
|
override val type: NodeType = NodeType.Native
|
||||||
|
|
||||||
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
|
visitor.visitNodes(form, definition)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitNative(this)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is Native) return false
|
||||||
|
return other.form == form && other.definition == definition
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = form.hashCode()
|
||||||
|
result = 31 * result + definition.hashCode()
|
||||||
|
result = 31 * result + type.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -8,9 +8,15 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
|||||||
override fun visitBooleanLiteral(node: BooleanLiteral): Unit =
|
override fun visitBooleanLiteral(node: BooleanLiteral): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
|
override fun visitBreak(node: Break): Unit =
|
||||||
|
handle(node)
|
||||||
|
|
||||||
override fun visitCompilationUnit(node: CompilationUnit): Unit =
|
override fun visitCompilationUnit(node: CompilationUnit): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
|
override fun visitContinue(node: Continue): Unit =
|
||||||
|
handle(node)
|
||||||
|
|
||||||
override fun visitFunctionCall(node: FunctionCall): Unit =
|
override fun visitFunctionCall(node: FunctionCall): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
@ -35,6 +41,9 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
|||||||
override fun visitListLiteral(node: ListLiteral): Unit =
|
override fun visitListLiteral(node: ListLiteral): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
|
override fun visitNative(node: Native): Unit =
|
||||||
|
handle(node)
|
||||||
|
|
||||||
override fun visitParentheses(node: Parentheses): Unit =
|
override fun visitParentheses(node: Parentheses): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
@ -50,6 +59,9 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
|||||||
override fun visitSymbolReference(node: SymbolReference): Unit =
|
override fun visitSymbolReference(node: SymbolReference): Unit =
|
||||||
handle(node)
|
handle(node)
|
||||||
|
|
||||||
|
override fun visitWhile(node: While): Unit =
|
||||||
|
handle(node)
|
||||||
|
|
||||||
fun handle(node: Node) {
|
fun handle(node: Node) {
|
||||||
handler(node)
|
handler(node)
|
||||||
node.visitChildren(this)
|
node.visitChildren(this)
|
||||||
|
@ -6,7 +6,9 @@ enum class NodeType(val parent: NodeType? = null) {
|
|||||||
Block(Node),
|
Block(Node),
|
||||||
Expression(Node),
|
Expression(Node),
|
||||||
BooleanLiteral(Expression),
|
BooleanLiteral(Expression),
|
||||||
|
Break(Expression),
|
||||||
CompilationUnit(Node),
|
CompilationUnit(Node),
|
||||||
|
Continue(Expression),
|
||||||
Declaration(Node),
|
Declaration(Node),
|
||||||
Definition(Node),
|
Definition(Node),
|
||||||
FunctionCall(Expression),
|
FunctionCall(Expression),
|
||||||
@ -17,9 +19,11 @@ enum class NodeType(val parent: NodeType? = null) {
|
|||||||
IntLiteral(Expression),
|
IntLiteral(Expression),
|
||||||
LetAssignment(Expression),
|
LetAssignment(Expression),
|
||||||
ListLiteral(Expression),
|
ListLiteral(Expression),
|
||||||
|
Native(Node),
|
||||||
Parentheses(Expression),
|
Parentheses(Expression),
|
||||||
PrefixOperation(Expression),
|
PrefixOperation(Expression),
|
||||||
StringLiteral(Expression),
|
StringLiteral(Expression),
|
||||||
Symbol(Node),
|
Symbol(Node),
|
||||||
SymbolReference(Expression)
|
SymbolReference(Expression),
|
||||||
|
While(Expression)
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,12 @@ interface NodeVisitor<T> {
|
|||||||
|
|
||||||
fun visitBooleanLiteral(node: BooleanLiteral): T
|
fun visitBooleanLiteral(node: BooleanLiteral): T
|
||||||
|
|
||||||
|
fun visitBreak(node: Break): T
|
||||||
|
|
||||||
fun visitCompilationUnit(node: CompilationUnit): T
|
fun visitCompilationUnit(node: CompilationUnit): T
|
||||||
|
|
||||||
|
fun visitContinue(node: Continue): T
|
||||||
|
|
||||||
fun visitFunctionCall(node: FunctionCall): T
|
fun visitFunctionCall(node: FunctionCall): T
|
||||||
|
|
||||||
fun visitFunctionDefinition(node: FunctionDefinition): T
|
fun visitFunctionDefinition(node: FunctionDefinition): T
|
||||||
@ -24,6 +28,8 @@ interface NodeVisitor<T> {
|
|||||||
|
|
||||||
fun visitListLiteral(node: ListLiteral): T
|
fun visitListLiteral(node: ListLiteral): T
|
||||||
|
|
||||||
|
fun visitNative(node: Native): T
|
||||||
|
|
||||||
fun visitParentheses(node: Parentheses): T
|
fun visitParentheses(node: Parentheses): T
|
||||||
|
|
||||||
fun visitPrefixOperation(node: PrefixOperation): T
|
fun visitPrefixOperation(node: PrefixOperation): T
|
||||||
@ -33,4 +39,6 @@ interface NodeVisitor<T> {
|
|||||||
fun visitSymbol(node: Symbol): T
|
fun visitSymbol(node: Symbol): T
|
||||||
|
|
||||||
fun visitSymbolReference(node: SymbolReference): T
|
fun visitSymbolReference(node: SymbolReference): T
|
||||||
|
|
||||||
|
fun visitWhile(node: While): T
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,14 @@ fun <T> NodeVisitor<T>.visit(node: Node): T =
|
|||||||
is PrefixOperation -> visitPrefixOperation(node)
|
is PrefixOperation -> visitPrefixOperation(node)
|
||||||
is StringLiteral -> visitStringLiteral(node)
|
is StringLiteral -> visitStringLiteral(node)
|
||||||
is SymbolReference -> visitSymbolReference(node)
|
is SymbolReference -> visitSymbolReference(node)
|
||||||
|
is While -> visitWhile(node)
|
||||||
|
is Break -> visitBreak(node)
|
||||||
|
is Continue -> visitContinue(node)
|
||||||
|
is Native -> visitNative(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> NodeVisitor<T>.visitNodes(vararg nodes: Node?): List<T> =
|
fun <T> NodeVisitor<T>.visitNodes(vararg nodes: Node?): List<T> =
|
||||||
nodes.asSequence().filterNotNull().map { visit(it) }.toList()
|
nodes.asSequence().filterNotNull().map { visit(it) }.toList()
|
||||||
|
|
||||||
fun <T> NodeVisitor<T>.visitAll(vararg nodeLists: List<Node>): List<T> =
|
fun <T> NodeVisitor<T>.visitAll(vararg nodeLists: List<Node?>): List<T> =
|
||||||
nodeLists.asSequence().flatten().map { visit(it) }.toList()
|
nodeLists.asSequence().flatten().filterNotNull().map { visit(it) }.toList()
|
||||||
|
29
ast/src/main/kotlin/gay/pizza/pork/ast/While.kt
Normal file
29
ast/src/main/kotlin/gay/pizza/pork/ast/While.kt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// GENERATED CODE FROM PORK AST CODEGEN
|
||||||
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("while")
|
||||||
|
class While(val condition: Expression, val block: Block) : Expression() {
|
||||||
|
override val type: NodeType = NodeType.While
|
||||||
|
|
||||||
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
|
visitor.visitNodes(condition, block)
|
||||||
|
|
||||||
|
override fun <T> visit(visitor: NodeVisitor<T>): T =
|
||||||
|
visitor.visitWhile(this)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is While) return false
|
||||||
|
return other.condition == condition && other.block == block
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = condition.hashCode()
|
||||||
|
result = 31 * result + block.hashCode()
|
||||||
|
result = 31 * result + type.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -120,11 +120,12 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
extensionOf = "NodeVisitor<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)
|
||||||
),
|
),
|
||||||
isImmediateExpression = true
|
isImmediateExpression = true
|
||||||
)
|
)
|
||||||
visitAllFunction.body.add("nodeLists.asSequence().flatten().map { visit(it) }.toList()")
|
visitAllFunction.body.add(
|
||||||
|
"nodeLists.asSequence().flatten().filterNotNull().map { visit(it) }.toList()")
|
||||||
visitorExtensionSet.functions.add(visitAllFunction)
|
visitorExtensionSet.functions.add(visitAllFunction)
|
||||||
|
|
||||||
write("NodeVisitorExtensions.kt", KotlinWriter(visitorExtensionSet))
|
write("NodeVisitorExtensions.kt", KotlinWriter(visitorExtensionSet))
|
||||||
@ -239,16 +240,18 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
kotlinClassLike.inherits.add("$parentName()")
|
kotlinClassLike.inherits.add("$parentName()")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (value in type.values) {
|
if (type.values != null) {
|
||||||
val member = KotlinMember(value.name, toKotlinType(value.typeRef))
|
for (value in type.values!!) {
|
||||||
member.abstract = value.abstract
|
val member = KotlinMember(value.name, toKotlinType(value.typeRef))
|
||||||
if (type.isParentAbstract(value)) {
|
member.abstract = value.abstract
|
||||||
member.overridden = true
|
if (type.isParentAbstract(value)) {
|
||||||
|
member.overridden = true
|
||||||
|
}
|
||||||
|
if (role == AstTypeRole.ValueHolder) {
|
||||||
|
member.mutable = true
|
||||||
|
}
|
||||||
|
kotlinClassLike.members.add(member)
|
||||||
}
|
}
|
||||||
if (role == AstTypeRole.ValueHolder) {
|
|
||||||
member.mutable = true
|
|
||||||
}
|
|
||||||
kotlinClassLike.members.add(member)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == AstTypeRole.Enum) {
|
if (role == AstTypeRole.Enum) {
|
||||||
@ -279,25 +282,26 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
),
|
),
|
||||||
isImmediateExpression = true
|
isImmediateExpression = true
|
||||||
)
|
)
|
||||||
val anyListMembers = type.values.any { it.typeRef.form == AstTypeRefForm.List }
|
val anyListMembers = type.values?.any { it.typeRef.form == AstTypeRefForm.List } ?: false
|
||||||
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 &&
|
} else if (it.typeRef.type != null &&
|
||||||
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
||||||
null
|
null
|
||||||
} else if (it.typeRef.form == AstTypeRefForm.Single) {
|
} else if (it.typeRef.form == AstTypeRefForm.Single ||
|
||||||
|
it.typeRef.form == AstTypeRefForm.Nullable) {
|
||||||
"listOf(${it.name})"
|
"listOf(${it.name})"
|
||||||
} else {
|
} else {
|
||||||
it.name
|
it.name
|
||||||
}
|
}
|
||||||
}.joinToString(", ")
|
} ?: emptyList()).joinToString(", ")
|
||||||
elideVisitChildren = visitParameters.isEmpty()
|
elideVisitChildren = visitParameters.isEmpty()
|
||||||
visitChildrenFunction.body.add("visitor.visitAll(${visitParameters})")
|
visitChildrenFunction.body.add("visitor.visitAll(${visitParameters})")
|
||||||
} else {
|
} else {
|
||||||
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 &&
|
} else if (it.typeRef.type != null &&
|
||||||
@ -306,7 +310,7 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
} else {
|
} else {
|
||||||
it.name
|
it.name
|
||||||
}
|
}
|
||||||
}.joinToString(", ")
|
} ?: emptyList()).joinToString(", ")
|
||||||
elideVisitChildren = visitParameters.isEmpty()
|
elideVisitChildren = visitParameters.isEmpty()
|
||||||
visitChildrenFunction.body.add("visitor.visitNodes(${visitParameters})")
|
visitChildrenFunction.body.add("visitor.visitNodes(${visitParameters})")
|
||||||
}
|
}
|
||||||
@ -341,9 +345,12 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
|||||||
"Any?"
|
"Any?"
|
||||||
))
|
))
|
||||||
equalsFunction.body.add("if (other !is ${type.name}) return false")
|
equalsFunction.body.add("if (other !is ${type.name}) return false")
|
||||||
val predicate = equalsAndHashCodeMembers.mapNotNull {
|
var predicate = equalsAndHashCodeMembers.mapNotNull {
|
||||||
if (it == "type") null else "other.${it} == $it"
|
if (it == "type") null else "other.${it} == $it"
|
||||||
}.joinToString(" && ")
|
}.joinToString(" && ")
|
||||||
|
if (predicate.isEmpty()) {
|
||||||
|
predicate = "true"
|
||||||
|
}
|
||||||
equalsFunction.body.add("return $predicate")
|
equalsFunction.body.add("return $predicate")
|
||||||
kotlinClassLike.functions.add(equalsFunction)
|
kotlinClassLike.functions.add(equalsFunction)
|
||||||
|
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
package gay.pizza.pork.buildext.ast
|
package gay.pizza.pork.buildext.ast
|
||||||
|
|
||||||
class AstType(val name: String, var parent: AstType? = null) {
|
class AstType(val name: String, var parent: AstType? = null) {
|
||||||
private val internalValues = mutableListOf<AstValue>()
|
private var internalValues: MutableList<AstValue>? = null
|
||||||
private val internalEnums = mutableListOf<AstEnum>()
|
private val internalEnums = mutableListOf<AstEnum>()
|
||||||
|
|
||||||
val values: List<AstValue>
|
val values: List<AstValue>?
|
||||||
get() = internalValues
|
get() = internalValues
|
||||||
|
|
||||||
val enums: List<AstEnum>
|
val enums: List<AstEnum>
|
||||||
get() = internalEnums
|
get() = internalEnums
|
||||||
|
|
||||||
|
internal fun markHasValues() {
|
||||||
|
if (internalValues == null) {
|
||||||
|
internalValues = mutableListOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun addValue(value: AstValue) {
|
internal fun addValue(value: AstValue) {
|
||||||
internalValues.add(value)
|
markHasValues()
|
||||||
|
internalValues!!.add(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun addEnum(enum: AstEnum) {
|
internal fun addEnum(enum: AstEnum) {
|
||||||
@ -25,7 +32,7 @@ class AstType(val name: String, var parent: AstType? = null) {
|
|||||||
|
|
||||||
var current = parent
|
var current = parent
|
||||||
while (current != null) {
|
while (current != null) {
|
||||||
val abstract = current.values.firstOrNull {
|
val abstract = current.values?.firstOrNull {
|
||||||
it.name == value.name && it.abstract
|
it.name == value.name && it.abstract
|
||||||
}
|
}
|
||||||
if (abstract != null) {
|
if (abstract != null) {
|
||||||
|
@ -2,6 +2,6 @@ package gay.pizza.pork.buildext.ast
|
|||||||
|
|
||||||
data class AstTypeDescription(
|
data class AstTypeDescription(
|
||||||
val parent: String? = null,
|
val parent: String? = null,
|
||||||
val values: List<AstValueDescription> = emptyList(),
|
val values: List<AstValueDescription>? = null,
|
||||||
val enums: List<AstEnumDescription> = emptyList()
|
val enums: List<AstEnumDescription> = emptyList()
|
||||||
)
|
)
|
||||||
|
@ -21,13 +21,14 @@ class AstTypeRegistry {
|
|||||||
when {
|
when {
|
||||||
type.enums.isNotEmpty() ->
|
type.enums.isNotEmpty() ->
|
||||||
AstTypeRole.Enum
|
AstTypeRole.Enum
|
||||||
type.parent == null && type.values.isEmpty() ->
|
type.parent == null && type.values == null ->
|
||||||
AstTypeRole.RootNode
|
AstTypeRole.RootNode
|
||||||
type.parent != null && type.values.all { it.abstract } ->
|
type.parent != null && (type.values == null ||
|
||||||
|
(type.values!!.isNotEmpty() && type.values!!.all { it.abstract })) ->
|
||||||
AstTypeRole.HierarchyNode
|
AstTypeRole.HierarchyNode
|
||||||
type.parent != null && type.values.none { it.abstract } ->
|
type.parent != null && (type.values != null && type.values!!.none { it.abstract }) ->
|
||||||
AstTypeRole.AstNode
|
AstTypeRole.AstNode
|
||||||
type.parent == null && type.values.isNotEmpty() ->
|
type.parent == null && (type.values != null && type.values!!.isNotEmpty()) ->
|
||||||
AstTypeRole.ValueHolder
|
AstTypeRole.ValueHolder
|
||||||
else -> throw RuntimeException("Unable to determine role of type ${type.name}")
|
else -> throw RuntimeException("Unable to determine role of type ${type.name}")
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,13 @@ class AstWorld {
|
|||||||
type.parent = world.typeRegistry.lookup(typeDescription.parent)
|
type.parent = world.typeRegistry.lookup(typeDescription.parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (value in typeDescription.values) {
|
if (typeDescription.values != null) {
|
||||||
val typeRef = AstTypeRef.parse(value.type, world.typeRegistry)
|
type.markHasValues()
|
||||||
val typeValue = AstValue(value.name, typeRef, abstract = value.required)
|
for (value in typeDescription.values) {
|
||||||
type.addValue(typeValue)
|
val typeRef = AstTypeRef.parse(value.type, world.typeRegistry)
|
||||||
|
val typeValue = AstValue(value.name, typeRef, abstract = value.required)
|
||||||
|
type.addValue(typeValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (enum in typeDescription.enums) {
|
for (enum in typeDescription.enums) {
|
||||||
|
@ -39,7 +39,7 @@ class CompilationUnitContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun definitionValue(definition: Definition): Any = when (definition) {
|
private fun definitionValue(definition: Definition): Any = when (definition) {
|
||||||
is FunctionDefinition -> FunctionContext(definition, internalScope)
|
is FunctionDefinition -> FunctionContext(this, definition)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processAllImports() {
|
private fun processAllImports() {
|
||||||
|
@ -8,6 +8,9 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
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 visitBreak(node: Break): Any = throw BreakMarker
|
||||||
|
|
||||||
override fun visitListLiteral(node: ListLiteral): Any =
|
override fun visitListLiteral(node: ListLiteral): Any =
|
||||||
node.items.map { it.visit(this) }
|
node.items.map { it.visit(this) }
|
||||||
|
|
||||||
@ -15,7 +18,8 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
|
|
||||||
override fun visitFunctionCall(node: FunctionCall): Any {
|
override fun visitFunctionCall(node: FunctionCall): Any {
|
||||||
val arguments = node.arguments.map { it.visit(this) }
|
val arguments = node.arguments.map { it.visit(this) }
|
||||||
return currentScope.call(node.symbol.id, Arguments(arguments))
|
val functionValue = currentScope.value(node.symbol.id) as CallableFunction
|
||||||
|
return functionValue.call(Arguments(arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLetAssignment(node: LetAssignment): Any {
|
override fun visitLetAssignment(node: LetAssignment): Any {
|
||||||
@ -27,6 +31,26 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
override fun visitSymbolReference(node: SymbolReference): Any =
|
override fun visitSymbolReference(node: SymbolReference): Any =
|
||||||
currentScope.value(node.symbol.id)
|
currentScope.value(node.symbol.id)
|
||||||
|
|
||||||
|
override fun visitWhile(node: While): Any {
|
||||||
|
val blockFunction = node.block.visit(this) as BlockFunction
|
||||||
|
var result: Any? = null
|
||||||
|
while (true) {
|
||||||
|
val value = node.condition.visit(this)
|
||||||
|
if (value !is Boolean) {
|
||||||
|
throw RuntimeException("While loop attempted on non-boolean value: $value")
|
||||||
|
}
|
||||||
|
if (!value) break
|
||||||
|
try {
|
||||||
|
scoped { result = blockFunction.call() }
|
||||||
|
} catch (_: BreakMarker) {
|
||||||
|
break
|
||||||
|
} catch (_: ContinueMarker) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result ?: None
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitParentheses(node: Parentheses): Any =
|
override fun visitParentheses(node: Parentheses): Any =
|
||||||
node.expression.visit(this)
|
node.expression.visit(this)
|
||||||
|
|
||||||
@ -45,11 +69,12 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
override fun visitIf(node: If): Any {
|
override fun visitIf(node: If): Any {
|
||||||
val condition = node.condition.visit(this)
|
val condition = node.condition.visit(this)
|
||||||
return if (condition == true) {
|
return if (condition == true) {
|
||||||
node.thenExpression.visit(this)
|
val blockFunction = node.thenBlock.visit(this) as BlockFunction
|
||||||
} else {
|
scoped { blockFunction.call() }
|
||||||
val elseExpression = node.elseExpression
|
} else if (node.elseBlock != null) {
|
||||||
elseExpression?.visit(this) ?: None
|
val blockFunction = node.elseBlock!!.visit(this) as BlockFunction
|
||||||
}
|
scoped { blockFunction.call() }
|
||||||
|
} else None
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitInfixOperation(node: InfixOperation): Any {
|
override fun visitInfixOperation(node: InfixOperation): Any {
|
||||||
@ -93,21 +118,42 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
||||||
throw RuntimeException(
|
throw RuntimeException(
|
||||||
"Function declarations cannot be visited in an EvaluationVisitor. " +
|
"Function declarations cannot be visited in an EvaluationVisitor. " +
|
||||||
"Utilize a FunctionContext."
|
"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. " +
|
||||||
"Utilize an EvaluationContext."
|
"Utilize an CompilationUnitContext."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCompilationUnit(node: CompilationUnit): Any {
|
override fun visitCompilationUnit(node: CompilationUnit): Any {
|
||||||
throw RuntimeException(
|
throw RuntimeException(
|
||||||
"Compilation units cannot be visited in an EvaluationVisitor. " +
|
"Compilation units cannot be visited in an EvaluationVisitor. " +
|
||||||
"Utilize an EvaluationContext."
|
"Utilize an CompilationUnitContext."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitNative(node: Native): Any {
|
||||||
|
throw RuntimeException(
|
||||||
|
"Native definition cannot be visited in an EvaluationVisitor. " +
|
||||||
|
"Utilize an FunctionContext."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitContinue(node: Continue): Any = ContinueMarker
|
||||||
|
|
||||||
|
private inline fun <T> scoped(block: () -> T): T {
|
||||||
|
currentScope = currentScope.fork()
|
||||||
|
try {
|
||||||
|
return block()
|
||||||
|
} finally {
|
||||||
|
currentScope = currentScope.leave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object BreakMarker : RuntimeException("Break Marker")
|
||||||
|
private object ContinueMarker: RuntimeException("Continue Marker")
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import gay.pizza.pork.frontend.World
|
|||||||
|
|
||||||
class Evaluator(val world: World, val scope: Scope) {
|
class Evaluator(val world: World, val scope: Scope) {
|
||||||
private val contexts = mutableMapOf<String, CompilationUnitContext>()
|
private val contexts = mutableMapOf<String, CompilationUnitContext>()
|
||||||
|
private val nativeFunctionProviders = mutableMapOf<String, NativeFunctionProvider>()
|
||||||
|
|
||||||
fun evaluate(path: String): Scope =
|
fun evaluate(path: String): Scope =
|
||||||
context(path).externalScope
|
context(path).externalScope
|
||||||
@ -17,4 +18,13 @@ class Evaluator(val world: World, val scope: Scope) {
|
|||||||
context.initIfNeeded()
|
context.initIfNeeded()
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun nativeFunctionProvider(form: String): NativeFunctionProvider {
|
||||||
|
return nativeFunctionProviders[form] ?:
|
||||||
|
throw RuntimeException("Unknown native function form: $form")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addNativeFunctionProvider(form: String, nativeFunctionProvider: NativeFunctionProvider) {
|
||||||
|
nativeFunctionProviders[form] = nativeFunctionProvider
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,27 @@ package gay.pizza.pork.evaluator
|
|||||||
|
|
||||||
import gay.pizza.pork.ast.FunctionDefinition
|
import gay.pizza.pork.ast.FunctionDefinition
|
||||||
|
|
||||||
class FunctionContext(val node: FunctionDefinition, val internalScope: Scope) : CallableFunction {
|
class FunctionContext(val compilationUnitContext: CompilationUnitContext, val node: FunctionDefinition) : CallableFunction {
|
||||||
override fun call(arguments: Arguments): Any {
|
override fun call(arguments: Arguments): Any {
|
||||||
val scope = internalScope.fork()
|
val scope = compilationUnitContext.internalScope.fork()
|
||||||
for ((index, argumentSymbol) in node.arguments.withIndex()) {
|
for ((index, argumentSymbol) in node.arguments.withIndex()) {
|
||||||
scope.define(argumentSymbol.id, arguments.values[index])
|
scope.define(argumentSymbol.id, arguments.values[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.native != null) {
|
||||||
|
val native = node.native!!
|
||||||
|
val nativeFunctionProvider =
|
||||||
|
compilationUnitContext.evaluator.nativeFunctionProvider(native.form.id)
|
||||||
|
val nativeFunction = nativeFunctionProvider.provideNativeFunction(native.definition.text)
|
||||||
|
return nativeFunction.call(arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.block == null) {
|
||||||
|
throw RuntimeException("Native or Block is required for FunctionDefinition")
|
||||||
|
}
|
||||||
|
|
||||||
val visitor = EvaluationVisitor(scope)
|
val visitor = EvaluationVisitor(scope)
|
||||||
val blockFunction = visitor.visitBlock(node.block)
|
val blockFunction = visitor.visitBlock(node.block!!)
|
||||||
return blockFunction.call()
|
return blockFunction.call()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
interface NativeFunctionProvider {
|
||||||
|
fun provideNativeFunction(definition: String): CallableFunction
|
||||||
|
}
|
@ -41,27 +41,19 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun call(name: String, arguments: Arguments): Any {
|
|
||||||
val value = value(name)
|
|
||||||
if (value !is CallableFunction) {
|
|
||||||
throw RuntimeException("$value is not callable")
|
|
||||||
}
|
|
||||||
return value.call(arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fork(): Scope =
|
fun fork(): Scope =
|
||||||
Scope(this)
|
Scope(this)
|
||||||
|
|
||||||
fun leave(): Scope {
|
|
||||||
if (parent == null) {
|
|
||||||
throw RuntimeException("Parent context not found")
|
|
||||||
}
|
|
||||||
return parent
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun inherit(scope: Scope) {
|
internal fun inherit(scope: Scope) {
|
||||||
inherited.add(scope)
|
inherited.add(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun leave(): Scope {
|
||||||
|
if (parent == null) {
|
||||||
|
throw RuntimeException("Attempted to leave the root scope!")
|
||||||
|
}
|
||||||
|
return parent
|
||||||
|
}
|
||||||
|
|
||||||
private object NotFound
|
private object NotFound
|
||||||
}
|
}
|
||||||
|
13
examples/ffi.pork
Normal file
13
examples/ffi.pork
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
func malloc(size)
|
||||||
|
native ffi "libc.dylib:malloc:void*"
|
||||||
|
|
||||||
|
func free(pointer)
|
||||||
|
native ffi "libc.dylib:free:void"
|
||||||
|
|
||||||
|
export func main() {
|
||||||
|
while true {
|
||||||
|
let pointer = malloc(8192)
|
||||||
|
println(pointer)
|
||||||
|
free(pointer)
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,14 @@
|
|||||||
/* fibonacci sequence */
|
/* fibonacci sequence */
|
||||||
func fib(n) {
|
func fib(n) {
|
||||||
if n == 0
|
if n == 0 {
|
||||||
then 0
|
0
|
||||||
else if n == 1
|
} else {
|
||||||
then 1
|
if n == 1 {
|
||||||
else fib(n - 1) + fib(n - 2)
|
1
|
||||||
|
} else {
|
||||||
|
fib(n - 1) + fib(n - 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export func main() {
|
export func main() {
|
||||||
|
6
examples/loop.pork
Normal file
6
examples/loop.pork
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export func main() {
|
||||||
|
while true {
|
||||||
|
println("Hello World")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
10
ffi/build.gradle.kts
Normal file
10
ffi/build.gradle.kts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
plugins {
|
||||||
|
id("gay.pizza.pork.module")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":evaluator"))
|
||||||
|
|
||||||
|
implementation(project(":common"))
|
||||||
|
implementation("net.java.dev.jna:jna:5.13.0")
|
||||||
|
}
|
26
ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt
Normal file
26
ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package gay.pizza.pork.ffi
|
||||||
|
|
||||||
|
import com.sun.jna.Function
|
||||||
|
import gay.pizza.pork.evaluator.CallableFunction
|
||||||
|
import gay.pizza.pork.evaluator.NativeFunctionProvider
|
||||||
|
|
||||||
|
class JnaNativeProvider : NativeFunctionProvider {
|
||||||
|
override fun provideNativeFunction(definition: String): CallableFunction {
|
||||||
|
val (libraryName, functionSymbol, returnType, _) =
|
||||||
|
definition.split(":", limit = 3)
|
||||||
|
val function = Function.getFunction(libraryName, functionSymbol)
|
||||||
|
return CallableFunction {
|
||||||
|
return@CallableFunction invoke(function, it.values.toTypedArray(), returnType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invoke(function: Function, values: Array<Any>, type: String): Any = when (type) {
|
||||||
|
"void*" -> function.invokePointer(values)
|
||||||
|
"int" -> function.invokeInt(values)
|
||||||
|
"long" -> function.invokeLong(values)
|
||||||
|
"float" -> function.invokeFloat(values)
|
||||||
|
"double" -> function.invokeDouble(values)
|
||||||
|
"void" -> function.invokeVoid(values)
|
||||||
|
else -> throw RuntimeException("Unsupported ffi return type: $type")
|
||||||
|
}
|
||||||
|
}
|
@ -72,13 +72,26 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
|||||||
private fun readIf(): If = within {
|
private fun readIf(): If = within {
|
||||||
expect(TokenType.If)
|
expect(TokenType.If)
|
||||||
val condition = readExpression()
|
val condition = readExpression()
|
||||||
expect(TokenType.Then)
|
val thenBlock = readBlock()
|
||||||
val thenExpression = readExpression()
|
var elseBlock: Block? = null
|
||||||
var elseExpression: Expression? = null
|
|
||||||
if (next(TokenType.Else)) {
|
if (next(TokenType.Else)) {
|
||||||
elseExpression = readExpression()
|
elseBlock = readBlock()
|
||||||
}
|
}
|
||||||
If(condition, thenExpression, elseExpression)
|
If(condition, thenBlock, elseBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readWhile(): While = within {
|
||||||
|
expect(TokenType.While)
|
||||||
|
val condition = readExpression()
|
||||||
|
val block = readBlock()
|
||||||
|
While(condition, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readNative(): Native = within {
|
||||||
|
expect(TokenType.Native)
|
||||||
|
val form = readSymbolRaw()
|
||||||
|
val definition = readStringLiteral()
|
||||||
|
Native(form, definition)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readExpression(): Expression {
|
fun readExpression(): Expression {
|
||||||
@ -120,6 +133,20 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
|||||||
readIf()
|
readIf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TokenType.While -> {
|
||||||
|
readWhile()
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenType.Break -> {
|
||||||
|
expect(TokenType.Break)
|
||||||
|
Break()
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenType.Continue -> {
|
||||||
|
expect(TokenType.Continue)
|
||||||
|
Continue()
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
throw RuntimeException(
|
throw RuntimeException(
|
||||||
"Failed to parse token: ${token.type} '${token.text}' as" +
|
"Failed to parse token: ${token.type} '${token.text}' as" +
|
||||||
@ -178,7 +205,15 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
|||||||
readSymbolRaw()
|
readSymbolRaw()
|
||||||
}
|
}
|
||||||
expect(TokenType.RightParentheses)
|
expect(TokenType.RightParentheses)
|
||||||
FunctionDefinition(modifiers, name, arguments, readBlock())
|
|
||||||
|
var native: Native? = null
|
||||||
|
var block: Block? = null
|
||||||
|
if (peek(TokenType.Native)) {
|
||||||
|
native = readNative()
|
||||||
|
} else {
|
||||||
|
block = readBlock()
|
||||||
|
}
|
||||||
|
FunctionDefinition(modifiers, name, arguments, block, native)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeReadDefinition(): Definition? {
|
private fun maybeReadDefinition(): Definition? {
|
||||||
|
@ -38,6 +38,8 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitBreak(node: Break): Unit = append("break")
|
||||||
|
|
||||||
override fun visitListLiteral(node: ListLiteral) {
|
override fun visitListLiteral(node: ListLiteral) {
|
||||||
append("[")
|
append("[")
|
||||||
if (node.items.isNotEmpty()) {
|
if (node.items.isNotEmpty()) {
|
||||||
@ -55,6 +57,13 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
append("]")
|
append("]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitNative(node: Native) {
|
||||||
|
append("native ")
|
||||||
|
visit(node.form)
|
||||||
|
append(" ")
|
||||||
|
visit(node.definition)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitSymbol(node: Symbol) {
|
override fun visitSymbol(node: Symbol) {
|
||||||
append(node.id)
|
append(node.id)
|
||||||
}
|
}
|
||||||
@ -82,6 +91,13 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
visit(node.symbol)
|
visit(node.symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitWhile(node: While) {
|
||||||
|
append("while ")
|
||||||
|
visit(node.condition)
|
||||||
|
append(" ")
|
||||||
|
visit(node.block)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitParentheses(node: Parentheses) {
|
override fun visitParentheses(node: Parentheses) {
|
||||||
append("(")
|
append("(")
|
||||||
visit(node.expression)
|
visit(node.expression)
|
||||||
@ -96,18 +112,13 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
override fun visitIf(node: If) {
|
override fun visitIf(node: If) {
|
||||||
append("if ")
|
append("if ")
|
||||||
visit(node.condition)
|
visit(node.condition)
|
||||||
append(" then")
|
append(" ")
|
||||||
out.increaseIndent()
|
visit(node.thenBlock)
|
||||||
appendLine()
|
if (node.elseBlock != null) {
|
||||||
visit(node.thenExpression)
|
append(" ")
|
||||||
out.decreaseIndent()
|
|
||||||
if (node.elseExpression != null) {
|
|
||||||
appendLine()
|
|
||||||
append("else")
|
append("else")
|
||||||
out.increaseIndent()
|
append(" ")
|
||||||
appendLine()
|
visit(node.elseBlock!!)
|
||||||
visit(node.elseExpression!!)
|
|
||||||
out.decreaseIndent()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +131,7 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionDefinition(node: FunctionDefinition) {
|
override fun visitFunctionDefinition(node: FunctionDefinition) {
|
||||||
append("fn ")
|
append("func ")
|
||||||
visit(node.symbol)
|
visit(node.symbol)
|
||||||
append("(")
|
append("(")
|
||||||
for ((index, argument) in node.arguments.withIndex()) {
|
for ((index, argument) in node.arguments.withIndex()) {
|
||||||
@ -130,7 +141,13 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
append(") ")
|
append(") ")
|
||||||
visit(node.block)
|
if (node.block != null) {
|
||||||
|
visit(node.block!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.native != null) {
|
||||||
|
visit(node.native!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBlock(node: Block) {
|
override fun visitBlock(node: Block) {
|
||||||
@ -167,4 +184,6 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
appendLine()
|
appendLine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitContinue(node: Continue): Unit = append("continue")
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,14 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
|
|||||||
False(Keyword("false"), KeywordFamily),
|
False(Keyword("false"), KeywordFamily),
|
||||||
True(Keyword("true"), KeywordFamily),
|
True(Keyword("true"), KeywordFamily),
|
||||||
If(Keyword("if"), KeywordFamily),
|
If(Keyword("if"), KeywordFamily),
|
||||||
Then(Keyword("then"), KeywordFamily),
|
|
||||||
Else(Keyword("else"), KeywordFamily),
|
Else(Keyword("else"), KeywordFamily),
|
||||||
|
While(Keyword("while"), KeywordFamily),
|
||||||
|
Continue(Keyword("continue"), KeywordFamily),
|
||||||
|
Break(Keyword("break"), KeywordFamily),
|
||||||
Import(Keyword("import"), KeywordFamily),
|
Import(Keyword("import"), KeywordFamily),
|
||||||
Export(Keyword("export"), KeywordFamily),
|
Export(Keyword("export"), KeywordFamily),
|
||||||
Func(Keyword("func"), KeywordFamily),
|
Func(Keyword("func"), KeywordFamily),
|
||||||
|
Native(Keyword("native"), KeywordFamily),
|
||||||
Let(Keyword("let"), KeywordFamily),
|
Let(Keyword("let"), KeywordFamily),
|
||||||
Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }),
|
Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }),
|
||||||
BlockComment(CommentFamily),
|
BlockComment(CommentFamily),
|
||||||
|
@ -8,16 +8,6 @@ include(
|
|||||||
":parser",
|
":parser",
|
||||||
":frontend",
|
":frontend",
|
||||||
":evaluator",
|
":evaluator",
|
||||||
|
":ffi",
|
||||||
":tool"
|
":tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
|
||||||
versionCatalogs {
|
|
||||||
create("libs") {
|
|
||||||
version("clikt", "4.2.0")
|
|
||||||
|
|
||||||
library("clikt", "com.github.ajalt.clikt", "clikt")
|
|
||||||
.versionRef("clikt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -10,7 +10,8 @@ dependencies {
|
|||||||
api(project(":parser"))
|
api(project(":parser"))
|
||||||
api(project(":frontend"))
|
api(project(":frontend"))
|
||||||
api(project(":evaluator"))
|
api(project(":evaluator"))
|
||||||
implementation(libs.clikt)
|
api(project(":ffi"))
|
||||||
|
api("com.github.ajalt.clikt:clikt:4.2.0")
|
||||||
implementation(project(":common"))
|
implementation(project(":common"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,11 @@ 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 gay.pizza.dough.fs.PlatformFsProvider
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
|
import gay.pizza.pork.evaluator.Arguments
|
||||||
import gay.pizza.pork.evaluator.CallableFunction
|
import gay.pizza.pork.evaluator.CallableFunction
|
||||||
import gay.pizza.pork.evaluator.None
|
import gay.pizza.pork.evaluator.None
|
||||||
import gay.pizza.pork.evaluator.Scope
|
import gay.pizza.pork.evaluator.Scope
|
||||||
|
import gay.pizza.pork.ffi.JnaNativeProvider
|
||||||
|
|
||||||
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()
|
||||||
@ -28,8 +30,12 @@ class RunCommand : CliktCommand(help = "Run Program", name = "run") {
|
|||||||
None
|
None
|
||||||
})
|
})
|
||||||
|
|
||||||
|
val main = tool.loadMainFunction(scope, setupEvaluator = {
|
||||||
|
addNativeFunctionProvider("ffi", JnaNativeProvider())
|
||||||
|
})
|
||||||
|
|
||||||
maybeLoopAndMeasure(loop, measure) {
|
maybeLoopAndMeasure(loop, measure) {
|
||||||
tool.evaluate(scope)
|
main.call(Arguments(emptyList()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ 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.ast.visit
|
||||||
import gay.pizza.pork.evaluator.Arguments
|
import gay.pizza.pork.evaluator.Arguments
|
||||||
|
import gay.pizza.pork.evaluator.CallableFunction
|
||||||
import gay.pizza.pork.evaluator.Evaluator
|
import gay.pizza.pork.evaluator.Evaluator
|
||||||
import gay.pizza.pork.evaluator.Scope
|
import gay.pizza.pork.evaluator.Scope
|
||||||
import gay.pizza.pork.frontend.ContentSource
|
import gay.pizza.pork.frontend.ContentSource
|
||||||
@ -29,11 +30,12 @@ abstract class Tool {
|
|||||||
|
|
||||||
fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
|
fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
|
||||||
|
|
||||||
fun evaluate(scope: Scope) {
|
fun loadMainFunction(scope: Scope, setupEvaluator: Evaluator.() -> Unit = {}): CallableFunction {
|
||||||
val contentSource = createContentSource()
|
val contentSource = createContentSource()
|
||||||
val world = World(contentSource)
|
val world = World(contentSource)
|
||||||
val evaluator = Evaluator(world, scope)
|
val evaluator = Evaluator(world, scope)
|
||||||
|
setupEvaluator(evaluator)
|
||||||
val resultingScope = evaluator.evaluate(rootFilePath())
|
val resultingScope = evaluator.evaluate(rootFilePath())
|
||||||
resultingScope.call("main", Arguments(emptyList()))
|
return resultingScope.value("main") as CallableFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user