diff --git a/src/main/kotlin/gay/pizza/pork/ast/nodes/Node.kt b/src/main/kotlin/gay/pizza/pork/ast/nodes/Node.kt index a7d2f6f..d98c56a 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/nodes/Node.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/nodes/Node.kt @@ -10,5 +10,6 @@ sealed class Node { abstract val type: NodeType open fun visitChildren(visitor: NodeVisitor): List = emptyList() - override fun toString(): String = let { node -> buildString { Printer(this).visit(node) } } + override fun toString(): String = + let { node -> buildString { Printer(this).visit(node) } } } diff --git a/src/main/kotlin/gay/pizza/pork/cli/AstCommand.kt b/src/main/kotlin/gay/pizza/pork/cli/AstCommand.kt index fbd87c0..3c3a547 100644 --- a/src/main/kotlin/gay/pizza/pork/cli/AstCommand.kt +++ b/src/main/kotlin/gay/pizza/pork/cli/AstCommand.kt @@ -4,13 +4,9 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.types.path import gay.pizza.pork.ast.nodes.Node -import gay.pizza.pork.parse.PorkParser -import gay.pizza.pork.parse.PorkTokenizer -import gay.pizza.pork.parse.StringCharSource -import gay.pizza.pork.parse.TokenStreamSource +import gay.pizza.pork.frontend.FileFrontend import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json -import kotlin.io.path.readText @OptIn(ExperimentalSerializationApi::class) class AstCommand : CliktCommand(help = "Print AST", name = "ast") { @@ -23,9 +19,7 @@ class AstCommand : CliktCommand(help = "Print AST", name = "ast") { } override fun run() { - val content = path.readText() - val tokenStream = PorkTokenizer(StringCharSource(content)).tokenize() - val program = PorkParser(TokenStreamSource(tokenStream)).readProgram() - println(json.encodeToString(Node.serializer(), program)) + val frontend = FileFrontend(path) + println(json.encodeToString(Node.serializer(), frontend.parse())) } } diff --git a/src/main/kotlin/gay/pizza/pork/cli/GenerateKotlinCommand.kt b/src/main/kotlin/gay/pizza/pork/cli/GenerateKotlinCommand.kt index 446d152..fdfc9a5 100644 --- a/src/main/kotlin/gay/pizza/pork/cli/GenerateKotlinCommand.kt +++ b/src/main/kotlin/gay/pizza/pork/cli/GenerateKotlinCommand.kt @@ -4,20 +4,13 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.types.path import gay.pizza.pork.compiler.KotlinCompiler -import gay.pizza.pork.parse.PorkParser -import gay.pizza.pork.parse.PorkTokenizer -import gay.pizza.pork.parse.StringCharSource -import gay.pizza.pork.parse.TokenStreamSource -import kotlin.io.path.readText +import gay.pizza.pork.frontend.FileFrontend class GenerateKotlinCommand : CliktCommand(help = "Generate Kotlin Code", name = "generate-kotlin") { val path by argument("file").path(mustExist = true, canBeDir = false) override fun run() { - val content = path.readText() - val tokenStream = PorkTokenizer(StringCharSource(content)).tokenize() - val program = PorkParser(TokenStreamSource(tokenStream)).readProgram() - val compiler = KotlinCompiler() - println(compiler.visit(program)) + val frontend = FileFrontend(path) + println(frontend.visit(KotlinCompiler())) } } diff --git a/src/main/kotlin/gay/pizza/pork/cli/HighlightCommand.kt b/src/main/kotlin/gay/pizza/pork/cli/HighlightCommand.kt index c1c6873..e58fd92 100644 --- a/src/main/kotlin/gay/pizza/pork/cli/HighlightCommand.kt +++ b/src/main/kotlin/gay/pizza/pork/cli/HighlightCommand.kt @@ -3,19 +3,14 @@ package gay.pizza.pork.cli import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.types.path +import gay.pizza.pork.frontend.FileFrontend import gay.pizza.pork.parse.AnsiHighlightScheme -import gay.pizza.pork.parse.Highlighter -import gay.pizza.pork.parse.PorkTokenizer -import gay.pizza.pork.parse.StringCharSource -import kotlin.io.path.readText class HighlightCommand : CliktCommand(help = "Syntax Highlighter", name = "highlight") { val path by argument("file").path(mustExist = true, canBeDir = false) override fun run() { - val content = path.readText() - val tokenStream = PorkTokenizer(StringCharSource(content)).tokenize() - val highlighter = Highlighter(AnsiHighlightScheme()) - print(highlighter.highlight(tokenStream).joinToString("")) + val frontend = FileFrontend(path) + print(frontend.highlight(AnsiHighlightScheme()).joinToString("")) } } diff --git a/src/main/kotlin/gay/pizza/pork/cli/ReprintCommand.kt b/src/main/kotlin/gay/pizza/pork/cli/ReprintCommand.kt index 13b1935..8a53c67 100644 --- a/src/main/kotlin/gay/pizza/pork/cli/ReprintCommand.kt +++ b/src/main/kotlin/gay/pizza/pork/cli/ReprintCommand.kt @@ -3,20 +3,13 @@ package gay.pizza.pork.cli import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.types.path -import gay.pizza.pork.ast.Printer -import gay.pizza.pork.parse.PorkParser -import gay.pizza.pork.parse.PorkTokenizer -import gay.pizza.pork.parse.StringCharSource -import gay.pizza.pork.parse.TokenStreamSource -import kotlin.io.path.readText +import gay.pizza.pork.frontend.FileFrontend class ReprintCommand : CliktCommand(help = "Reprint Parsed Program", name = "reprint") { val path by argument("file").path(mustExist = true, canBeDir = false) override fun run() { - val content = path.readText() - val tokenStream = PorkTokenizer(StringCharSource(content)).tokenize() - val program = PorkParser(TokenStreamSource(tokenStream)).readProgram() - print(buildString { Printer(this).visit(program) }) + val frontend = FileFrontend(path) + print(frontend.reprint()) } } diff --git a/src/main/kotlin/gay/pizza/pork/cli/RunCommand.kt b/src/main/kotlin/gay/pizza/pork/cli/RunCommand.kt index 7c4a7de..a2182b8 100644 --- a/src/main/kotlin/gay/pizza/pork/cli/RunCommand.kt +++ b/src/main/kotlin/gay/pizza/pork/cli/RunCommand.kt @@ -4,29 +4,20 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.types.path import gay.pizza.pork.eval.CallableFunction -import gay.pizza.pork.eval.PorkEvaluator import gay.pizza.pork.eval.Scope -import gay.pizza.pork.parse.PorkParser -import gay.pizza.pork.parse.PorkTokenizer -import gay.pizza.pork.parse.StringCharSource -import gay.pizza.pork.parse.TokenStreamSource -import kotlin.io.path.readText +import gay.pizza.pork.frontend.FileFrontend class RunCommand : CliktCommand(help = "Run Program", name = "run") { val path by argument("file").path(mustExist = true, canBeDir = false) override fun run() { - val content = path.readText() - val tokenStream = PorkTokenizer(StringCharSource(content)).tokenize() - val program = PorkParser(TokenStreamSource(tokenStream)).readProgram() - + val frontend = FileFrontend(path) val scope = Scope() scope.define("println", CallableFunction { arguments -> for (argument in arguments.values) { println(argument) } }) - val evaluator = PorkEvaluator(scope) - evaluator.visit(program) + frontend.evaluate(scope) } } diff --git a/src/main/kotlin/gay/pizza/pork/cli/TokenizeCommand.kt b/src/main/kotlin/gay/pizza/pork/cli/TokenizeCommand.kt index 4ac51d0..d9e67c6 100644 --- a/src/main/kotlin/gay/pizza/pork/cli/TokenizeCommand.kt +++ b/src/main/kotlin/gay/pizza/pork/cli/TokenizeCommand.kt @@ -3,16 +3,14 @@ package gay.pizza.pork.cli import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.types.path -import gay.pizza.pork.parse.PorkTokenizer -import gay.pizza.pork.parse.StringCharSource -import kotlin.io.path.readText +import gay.pizza.pork.frontend.FileFrontend class TokenizeCommand : CliktCommand(help = "Tokenize Program", name = "tokenize") { val path by argument("file").path(mustExist = true, canBeDir = false) override fun run() { - val content = path.readText() - val tokenStream = PorkTokenizer(StringCharSource(content)).tokenize() + val frontend = FileFrontend(path) + val tokenStream = frontend.tokenize() for (token in tokenStream.tokens) { println("${token.start} ${token.type.name} '${sanitize(token.text)}'") } diff --git a/src/main/kotlin/gay/pizza/pork/eval/PorkEvaluator.kt b/src/main/kotlin/gay/pizza/pork/eval/Evaluator.kt similarity index 98% rename from src/main/kotlin/gay/pizza/pork/eval/PorkEvaluator.kt rename to src/main/kotlin/gay/pizza/pork/eval/Evaluator.kt index b00a893..1d73ef9 100644 --- a/src/main/kotlin/gay/pizza/pork/eval/PorkEvaluator.kt +++ b/src/main/kotlin/gay/pizza/pork/eval/Evaluator.kt @@ -3,7 +3,7 @@ package gay.pizza.pork.eval import gay.pizza.pork.ast.* import gay.pizza.pork.ast.nodes.* -class PorkEvaluator(root: Scope) : NodeVisitor { +class Evaluator(root: Scope) : NodeVisitor { private var currentScope: Scope = root override fun visitDefine(node: Define): Any { diff --git a/src/main/kotlin/gay/pizza/pork/frontend/FileFrontend.kt b/src/main/kotlin/gay/pizza/pork/frontend/FileFrontend.kt new file mode 100644 index 0000000..5a64d8c --- /dev/null +++ b/src/main/kotlin/gay/pizza/pork/frontend/FileFrontend.kt @@ -0,0 +1,11 @@ +package gay.pizza.pork.frontend + +import gay.pizza.pork.ast.NodeVisitor +import gay.pizza.pork.parse.CharSource +import gay.pizza.pork.parse.StringCharSource +import java.nio.file.Path +import kotlin.io.path.readText + +class FileFrontend(val path: Path) : Frontend() { + override fun createCharSource(): CharSource = StringCharSource(path.readText()) +} diff --git a/src/main/kotlin/gay/pizza/pork/frontend/Frontend.kt b/src/main/kotlin/gay/pizza/pork/frontend/Frontend.kt new file mode 100644 index 0000000..ecd3fcb --- /dev/null +++ b/src/main/kotlin/gay/pizza/pork/frontend/Frontend.kt @@ -0,0 +1,28 @@ +package gay.pizza.pork.frontend + +import gay.pizza.pork.ast.NodeVisitor +import gay.pizza.pork.ast.Printer +import gay.pizza.pork.ast.nodes.Program +import gay.pizza.pork.eval.Evaluator +import gay.pizza.pork.eval.Scope +import gay.pizza.pork.parse.* + +abstract class Frontend { + abstract fun createCharSource(): CharSource + + fun tokenize(): TokenStream = + Tokenizer(createCharSource()).tokenize() + + fun parse(): Program = + Parser(TokenStreamSource(tokenize())).readProgram() + + fun highlight(scheme: HighlightScheme): List = + Highlighter(scheme).highlight(tokenize()) + + fun evaluate(scope: Scope = Scope()): Any = + visit(Evaluator(scope)) + + fun reprint(): String = buildString { visit(Printer(this)) } + + fun visit(visitor: NodeVisitor): T = visitor.visit(parse()) +} diff --git a/src/main/kotlin/gay/pizza/pork/parse/PorkParser.kt b/src/main/kotlin/gay/pizza/pork/parse/Parser.kt similarity index 99% rename from src/main/kotlin/gay/pizza/pork/parse/PorkParser.kt rename to src/main/kotlin/gay/pizza/pork/parse/Parser.kt index 1d0d0f1..7cd0338 100644 --- a/src/main/kotlin/gay/pizza/pork/parse/PorkParser.kt +++ b/src/main/kotlin/gay/pizza/pork/parse/Parser.kt @@ -2,7 +2,7 @@ package gay.pizza.pork.parse import gay.pizza.pork.ast.nodes.* -class PorkParser(source: PeekableSource) { +class Parser(source: PeekableSource) { private val unsanitizedSource = source private fun readIntLiteral(): IntLiteral { diff --git a/src/main/kotlin/gay/pizza/pork/parse/PorkTokenizer.kt b/src/main/kotlin/gay/pizza/pork/parse/Tokenizer.kt similarity index 98% rename from src/main/kotlin/gay/pizza/pork/parse/PorkTokenizer.kt rename to src/main/kotlin/gay/pizza/pork/parse/Tokenizer.kt index abc7dca..53ad435 100644 --- a/src/main/kotlin/gay/pizza/pork/parse/PorkTokenizer.kt +++ b/src/main/kotlin/gay/pizza/pork/parse/Tokenizer.kt @@ -1,6 +1,6 @@ package gay.pizza.pork.parse -class PorkTokenizer(val source: CharSource) { +class Tokenizer(val source: CharSource) { private var tokenStart: Int = 0 private fun isSymbol(c: Char): Boolean =