mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
build: move parser and tokenizer into separate modules
This commit is contained in:
parent
9338b01b48
commit
15f5f313cc
@ -2,9 +2,9 @@ package gay.pizza.pork.ffi
|
||||
|
||||
import gay.pizza.pork.ast.gen.visit
|
||||
import gay.pizza.pork.frontend.ContentSource
|
||||
import gay.pizza.pork.parser.CharSource
|
||||
import gay.pizza.pork.tokenizer.CharSource
|
||||
import gay.pizza.pork.parser.Printer
|
||||
import gay.pizza.pork.parser.StringCharSource
|
||||
import gay.pizza.pork.tokenizer.StringCharSource
|
||||
|
||||
object JavaAutogenContentSource : ContentSource {
|
||||
override fun loadAsCharSource(path: String): CharSource {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package gay.pizza.pork.frontend
|
||||
|
||||
import gay.pizza.pork.parser.CharSource
|
||||
import gay.pizza.pork.tokenizer.CharSource
|
||||
|
||||
interface ContentSource {
|
||||
fun loadAsCharSource(path: String): CharSource
|
||||
|
@ -3,8 +3,8 @@ 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.StringCharSource
|
||||
import gay.pizza.pork.tokenizer.CharSource
|
||||
import gay.pizza.pork.tokenizer.StringCharSource
|
||||
|
||||
class FsContentSource(val root: FsPath) : ContentSource {
|
||||
override fun loadAsCharSource(path: String): CharSource =
|
||||
|
@ -4,7 +4,7 @@ import gay.pizza.pork.ast.gen.CompilationUnit
|
||||
import gay.pizza.pork.ast.gen.ImportDeclaration
|
||||
import gay.pizza.pork.parser.DiscardNodeAttribution
|
||||
import gay.pizza.pork.parser.Parser
|
||||
import gay.pizza.pork.parser.Tokenizer
|
||||
import gay.pizza.pork.tokenizer.Tokenizer
|
||||
|
||||
class World(val importSource: ImportSource) {
|
||||
private val internalUnits = mutableMapOf<String, CompilationUnit>()
|
||||
|
@ -4,8 +4,8 @@ import gay.pizza.dough.fs.FsPath
|
||||
import gay.pizza.dough.fs.readString
|
||||
import gay.pizza.pork.frontend.ContentSource
|
||||
import gay.pizza.pork.frontend.FsContentSource
|
||||
import gay.pizza.pork.parser.CharSource
|
||||
import gay.pizza.pork.parser.StringCharSource
|
||||
import gay.pizza.pork.tokenizer.CharSource
|
||||
import gay.pizza.pork.tokenizer.StringCharSource
|
||||
|
||||
class FileTool(val path: FsPath) : Tool() {
|
||||
override fun createCharSource(): CharSource =
|
||||
|
@ -13,6 +13,7 @@ import gay.pizza.pork.frontend.DynamicImportSource
|
||||
import gay.pizza.pork.frontend.World
|
||||
import gay.pizza.pork.parser.*
|
||||
import gay.pizza.pork.stdlib.PorkStdlib
|
||||
import gay.pizza.pork.tokenizer.*
|
||||
|
||||
abstract class Tool {
|
||||
abstract fun createCharSource(): CharSource
|
||||
|
@ -4,6 +4,7 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
api(project(":ast"))
|
||||
api(project(":tokenizer"))
|
||||
|
||||
implementation(project(":common"))
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
class BadCharacterError(val char: Char, sourceIndex: SourceIndex, state: TokenizerState) : ParseError(
|
||||
"Failed to produce token for '${char}' at $sourceIndex in state $state"
|
||||
)
|
@ -2,6 +2,7 @@ package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.gen.Node
|
||||
import gay.pizza.pork.ast.gen.NodeType
|
||||
import gay.pizza.pork.tokenizer.Token
|
||||
|
||||
object DiscardNodeAttribution : NodeAttribution {
|
||||
override fun push(token: Token) {}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.tokenizer.Token
|
||||
import gay.pizza.pork.tokenizer.TokenSource
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
class LazySkippingTokenSource(val source: TokenSource, val skipping: Set<TokenType>) : ParserAwareTokenSource {
|
||||
private var index = 0
|
||||
override val currentIndex: Int
|
||||
|
@ -2,6 +2,7 @@ package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.gen.Node
|
||||
import gay.pizza.pork.ast.gen.NodeType
|
||||
import gay.pizza.pork.tokenizer.Token
|
||||
|
||||
interface NodeAttribution {
|
||||
fun push(token: Token)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.gen.*
|
||||
import gay.pizza.pork.tokenizer.TokenSource
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
ParserBase(source, attribution) {
|
||||
|
@ -4,6 +4,7 @@ import gay.pizza.pork.ast.gen.Node
|
||||
import gay.pizza.pork.ast.gen.NodeCoalescer
|
||||
import gay.pizza.pork.ast.gen.data
|
||||
import gay.pizza.pork.ast.gen.visit
|
||||
import gay.pizza.pork.tokenizer.Token
|
||||
|
||||
data class ParserAttributes(val tokens: List<Token>) {
|
||||
companion object {
|
||||
|
@ -1,3 +1,5 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.tokenizer.TokenSource
|
||||
|
||||
interface ParserAwareTokenSource : TokenSource
|
||||
|
@ -3,6 +3,7 @@ package gay.pizza.pork.parser
|
||||
import gay.pizza.pork.ast.gen.Node
|
||||
import gay.pizza.pork.ast.gen.NodeParser
|
||||
import gay.pizza.pork.ast.gen.NodeType
|
||||
import gay.pizza.pork.tokenizer.*
|
||||
|
||||
abstract class ParserBase(source: TokenSource, val attribution: NodeAttribution) : NodeParser {
|
||||
val source: TokenSource = if (source is ParserAwareTokenSource) {
|
||||
|
@ -3,6 +3,8 @@ package gay.pizza.pork.parser
|
||||
import gay.pizza.pork.ast.gen.InfixOperator
|
||||
import gay.pizza.pork.ast.gen.PrefixOperator
|
||||
import gay.pizza.pork.ast.gen.SuffixOperator
|
||||
import gay.pizza.pork.tokenizer.Token
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
internal object ParserHelpers {
|
||||
fun convertInfixOperator(token: Token): InfixOperator = when (token.type) {
|
||||
|
@ -3,6 +3,7 @@ package gay.pizza.pork.parser
|
||||
import gay.pizza.pork.ast.gen.Node
|
||||
import gay.pizza.pork.ast.gen.NodeType
|
||||
import gay.pizza.pork.ast.gen.data
|
||||
import gay.pizza.pork.tokenizer.Token
|
||||
|
||||
open class ParserNodeAttribution : NodeAttribution {
|
||||
private val stack = mutableListOf<MutableList<Token>>()
|
||||
|
@ -4,6 +4,7 @@ includeBuild("buildext")
|
||||
|
||||
include(
|
||||
":common",
|
||||
":tokenizer",
|
||||
":ast",
|
||||
":parser",
|
||||
":frontend",
|
||||
|
@ -1,8 +1,8 @@
|
||||
package gay.pizza.pork.stdlib
|
||||
|
||||
import gay.pizza.pork.frontend.ContentSource
|
||||
import gay.pizza.pork.parser.CharSource
|
||||
import gay.pizza.pork.parser.StringCharSource
|
||||
import gay.pizza.pork.tokenizer.CharSource
|
||||
import gay.pizza.pork.tokenizer.StringCharSource
|
||||
|
||||
object PorkStdlib : ContentSource {
|
||||
private val stdlibClass = PorkStdlib::class.java
|
||||
|
@ -4,7 +4,7 @@ import com.intellij.lang.BracePair
|
||||
import com.intellij.lang.PairedBraceMatcher
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
class PorkBraceMatcher : PairedBraceMatcher {
|
||||
override fun getPairs(): Array<BracePair> = arrayOf(
|
||||
|
@ -3,7 +3,7 @@ package gay.pizza.pork.idea
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import gay.pizza.pork.ast.gen.NodeType
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
object PorkElementTypes {
|
||||
private val tokenTypeToElementType = mutableMapOf<TokenType, IElementType>()
|
||||
|
@ -3,10 +3,10 @@ package gay.pizza.pork.idea
|
||||
import com.intellij.lexer.LexerBase
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import gay.pizza.pork.parser.BadCharacterError
|
||||
import gay.pizza.pork.parser.StringCharSource
|
||||
import gay.pizza.pork.parser.Tokenizer
|
||||
import gay.pizza.pork.parser.UnterminatedTokenError
|
||||
import gay.pizza.pork.tokenizer.BadCharacterError
|
||||
import gay.pizza.pork.tokenizer.StringCharSource
|
||||
import gay.pizza.pork.tokenizer.Tokenizer
|
||||
import gay.pizza.pork.tokenizer.UnterminatedTokenError
|
||||
import com.intellij.psi.TokenType as PsiTokenType
|
||||
|
||||
class PorkLexer : LexerBase() {
|
||||
|
@ -11,7 +11,7 @@ import com.intellij.psi.util.elementsAtOffsetUp
|
||||
import gay.pizza.pork.idea.psi.gen.ArgumentSpecElement
|
||||
import gay.pizza.pork.idea.psi.gen.FunctionCallElement
|
||||
import gay.pizza.pork.idea.psi.gen.FunctionDefinitionElement
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class PorkParameterInfoHandler : ParameterInfoHandler<FunctionCallElement, FunctionDefinitionElement> {
|
||||
|
@ -11,7 +11,7 @@ import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.tree.IFileElementType
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import gay.pizza.pork.idea.psi.gen.PorkElementFactory
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
class PorkParserDefinition : ParserDefinition {
|
||||
val fileElementType = IFileElementType(PorkLanguage)
|
||||
|
@ -6,8 +6,8 @@ import com.intellij.openapi.editor.colors.TextAttributesKey
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import gay.pizza.pork.parser.TokenFamily
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
import gay.pizza.pork.tokenizer.TokenFamily
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
object PorkSyntaxHighlighter : SyntaxHighlighter {
|
||||
override fun getHighlightingLexer(): Lexer {
|
||||
|
@ -1,7 +1,10 @@
|
||||
package gay.pizza.pork.idea
|
||||
|
||||
import com.intellij.lang.PsiBuilder
|
||||
import gay.pizza.pork.parser.*
|
||||
import gay.pizza.pork.parser.ParserAwareTokenSource
|
||||
import gay.pizza.pork.tokenizer.SourceIndex
|
||||
import gay.pizza.pork.tokenizer.Token
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
import com.intellij.psi.TokenType as PsiTokenType
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
|
7
tokenizer/build.gradle.kts
Normal file
7
tokenizer/build.gradle.kts
Normal file
@ -0,0 +1,7 @@
|
||||
plugins {
|
||||
id("gay.pizza.pork.module")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
open class AnsiHighlightScheme : HighlightScheme {
|
||||
override fun highlight(token: Token): Highlight {
|
@ -0,0 +1,5 @@
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class BadCharacterError(char: Char, sourceIndex: SourceIndex, state: TokenizerState) : TokenizeError(
|
||||
"Failed to produce token for '${char}' at $sourceIndex in state $state"
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
interface CharConsumer {
|
||||
fun consume(type: TokenType, tokenizer: Tokenizer): String?
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
fun interface CharMatcher {
|
||||
fun valid(char: Char, index: Int): Boolean
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
interface CharSource : PeekableSource<Char> {
|
||||
fun peek(index: Int): Char
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
fun CharSource.readToString(): String = buildString {
|
||||
while (peek() != CharSource.EndOfFile) {
|
@ -1,6 +1,6 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class ExpectedTokenError(got: Token, sourceIndex: SourceIndex, vararg expectedTypes: TokenType) : ParseError(
|
||||
class ExpectedTokenError(got: Token, sourceIndex: SourceIndex, vararg expectedTypes: TokenType) : TokenizeError(
|
||||
message(got, sourceIndex, expectedTypes)
|
||||
) {
|
||||
companion object {
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class Highlight(val token: Token, val text: String? = null) {
|
||||
override fun toString(): String = text ?: token.text
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
interface HighlightScheme {
|
||||
fun highlight(token: Token): Highlight
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class Highlighter(val scheme: HighlightScheme) {
|
||||
fun highlight(stream: TokenStream): List<Highlight> =
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
@Suppress("CanBeParameter")
|
||||
class MatchedCharConsumer(
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
interface PeekableSource<T> {
|
||||
val currentIndex: Int
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
data class SourceIndex(val index: Int, val line: Int, val column: Int, val locationReliable: Boolean = true) {
|
||||
companion object {
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class SourceIndexCharSource(val delegate: CharSource) : CharSource by delegate {
|
||||
private var currentLineIndex = 1
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
object StringCharConsumer : CharConsumer {
|
||||
override fun consume(type: TokenType, tokenizer: Tokenizer): String {
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class StringCharSource(
|
||||
val input: CharSequence,
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class Token(val type: TokenType, val sourceIndex: SourceIndex, val text: String) {
|
||||
override fun toString(): String =
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
enum class TokenFamily : TokenTypeProperty {
|
||||
OperatorFamily,
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
interface TokenSource : PeekableSource<Token> {
|
||||
fun peekTypeAhead(ahead: Int): TokenType
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class TokenStream(val tokens: List<Token>) {
|
||||
override fun toString(): String = tokens.toString()
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class TokenStreamSource(val stream: TokenStream) : TokenSource {
|
||||
private var index = 0
|
@ -1,10 +1,10 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
import gay.pizza.pork.parser.CharMatcher.*
|
||||
import gay.pizza.pork.parser.MatchedCharConsumer.Options.AllowEofTermination
|
||||
import gay.pizza.pork.parser.TokenTypeProperty.*
|
||||
import gay.pizza.pork.parser.TokenFamily.*
|
||||
import gay.pizza.pork.parser.TokenTypeProperty.AnyOf
|
||||
import gay.pizza.pork.tokenizer.CharMatcher.*
|
||||
import gay.pizza.pork.tokenizer.MatchedCharConsumer.Options.AllowEofTermination
|
||||
import gay.pizza.pork.tokenizer.TokenTypeProperty.*
|
||||
import gay.pizza.pork.tokenizer.TokenFamily.*
|
||||
import gay.pizza.pork.tokenizer.TokenTypeProperty.AnyOf
|
||||
|
||||
enum class TokenType(vararg val properties: TokenTypeProperty) {
|
||||
NumberLiteral(NumericLiteralFamily, CharMatch(CharMatcher.AnyOf(
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
interface TokenTypeProperty {
|
||||
class SingleChar(val char: Char) : TokenTypeProperty
|
@ -0,0 +1,3 @@
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
abstract class TokenizeError(message: String) : RuntimeException(message)
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class Tokenizer(source: CharSource) : TokenSource {
|
||||
internal val source = SourceIndexCharSource(source)
|
@ -1,4 +1,4 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
enum class TokenizerState(vararg val transitions: Transition) {
|
||||
Normal(Transition({ TokenType.Quote }) { StringLiteralStart }),
|
@ -1,5 +1,5 @@
|
||||
package gay.pizza.pork.parser
|
||||
package gay.pizza.pork.tokenizer
|
||||
|
||||
class UnterminatedTokenError(what: String, sourceIndex: SourceIndex) : ParseError(
|
||||
class UnterminatedTokenError(what: String, sourceIndex: SourceIndex) : TokenizeError(
|
||||
"Unterminated $what at $sourceIndex"
|
||||
)
|
@ -7,7 +7,7 @@ import gay.pizza.dough.fs.PlatformFsProvider
|
||||
import gay.pizza.dough.fs.createDirectories
|
||||
import gay.pizza.dough.fs.exists
|
||||
import gay.pizza.dough.fs.writeString
|
||||
import gay.pizza.pork.parser.readToString
|
||||
import gay.pizza.pork.tokenizer.readToString
|
||||
import gay.pizza.pork.stdlib.PorkStdlib
|
||||
|
||||
class CopyStdlibCommand : CliktCommand(help = "Copy Stdlib", name = "copy-stdlib") {
|
||||
|
@ -4,7 +4,7 @@ import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||
import gay.pizza.dough.fs.PlatformFsProvider
|
||||
import gay.pizza.pork.minimal.FileTool
|
||||
import gay.pizza.pork.parser.AnsiHighlightScheme
|
||||
import gay.pizza.pork.tokenizer.AnsiHighlightScheme
|
||||
|
||||
class HighlightCommand : CliktCommand(help = "Syntax Highlighter", name = "highlight") {
|
||||
val path by argument("file")
|
||||
|
@ -4,7 +4,7 @@ import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||
import gay.pizza.dough.fs.PlatformFsProvider
|
||||
import gay.pizza.pork.minimal.FileTool
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
import gay.pizza.pork.tokenizer.TokenType
|
||||
|
||||
class TokenizeCommand : CliktCommand(help = "Tokenize Compilation Unit", name = "tokenize") {
|
||||
val path by argument("file")
|
||||
|
Loading…
Reference in New Issue
Block a user