mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 21:00:56 +00:00
Implement a very dumb import system.
This commit is contained in:
parent
e7be1f622d
commit
ed5bbec004
5
examples/imports.pork
Normal file
5
examples/imports.pork
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import "module.pork"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
hello()
|
||||||
|
}
|
3
examples/module.pork
Normal file
3
examples/module.pork
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
func hello() {
|
||||||
|
println("Hello World")
|
||||||
|
}
|
@ -9,15 +9,16 @@ class NodeCoalescer(val handler: (Node) -> Unit) : NodeVisitor<Unit> {
|
|||||||
override fun visitListLiteral(node: ListLiteral): Unit = handle(node)
|
override fun visitListLiteral(node: ListLiteral): Unit = handle(node)
|
||||||
override fun visitSymbol(node: Symbol): Unit = handle(node)
|
override fun visitSymbol(node: Symbol): Unit = handle(node)
|
||||||
override fun visitFunctionCall(node: FunctionCall): Unit = handle(node)
|
override fun visitFunctionCall(node: FunctionCall): Unit = handle(node)
|
||||||
override fun visitDefine(node: Define): Unit = handle(node)
|
override fun visitDefine(node: Assignment): Unit = handle(node)
|
||||||
override fun visitSymbolReference(node: SymbolReference): Unit = handle(node)
|
override fun visitSymbolReference(node: SymbolReference): Unit = handle(node)
|
||||||
override fun visitLambda(node: Lambda): Unit = handle(node)
|
override fun visitLambda(node: Lambda): Unit = handle(node)
|
||||||
override fun visitParentheses(node: Parentheses): Unit = handle(node)
|
override fun visitParentheses(node: Parentheses): Unit = handle(node)
|
||||||
override fun visitPrefixOperation(node: PrefixOperation): Unit = handle(node)
|
override fun visitPrefixOperation(node: PrefixOperation): Unit = handle(node)
|
||||||
override fun visitIf(node: If): Unit = handle(node)
|
override fun visitIf(node: If): Unit = handle(node)
|
||||||
override fun visitInfixOperation(node: InfixOperation): Unit = handle(node)
|
override fun visitInfixOperation(node: InfixOperation): Unit = handle(node)
|
||||||
override fun visitFunctionDeclaration(node: FunctionDeclaration): Unit = handle(node)
|
override fun visitFunctionDeclaration(node: FunctionDefinition): Unit = handle(node)
|
||||||
override fun visitBlock(node: Block): Unit = handle(node)
|
override fun visitBlock(node: Block): Unit = handle(node)
|
||||||
|
override fun visitImportDeclaration(node: ImportDeclaration): Unit = handle(node)
|
||||||
|
|
||||||
override fun visitCompilationUnit(node: CompilationUnit): Unit = handle(node)
|
override fun visitCompilationUnit(node: CompilationUnit): Unit = handle(node)
|
||||||
|
|
||||||
|
@ -12,13 +12,14 @@ enum class NodeType(val parent: NodeType? = null) {
|
|||||||
ListLiteral(Expression),
|
ListLiteral(Expression),
|
||||||
StringLiteral(Expression),
|
StringLiteral(Expression),
|
||||||
Parentheses(Expression),
|
Parentheses(Expression),
|
||||||
Define(Expression),
|
Assignment(Expression),
|
||||||
Lambda(Expression),
|
Lambda(Expression),
|
||||||
PrefixOperation(Expression),
|
PrefixOperation(Expression),
|
||||||
InfixOperation(Expression),
|
InfixOperation(Expression),
|
||||||
SymbolReference(Expression),
|
SymbolReference(Expression),
|
||||||
FunctionCall(Expression),
|
FunctionCall(Expression),
|
||||||
If(Expression),
|
If(Expression),
|
||||||
|
ImportDeclaration(Declaration),
|
||||||
FunctionDeclaration(Declaration);
|
FunctionDeclaration(Declaration);
|
||||||
|
|
||||||
val parents: Set<NodeType>
|
val parents: Set<NodeType>
|
||||||
|
@ -9,16 +9,17 @@ interface NodeVisitor<T> {
|
|||||||
fun visitListLiteral(node: ListLiteral): T
|
fun visitListLiteral(node: ListLiteral): T
|
||||||
fun visitSymbol(node: Symbol): T
|
fun visitSymbol(node: Symbol): T
|
||||||
fun visitFunctionCall(node: FunctionCall): T
|
fun visitFunctionCall(node: FunctionCall): T
|
||||||
fun visitDefine(node: Define): T
|
fun visitDefine(node: Assignment): T
|
||||||
fun visitSymbolReference(node: SymbolReference): T
|
fun visitSymbolReference(node: SymbolReference): T
|
||||||
fun visitLambda(node: Lambda): T
|
fun visitLambda(node: Lambda): T
|
||||||
fun visitParentheses(node: Parentheses): T
|
fun visitParentheses(node: Parentheses): T
|
||||||
fun visitPrefixOperation(node: PrefixOperation): T
|
fun visitPrefixOperation(node: PrefixOperation): T
|
||||||
fun visitIf(node: If): T
|
fun visitIf(node: If): T
|
||||||
fun visitInfixOperation(node: InfixOperation): T
|
fun visitInfixOperation(node: InfixOperation): T
|
||||||
fun visitFunctionDeclaration(node: FunctionDeclaration): T
|
fun visitFunctionDeclaration(node: FunctionDefinition): T
|
||||||
fun visitBlock(node: Block): T
|
fun visitBlock(node: Block): T
|
||||||
|
|
||||||
|
fun visitImportDeclaration(node: ImportDeclaration): T
|
||||||
fun visitCompilationUnit(node: CompilationUnit): T
|
fun visitCompilationUnit(node: CompilationUnit): T
|
||||||
|
|
||||||
fun visitExpression(node: Expression): T = when (node) {
|
fun visitExpression(node: Expression): T = when (node) {
|
||||||
@ -27,7 +28,7 @@ interface NodeVisitor<T> {
|
|||||||
is BooleanLiteral -> visitBooleanLiteral(node)
|
is BooleanLiteral -> visitBooleanLiteral(node)
|
||||||
is ListLiteral -> visitListLiteral(node)
|
is ListLiteral -> visitListLiteral(node)
|
||||||
is FunctionCall -> visitFunctionCall(node)
|
is FunctionCall -> visitFunctionCall(node)
|
||||||
is Define -> visitDefine(node)
|
is Assignment -> visitDefine(node)
|
||||||
is SymbolReference -> visitSymbolReference(node)
|
is SymbolReference -> visitSymbolReference(node)
|
||||||
is Lambda -> visitLambda(node)
|
is Lambda -> visitLambda(node)
|
||||||
is Parentheses -> visitParentheses(node)
|
is Parentheses -> visitParentheses(node)
|
||||||
@ -37,7 +38,11 @@ interface NodeVisitor<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun visitDeclaration(node: Declaration): T = when (node) {
|
fun visitDeclaration(node: Declaration): T = when (node) {
|
||||||
is FunctionDeclaration -> visitFunctionDeclaration(node)
|
is ImportDeclaration -> visitImportDeclaration(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun visitDefinition(node: Definition): T = when (node) {
|
||||||
|
is FunctionDefinition -> visitFunctionDeclaration(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(node: Node): T = when (node) {
|
fun visit(node: Node): T = when (node) {
|
||||||
@ -46,6 +51,7 @@ interface NodeVisitor<T> {
|
|||||||
is CompilationUnit -> visitCompilationUnit(node)
|
is CompilationUnit -> visitCompilationUnit(node)
|
||||||
is Block -> visitBlock(node)
|
is Block -> visitBlock(node)
|
||||||
is Declaration -> visitDeclaration(node)
|
is Declaration -> visitDeclaration(node)
|
||||||
|
is Definition -> visitDefinition(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visitNodes(vararg nodes: Node?): List<T> =
|
fun visitNodes(vararg nodes: Node?): List<T> =
|
||||||
|
@ -72,7 +72,7 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
append(")")
|
append(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDefine(node: Define) {
|
override fun visitDefine(node: Assignment) {
|
||||||
visit(node.symbol)
|
visit(node.symbol)
|
||||||
append(" = ")
|
append(" = ")
|
||||||
visit(node.value)
|
visit(node.value)
|
||||||
@ -147,7 +147,7 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
visit(node.right)
|
visit(node.right)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionDeclaration(node: FunctionDeclaration) {
|
override fun visitFunctionDeclaration(node: FunctionDefinition) {
|
||||||
append("fn ")
|
append("fn ")
|
||||||
visit(node.symbol)
|
visit(node.symbol)
|
||||||
append("(")
|
append("(")
|
||||||
@ -175,10 +175,24 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
|
|||||||
append("}")
|
append("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitImportDeclaration(node: ImportDeclaration) {
|
||||||
|
append("import ")
|
||||||
|
visit(node.path)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitCompilationUnit(node: CompilationUnit) {
|
override fun visitCompilationUnit(node: CompilationUnit) {
|
||||||
for (declaration in node.declarations) {
|
for (declaration in node.declarations) {
|
||||||
visit(declaration)
|
visit(declaration)
|
||||||
appendLine()
|
appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.declarations.isNotEmpty()) {
|
||||||
|
appendLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
for (definition in node.definitions) {
|
||||||
|
visit(definition)
|
||||||
|
appendLine()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,15 @@ import kotlinx.serialization.SerialName
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("define")
|
@SerialName("assignment")
|
||||||
class Define(val symbol: Symbol, val value: Expression) : Expression() {
|
class Assignment(val symbol: Symbol, val value: Expression) : Expression() {
|
||||||
override val type: NodeType = NodeType.Define
|
override val type: NodeType = NodeType.Assignment
|
||||||
|
|
||||||
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 equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is Define) return false
|
if (other !is Assignment) return false
|
||||||
return other.symbol == symbol && other.value == value
|
return other.symbol == symbol && other.value == value
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("compilationUnit")
|
@SerialName("compilationUnit")
|
||||||
class CompilationUnit(val declarations: List<Declaration>) : Node() {
|
class CompilationUnit(val declarations: List<Declaration>, val definitions: List<Definition>) : Node() {
|
||||||
override val type: NodeType = NodeType.CompilationUnit
|
override val type: NodeType = NodeType.CompilationUnit
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
|
6
src/main/kotlin/gay/pizza/pork/ast/nodes/Definition.kt
Normal file
6
src/main/kotlin/gay/pizza/pork/ast/nodes/Definition.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package gay.pizza.pork.ast.nodes
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed class Definition : Node()
|
@ -6,23 +6,23 @@ import kotlinx.serialization.SerialName
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("functionDeclaration")
|
@SerialName("functionDefinition")
|
||||||
class FunctionDeclaration(val symbol: Symbol, val arguments: List<Symbol>, val block: Block) : Declaration() {
|
class FunctionDefinition(val symbol: Symbol, val arguments: List<Symbol>, val block: Block) : Definition() {
|
||||||
override val type: NodeType = NodeType.FunctionDeclaration
|
override val type: NodeType = NodeType.FunctionDeclaration
|
||||||
|
|
||||||
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 equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is FunctionDeclaration) return false
|
if (other !is FunctionDefinition) return false
|
||||||
return other.symbol == symbol && other.arguments == arguments && other.block == block
|
return other.symbol == symbol && other.arguments == arguments && other.block == block
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = symbol.hashCode()
|
var 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 + type.hashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package gay.pizza.pork.ast.nodes
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.NodeType
|
||||||
|
import gay.pizza.pork.ast.NodeVisitor
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("importDeclaration")
|
||||||
|
class ImportDeclaration(val path: StringLiteral) : Declaration() {
|
||||||
|
override val type: NodeType = NodeType.FunctionDeclaration
|
||||||
|
|
||||||
|
override fun <T> visitChildren(visitor: NodeVisitor<T>): List<T> =
|
||||||
|
visitor.visitNodes(path)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is ImportDeclaration) return false
|
||||||
|
return other.path == path
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = path.hashCode()
|
||||||
|
result = 31 * result + type.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ package gay.pizza.pork.eval
|
|||||||
import gay.pizza.pork.ast.NodeVisitor
|
import gay.pizza.pork.ast.NodeVisitor
|
||||||
import gay.pizza.pork.ast.nodes.*
|
import gay.pizza.pork.ast.nodes.*
|
||||||
|
|
||||||
class Evaluator(root: Scope) : NodeVisitor<Any> {
|
class Evaluator(root: Scope, val importLoader: ImportLoader) : 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
|
||||||
@ -18,7 +18,7 @@ class Evaluator(root: Scope) : NodeVisitor<Any> {
|
|||||||
return currentScope.call(node.symbol.id, Arguments(arguments))
|
return currentScope.call(node.symbol.id, Arguments(arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDefine(node: Define): Any {
|
override fun visitDefine(node: Assignment): Any {
|
||||||
val value = visit(node.value)
|
val value = visit(node.value)
|
||||||
currentScope.define(node.symbol.id, value)
|
currentScope.define(node.symbol.id, value)
|
||||||
return value
|
return value
|
||||||
@ -102,7 +102,7 @@ class Evaluator(root: Scope) : NodeVisitor<Any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionDeclaration(node: FunctionDeclaration): Any {
|
override fun visitFunctionDeclaration(node: FunctionDefinition): Any {
|
||||||
val blockFunction = visitBlock(node.block) as BlockFunction
|
val blockFunction = visitBlock(node.block) as BlockFunction
|
||||||
val function = CallableFunction { arguments ->
|
val function = CallableFunction { arguments ->
|
||||||
currentScope = currentScope.fork()
|
currentScope = currentScope.fork()
|
||||||
@ -127,10 +127,21 @@ class Evaluator(root: Scope) : NodeVisitor<Any> {
|
|||||||
value ?: None
|
value ?: None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitImportDeclaration(node: ImportDeclaration): Any {
|
||||||
|
val importPath = node.path.text
|
||||||
|
val compilationUnit = importLoader.load(importPath)
|
||||||
|
visit(compilationUnit)
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitCompilationUnit(node: CompilationUnit): Any {
|
override fun visitCompilationUnit(node: CompilationUnit): Any {
|
||||||
for (declaration in node.declarations) {
|
for (declaration in node.declarations) {
|
||||||
visit(declaration)
|
visit(declaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (definition in node.definitions) {
|
||||||
|
visit(definition)
|
||||||
|
}
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
src/main/kotlin/gay/pizza/pork/eval/ImportLoader.kt
Normal file
7
src/main/kotlin/gay/pizza/pork/eval/ImportLoader.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.eval
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.nodes.CompilationUnit
|
||||||
|
|
||||||
|
interface ImportLoader {
|
||||||
|
fun load(path: String): CompilationUnit
|
||||||
|
}
|
9
src/main/kotlin/gay/pizza/pork/eval/NullImportLoader.kt
Normal file
9
src/main/kotlin/gay/pizza/pork/eval/NullImportLoader.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package gay.pizza.pork.eval
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.nodes.CompilationUnit
|
||||||
|
|
||||||
|
object NullImportLoader : ImportLoader {
|
||||||
|
override fun load(path: String): CompilationUnit {
|
||||||
|
throw RuntimeException("NullImportLoader cannot import compilation units.")
|
||||||
|
}
|
||||||
|
}
|
@ -7,4 +7,6 @@ import kotlin.io.path.readText
|
|||||||
|
|
||||||
class FileFrontend(val path: Path) : Frontend() {
|
class FileFrontend(val path: Path) : Frontend() {
|
||||||
override fun createCharSource(): CharSource = StringCharSource(path.readText())
|
override fun createCharSource(): CharSource = StringCharSource(path.readText())
|
||||||
|
override fun resolveImportSource(path: String): CharSource =
|
||||||
|
StringCharSource(this.path.parent.resolve(path).readText())
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,13 @@ import gay.pizza.pork.ast.NodeVisitor
|
|||||||
import gay.pizza.pork.ast.Printer
|
import gay.pizza.pork.ast.Printer
|
||||||
import gay.pizza.pork.ast.nodes.CompilationUnit
|
import gay.pizza.pork.ast.nodes.CompilationUnit
|
||||||
import gay.pizza.pork.eval.Evaluator
|
import gay.pizza.pork.eval.Evaluator
|
||||||
|
import gay.pizza.pork.eval.ImportLoader
|
||||||
import gay.pizza.pork.eval.Scope
|
import gay.pizza.pork.eval.Scope
|
||||||
import gay.pizza.pork.parse.*
|
import gay.pizza.pork.parse.*
|
||||||
|
|
||||||
abstract class Frontend {
|
abstract class Frontend {
|
||||||
abstract fun createCharSource(): CharSource
|
abstract fun createCharSource(): CharSource
|
||||||
|
abstract fun resolveImportSource(path: String): CharSource
|
||||||
|
|
||||||
fun tokenize(): TokenStream =
|
fun tokenize(): TokenStream =
|
||||||
Tokenizer(createCharSource()).tokenize()
|
Tokenizer(createCharSource()).tokenize()
|
||||||
@ -20,9 +22,16 @@ abstract class Frontend {
|
|||||||
Highlighter(scheme).highlight(tokenize())
|
Highlighter(scheme).highlight(tokenize())
|
||||||
|
|
||||||
fun evaluate(scope: Scope = Scope()): Any =
|
fun evaluate(scope: Scope = Scope()): Any =
|
||||||
visit(Evaluator(scope))
|
visit(Evaluator(scope, FrontendImportLoader(this)))
|
||||||
|
|
||||||
fun reprint(): String = buildString { visit(Printer(this)) }
|
fun reprint(): String = buildString { visit(Printer(this)) }
|
||||||
|
|
||||||
fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
|
fun <T> visit(visitor: NodeVisitor<T>): T = visitor.visit(parse())
|
||||||
|
|
||||||
|
private class FrontendImportLoader(val frontend: Frontend) : ImportLoader {
|
||||||
|
override fun load(path: String): CompilationUnit {
|
||||||
|
val tokenStream = Tokenizer(frontend.resolveImportSource(path)).tokenize()
|
||||||
|
return Parser(TokenStreamSource(tokenStream), DiscardNodeAttribution).readCompilationUnit()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
|||||||
expect(TokenType.RightParentheses)
|
expect(TokenType.RightParentheses)
|
||||||
FunctionCall(symbol, arguments)
|
FunctionCall(symbol, arguments)
|
||||||
} else if (next(TokenType.Equals)) {
|
} else if (next(TokenType.Equals)) {
|
||||||
Define(symbol, readExpression())
|
Assignment(symbol, readExpression())
|
||||||
} else {
|
} else {
|
||||||
SymbolReference(symbol)
|
SymbolReference(symbol)
|
||||||
}
|
}
|
||||||
@ -169,19 +169,44 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
|||||||
Block(items)
|
Block(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readFunctionDeclaration(): FunctionDeclaration = within {
|
private fun readImportDeclaration(): ImportDeclaration = within {
|
||||||
|
expect(TokenType.Import)
|
||||||
|
ImportDeclaration(readStringLiteral())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readFunctionDeclaration(): FunctionDefinition = within {
|
||||||
expect(TokenType.Func)
|
expect(TokenType.Func)
|
||||||
val name = readSymbolRaw()
|
val name = readSymbolRaw()
|
||||||
expect(TokenType.LeftParentheses)
|
expect(TokenType.LeftParentheses)
|
||||||
val arguments = collect(TokenType.RightParentheses, TokenType.Comma) { readSymbolRaw() }
|
val arguments = collect(TokenType.RightParentheses, TokenType.Comma) { readSymbolRaw() }
|
||||||
expect(TokenType.RightParentheses)
|
expect(TokenType.RightParentheses)
|
||||||
FunctionDeclaration(name, arguments, readBlock())
|
FunctionDefinition(name, arguments, readBlock())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeReadDefinition(): Definition? {
|
||||||
|
val token = peek()
|
||||||
|
return when (token.type) {
|
||||||
|
TokenType.Func -> readFunctionDeclaration()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readDefinition(): Definition {
|
||||||
|
val definition = maybeReadDefinition()
|
||||||
|
if (definition != null) {
|
||||||
|
return definition
|
||||||
|
}
|
||||||
|
val token = peek()
|
||||||
|
throw RuntimeException(
|
||||||
|
"Failed to parse token: ${token.type} '${token.text}' as" +
|
||||||
|
" definition (index ${unsanitizedSource.currentIndex})"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readDeclaration(): Declaration {
|
fun readDeclaration(): Declaration {
|
||||||
val token = peek()
|
val token = peek()
|
||||||
return when (token.type) {
|
return when (token.type) {
|
||||||
TokenType.Func -> readFunctionDeclaration()
|
TokenType.Import -> readImportDeclaration()
|
||||||
else -> throw RuntimeException(
|
else -> throw RuntimeException(
|
||||||
"Failed to parse token: ${token.type} '${token.text}' as" +
|
"Failed to parse token: ${token.type} '${token.text}' as" +
|
||||||
" declaration (index ${unsanitizedSource.currentIndex})"
|
" declaration (index ${unsanitizedSource.currentIndex})"
|
||||||
@ -201,9 +226,25 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readCompilationUnit(): CompilationUnit = within {
|
fun readCompilationUnit(): CompilationUnit = within {
|
||||||
val declarations = collect(TokenType.EndOfFile) { readDeclaration() }
|
val declarations = mutableListOf<Declaration>()
|
||||||
expect(TokenType.EndOfFile)
|
val definitions = mutableListOf<Definition>()
|
||||||
CompilationUnit(declarations)
|
var declarationAccepted = true
|
||||||
|
|
||||||
|
while (!peek(TokenType.EndOfFile)) {
|
||||||
|
if (declarationAccepted) {
|
||||||
|
val definition = maybeReadDefinition()
|
||||||
|
if (definition != null) {
|
||||||
|
declarationAccepted = false
|
||||||
|
definitions.add(definition)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
declarations.add(readDeclaration())
|
||||||
|
} else {
|
||||||
|
definitions.add(readDefinition())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilationUnit(declarations, definitions)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> collect(
|
private fun <T> collect(
|
||||||
|
@ -28,6 +28,7 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
|
|||||||
If(Keyword("if"), KeywordFamily),
|
If(Keyword("if"), KeywordFamily),
|
||||||
Then(Keyword("then"), KeywordFamily),
|
Then(Keyword("then"), KeywordFamily),
|
||||||
Else(Keyword("else"), KeywordFamily),
|
Else(Keyword("else"), KeywordFamily),
|
||||||
|
Import(Keyword("import"), KeywordFamily),
|
||||||
Func(Keyword("func"), KeywordFamily),
|
Func(Keyword("func"), KeywordFamily),
|
||||||
Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }),
|
Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }),
|
||||||
BlockComment(CommentFamily),
|
BlockComment(CommentFamily),
|
||||||
|
Loading…
Reference in New Issue
Block a user