mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
parser: rewrite to be able to parse any node type on demand
This commit is contained in:
parent
b42ca92d9f
commit
2307fdc0ed
66
ast/src/main/kotlin/gay/pizza/pork/ast/NodeParser.kt
Normal file
66
ast/src/main/kotlin/gay/pizza/pork/ast/NodeParser.kt
Normal file
@ -0,0 +1,66 @@
|
||||
// GENERATED CODE FROM PORK AST CODEGEN
|
||||
package gay.pizza.pork.ast
|
||||
|
||||
interface NodeParser {
|
||||
fun parseBlock(): Block
|
||||
|
||||
fun parseExpression(): Expression
|
||||
|
||||
fun parseBooleanLiteral(): BooleanLiteral
|
||||
|
||||
fun parseBreak(): Break
|
||||
|
||||
fun parseCompilationUnit(): CompilationUnit
|
||||
|
||||
fun parseContinue(): Continue
|
||||
|
||||
fun parseDeclaration(): Declaration
|
||||
|
||||
fun parseDefinition(): Definition
|
||||
|
||||
fun parseDoubleLiteral(): DoubleLiteral
|
||||
|
||||
fun parseForIn(): ForIn
|
||||
|
||||
fun parseFunctionCall(): FunctionCall
|
||||
|
||||
fun parseFunctionDefinition(): FunctionDefinition
|
||||
|
||||
fun parseIf(): If
|
||||
|
||||
fun parseImportDeclaration(): ImportDeclaration
|
||||
|
||||
fun parseInfixOperation(): InfixOperation
|
||||
|
||||
fun parseIntegerLiteral(): IntegerLiteral
|
||||
|
||||
fun parseLetAssignment(): LetAssignment
|
||||
|
||||
fun parseLetDefinition(): LetDefinition
|
||||
|
||||
fun parseListLiteral(): ListLiteral
|
||||
|
||||
fun parseLongLiteral(): LongLiteral
|
||||
|
||||
fun parseNative(): Native
|
||||
|
||||
fun parseNoneLiteral(): NoneLiteral
|
||||
|
||||
fun parseParentheses(): Parentheses
|
||||
|
||||
fun parsePrefixOperation(): PrefixOperation
|
||||
|
||||
fun parseSetAssignment(): SetAssignment
|
||||
|
||||
fun parseStringLiteral(): StringLiteral
|
||||
|
||||
fun parseSuffixOperation(): SuffixOperation
|
||||
|
||||
fun parseSymbol(): Symbol
|
||||
|
||||
fun parseSymbolReference(): SymbolReference
|
||||
|
||||
fun parseVarAssignment(): VarAssignment
|
||||
|
||||
fun parseWhile(): While
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
// GENERATED CODE FROM PORK AST CODEGEN
|
||||
package gay.pizza.pork.ast
|
||||
|
||||
fun NodeParser.parse(type: NodeType): Node =
|
||||
when (type) {
|
||||
NodeType.Expression -> parseExpression()
|
||||
NodeType.Symbol -> parseSymbol()
|
||||
NodeType.Declaration -> parseDeclaration()
|
||||
NodeType.Definition -> parseDefinition()
|
||||
NodeType.Block -> parseBlock()
|
||||
NodeType.CompilationUnit -> parseCompilationUnit()
|
||||
NodeType.LetAssignment -> parseLetAssignment()
|
||||
NodeType.VarAssignment -> parseVarAssignment()
|
||||
NodeType.SetAssignment -> parseSetAssignment()
|
||||
NodeType.InfixOperation -> parseInfixOperation()
|
||||
NodeType.BooleanLiteral -> parseBooleanLiteral()
|
||||
NodeType.FunctionCall -> parseFunctionCall()
|
||||
NodeType.FunctionDefinition -> parseFunctionDefinition()
|
||||
NodeType.LetDefinition -> parseLetDefinition()
|
||||
NodeType.If -> parseIf()
|
||||
NodeType.ImportDeclaration -> parseImportDeclaration()
|
||||
NodeType.IntegerLiteral -> parseIntegerLiteral()
|
||||
NodeType.LongLiteral -> parseLongLiteral()
|
||||
NodeType.DoubleLiteral -> parseDoubleLiteral()
|
||||
NodeType.ListLiteral -> parseListLiteral()
|
||||
NodeType.Parentheses -> parseParentheses()
|
||||
NodeType.PrefixOperation -> parsePrefixOperation()
|
||||
NodeType.SuffixOperation -> parseSuffixOperation()
|
||||
NodeType.StringLiteral -> parseStringLiteral()
|
||||
NodeType.SymbolReference -> parseSymbolReference()
|
||||
NodeType.While -> parseWhile()
|
||||
NodeType.ForIn -> parseForIn()
|
||||
NodeType.Break -> parseBreak()
|
||||
NodeType.Continue -> parseContinue()
|
||||
NodeType.NoneLiteral -> parseNoneLiteral()
|
||||
NodeType.Native -> parseNative()
|
||||
else -> throw RuntimeException("Unable to automatically parse type: ${type.name}")
|
||||
}
|
@ -20,8 +20,11 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
}
|
||||
writeNodeExtensions()
|
||||
writeNodeType()
|
||||
writeNodeVisitors()
|
||||
writeNodeVisitor()
|
||||
writeNodeCoalescer()
|
||||
writeNodeVisitorExtensions()
|
||||
writeNodeParser()
|
||||
writeNodeParserExtensions()
|
||||
}
|
||||
|
||||
private fun writeNodeType() {
|
||||
@ -46,7 +49,7 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
write("NodeType.kt", KotlinWriter(enumClass))
|
||||
}
|
||||
|
||||
private fun writeNodeVisitors() {
|
||||
private fun writeNodeVisitor() {
|
||||
val nodeVisitorInterface = KotlinClass(
|
||||
pkg,
|
||||
"NodeVisitor",
|
||||
@ -72,7 +75,9 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
nodeVisitorInterface.functions.add(nodeVisitFunction)
|
||||
}
|
||||
write("NodeVisitor.kt", KotlinWriter(nodeVisitorInterface))
|
||||
}
|
||||
|
||||
private fun writeNodeVisitorExtensions() {
|
||||
val visitorExtensionSet = KotlinFunctionSet(pkg)
|
||||
val visitAnyFunction = KotlinFunction(
|
||||
"visit",
|
||||
@ -128,6 +133,63 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
write("NodeVisitorExtensions.kt", KotlinWriter(visitorExtensionSet))
|
||||
}
|
||||
|
||||
private fun writeNodeParserExtensions() {
|
||||
val parserExtensionSet = KotlinFunctionSet(pkg)
|
||||
val parseAnyFunction = KotlinFunction(
|
||||
"parse",
|
||||
extensionOf = "NodeParser",
|
||||
returnType = "Node",
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("type", type = "NodeType")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
|
||||
if (enableVisitAnyInline) {
|
||||
parseAnyFunction.inline = true
|
||||
parseAnyFunction.annotations.add("""@Suppress("NOTHING_TO_INLINE")""")
|
||||
}
|
||||
|
||||
parseAnyFunction.body.add("when (type) {")
|
||||
for (type in world.typeRegistry.types.filter {
|
||||
world.typeRegistry.roleOfType(it) in arrayOf(
|
||||
AstTypeRole.AstNode,
|
||||
AstTypeRole.HierarchyNode
|
||||
)
|
||||
}) {
|
||||
parseAnyFunction.body.add(" NodeType.${type.name} -> parse${type.name}()")
|
||||
}
|
||||
parseAnyFunction.body.add(" else -> throw RuntimeException(\"Unable to automatically parse type: \${type.name}\")")
|
||||
parseAnyFunction.body.add("}")
|
||||
parserExtensionSet.functions.add(parseAnyFunction)
|
||||
write("NodeParserExtensions.kt", KotlinWriter(parserExtensionSet))
|
||||
}
|
||||
|
||||
private fun writeNodeParser() {
|
||||
val nodeParserInterface = KotlinClass(
|
||||
pkg,
|
||||
"NodeParser",
|
||||
isInterface = true
|
||||
)
|
||||
|
||||
for (type in world.typesInDependencyOrder()) {
|
||||
val role = world.typeRegistry.roleOfType(type)
|
||||
|
||||
if (role !in arrayOf(AstTypeRole.AstNode, AstTypeRole.HierarchyNode)) {
|
||||
continue
|
||||
}
|
||||
|
||||
val nodeParseFunction = KotlinFunction(
|
||||
"parse${type.name}",
|
||||
returnType = type.name,
|
||||
parameters = mutableListOf(),
|
||||
isInterfaceMethod = true
|
||||
)
|
||||
nodeParserInterface.functions.add(nodeParseFunction)
|
||||
}
|
||||
write("NodeParser.kt", KotlinWriter(nodeParserInterface))
|
||||
}
|
||||
|
||||
private fun writeNodeCoalescer() {
|
||||
val coalescerClass = KotlinClass(
|
||||
pkg,
|
||||
@ -190,48 +252,7 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
}
|
||||
|
||||
if (role == AstTypeRole.RootNode) {
|
||||
kotlinClassLike.imports.add("kotlinx.serialization.Transient")
|
||||
val typeMember = KotlinMember(
|
||||
"type",
|
||||
"NodeType",
|
||||
abstract = true
|
||||
)
|
||||
kotlinClassLike.members.add(typeMember)
|
||||
val dataMember = KotlinMember(
|
||||
"data",
|
||||
"Any?",
|
||||
value = "null",
|
||||
mutable = true,
|
||||
notInsideConstructor = true,
|
||||
annotations = mutableListOf("@Transient")
|
||||
)
|
||||
kotlinClassLike.members.add(dataMember)
|
||||
|
||||
val abstractVisitChildrenFunction = KotlinFunction(
|
||||
"visitChildren",
|
||||
returnType = "List<T>",
|
||||
open = true,
|
||||
typeParameters = mutableListOf("T"),
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
abstractVisitChildrenFunction.body.add("emptyList()")
|
||||
kotlinClassLike.functions.add(abstractVisitChildrenFunction)
|
||||
|
||||
val abstractVisitSelfFunction = KotlinFunction(
|
||||
"visit",
|
||||
returnType = "T",
|
||||
open = true,
|
||||
typeParameters = mutableListOf("T"),
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
abstractVisitSelfFunction.body.add("visitor.visit(this)")
|
||||
kotlinClassLike.functions.add(abstractVisitSelfFunction)
|
||||
addRootNodeDefinitions(kotlinClassLike)
|
||||
} else if (role == AstTypeRole.AstNode) {
|
||||
val typeMember = KotlinMember(
|
||||
"type",
|
||||
@ -282,111 +303,7 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
}
|
||||
|
||||
if (role == AstTypeRole.AstNode) {
|
||||
val visitChildrenFunction = KotlinFunction(
|
||||
"visitChildren",
|
||||
returnType = "List<T>",
|
||||
typeParameters = mutableListOf("T"),
|
||||
overridden = true,
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
val anyListMembers = type.values?.any {
|
||||
it.typeRef.form == AstTypeRefForm.List
|
||||
} ?: false
|
||||
val elideVisitChildren: Boolean
|
||||
if (anyListMembers) {
|
||||
val visitParameters = (type.values?.mapNotNull {
|
||||
if (it.typeRef.primitive != null) {
|
||||
null
|
||||
} else if (it.typeRef.type != null &&
|
||||
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
||||
null
|
||||
} else if (it.typeRef.form == AstTypeRefForm.Single ||
|
||||
it.typeRef.form == AstTypeRefForm.Nullable) {
|
||||
"listOf(${it.name})"
|
||||
} else {
|
||||
it.name
|
||||
}
|
||||
} ?: emptyList()).joinToString(", ")
|
||||
elideVisitChildren = visitParameters.isEmpty()
|
||||
visitChildrenFunction.body.add("visitor.visitAll(${visitParameters})")
|
||||
} else {
|
||||
val visitParameters = (type.values?.mapNotNull {
|
||||
if (it.typeRef.primitive != null) {
|
||||
null
|
||||
} else if (it.typeRef.type != null &&
|
||||
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
||||
null
|
||||
} else {
|
||||
it.name
|
||||
}
|
||||
} ?: emptyList()).joinToString(", ")
|
||||
elideVisitChildren = visitParameters.isEmpty()
|
||||
visitChildrenFunction.body.add("visitor.visitNodes(${visitParameters})")
|
||||
}
|
||||
|
||||
if (!elideVisitChildren) {
|
||||
kotlinClassLike.functions.add(visitChildrenFunction)
|
||||
}
|
||||
|
||||
val visitSelfFunction = KotlinFunction(
|
||||
"visit",
|
||||
returnType = "T",
|
||||
typeParameters = mutableListOf("T"),
|
||||
overridden = true,
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
visitSelfFunction.body.add("visitor.visit${type.name}(this)")
|
||||
kotlinClassLike.functions.add(visitSelfFunction)
|
||||
|
||||
val equalsAndHashCodeMembers = kotlinClassLike.members.map {
|
||||
it.name
|
||||
}.sortedBy { it == "type" }
|
||||
val equalsFunction = KotlinFunction(
|
||||
"equals",
|
||||
returnType = "Boolean",
|
||||
overridden = true
|
||||
)
|
||||
equalsFunction.parameters.add(KotlinParameter(
|
||||
"other",
|
||||
"Any?"
|
||||
))
|
||||
equalsFunction.body.add("if (other !is ${type.name}) return false")
|
||||
var predicate = equalsAndHashCodeMembers.mapNotNull {
|
||||
if (it == "type") null else "other.${it} == $it"
|
||||
}.joinToString(" && ")
|
||||
if (predicate.isEmpty()) {
|
||||
predicate = "true"
|
||||
}
|
||||
equalsFunction.body.add("return $predicate")
|
||||
kotlinClassLike.functions.add(equalsFunction)
|
||||
|
||||
val hashCodeFunction = KotlinFunction(
|
||||
"hashCode",
|
||||
returnType = "Int",
|
||||
overridden = true
|
||||
)
|
||||
|
||||
if (equalsAndHashCodeMembers.size == 1) {
|
||||
val member = equalsAndHashCodeMembers.single()
|
||||
hashCodeFunction.isImmediateExpression = true
|
||||
hashCodeFunction.body.add("31 * ${member}.hashCode()")
|
||||
} else {
|
||||
for ((index, value) in equalsAndHashCodeMembers.withIndex()) {
|
||||
if (index == 0) {
|
||||
hashCodeFunction.body.add("var result = ${value}.hashCode()")
|
||||
} else {
|
||||
hashCodeFunction.body.add("result = 31 * result + ${value}.hashCode()")
|
||||
}
|
||||
}
|
||||
hashCodeFunction.body.add("return result")
|
||||
}
|
||||
kotlinClassLike.functions.add(hashCodeFunction)
|
||||
addAstNodeDefinitions(type, kotlinClassLike)
|
||||
}
|
||||
|
||||
val serialName = kotlinClassLike.name[0].lowercase() +
|
||||
@ -399,6 +316,159 @@ class AstCodegen(val pkg: String, val outputDirectory: Path, val world: AstWorld
|
||||
write("${type.name}.kt", KotlinWriter(kotlinClassLike))
|
||||
}
|
||||
|
||||
private fun addRootNodeDefinitions(kotlinClassLike: KotlinClassLike) {
|
||||
kotlinClassLike.imports.add("kotlinx.serialization.Transient")
|
||||
val typeMember = KotlinMember(
|
||||
"type",
|
||||
"NodeType",
|
||||
abstract = true
|
||||
)
|
||||
kotlinClassLike.members.add(typeMember)
|
||||
val dataMember = KotlinMember(
|
||||
"data",
|
||||
"Any?",
|
||||
value = "null",
|
||||
mutable = true,
|
||||
notInsideConstructor = true,
|
||||
annotations = mutableListOf("@Transient")
|
||||
)
|
||||
kotlinClassLike.members.add(dataMember)
|
||||
|
||||
val abstractVisitChildrenFunction = KotlinFunction(
|
||||
"visitChildren",
|
||||
returnType = "List<T>",
|
||||
open = true,
|
||||
typeParameters = mutableListOf("T"),
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
abstractVisitChildrenFunction.body.add("emptyList()")
|
||||
kotlinClassLike.functions.add(abstractVisitChildrenFunction)
|
||||
|
||||
val abstractVisitSelfFunction = KotlinFunction(
|
||||
"visit",
|
||||
returnType = "T",
|
||||
open = true,
|
||||
typeParameters = mutableListOf("T"),
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
abstractVisitSelfFunction.body.add("visitor.visit(this)")
|
||||
kotlinClassLike.functions.add(abstractVisitSelfFunction)
|
||||
}
|
||||
|
||||
private fun addAstNodeDefinitions(type: AstType, kotlinClassLike: KotlinClassLike) {
|
||||
val visitChildrenFunction = KotlinFunction(
|
||||
"visitChildren",
|
||||
returnType = "List<T>",
|
||||
typeParameters = mutableListOf("T"),
|
||||
overridden = true,
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
val anyListMembers = type.values?.any {
|
||||
it.typeRef.form == AstTypeRefForm.List
|
||||
} ?: false
|
||||
val elideVisitChildren: Boolean
|
||||
if (anyListMembers) {
|
||||
val visitParameters = (type.values?.mapNotNull {
|
||||
if (it.typeRef.primitive != null) {
|
||||
null
|
||||
} else if (it.typeRef.type != null &&
|
||||
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
||||
null
|
||||
} else if (it.typeRef.form == AstTypeRefForm.Single ||
|
||||
it.typeRef.form == AstTypeRefForm.Nullable) {
|
||||
"listOf(${it.name})"
|
||||
} else {
|
||||
it.name
|
||||
}
|
||||
} ?: emptyList()).joinToString(", ")
|
||||
elideVisitChildren = visitParameters.isEmpty()
|
||||
visitChildrenFunction.body.add("visitor.visitAll(${visitParameters})")
|
||||
} else {
|
||||
val visitParameters = (type.values?.mapNotNull {
|
||||
if (it.typeRef.primitive != null) {
|
||||
null
|
||||
} else if (it.typeRef.type != null &&
|
||||
!world.typeRegistry.roleOfType(it.typeRef.type).isNodeInherited()) {
|
||||
null
|
||||
} else {
|
||||
it.name
|
||||
}
|
||||
} ?: emptyList()).joinToString(", ")
|
||||
elideVisitChildren = visitParameters.isEmpty()
|
||||
visitChildrenFunction.body.add("visitor.visitNodes(${visitParameters})")
|
||||
}
|
||||
|
||||
if (!elideVisitChildren) {
|
||||
kotlinClassLike.functions.add(visitChildrenFunction)
|
||||
}
|
||||
|
||||
val visitSelfFunction = KotlinFunction(
|
||||
"visit",
|
||||
returnType = "T",
|
||||
typeParameters = mutableListOf("T"),
|
||||
overridden = true,
|
||||
parameters = mutableListOf(
|
||||
KotlinParameter("visitor", "NodeVisitor<T>")
|
||||
),
|
||||
isImmediateExpression = true
|
||||
)
|
||||
visitSelfFunction.body.add("visitor.visit${type.name}(this)")
|
||||
kotlinClassLike.functions.add(visitSelfFunction)
|
||||
|
||||
val equalsAndHashCodeMembers = kotlinClassLike.members.map {
|
||||
it.name
|
||||
}.sortedBy { it == "type" }
|
||||
val equalsFunction = KotlinFunction(
|
||||
"equals",
|
||||
returnType = "Boolean",
|
||||
overridden = true
|
||||
)
|
||||
equalsFunction.parameters.add(KotlinParameter(
|
||||
"other",
|
||||
"Any?"
|
||||
))
|
||||
equalsFunction.body.add("if (other !is ${type.name}) return false")
|
||||
var predicate = equalsAndHashCodeMembers.mapNotNull {
|
||||
if (it == "type") null else "other.${it} == $it"
|
||||
}.joinToString(" && ")
|
||||
if (predicate.isEmpty()) {
|
||||
predicate = "true"
|
||||
}
|
||||
equalsFunction.body.add("return $predicate")
|
||||
kotlinClassLike.functions.add(equalsFunction)
|
||||
|
||||
val hashCodeFunction = KotlinFunction(
|
||||
"hashCode",
|
||||
returnType = "Int",
|
||||
overridden = true
|
||||
)
|
||||
|
||||
if (equalsAndHashCodeMembers.size == 1) {
|
||||
val member = equalsAndHashCodeMembers.single()
|
||||
hashCodeFunction.isImmediateExpression = true
|
||||
hashCodeFunction.body.add("31 * ${member}.hashCode()")
|
||||
} else {
|
||||
for ((index, value) in equalsAndHashCodeMembers.withIndex()) {
|
||||
if (index == 0) {
|
||||
hashCodeFunction.body.add("var result = ${value}.hashCode()")
|
||||
} else {
|
||||
hashCodeFunction.body.add("result = 31 * result + ${value}.hashCode()")
|
||||
}
|
||||
}
|
||||
hashCodeFunction.body.add("return result")
|
||||
}
|
||||
kotlinClassLike.functions.add(hashCodeFunction)
|
||||
}
|
||||
|
||||
private fun writeNodeExtensions() {
|
||||
val nodeExtensionSet = KotlinFunctionSet(pkg)
|
||||
val dataFunction = KotlinFunction(
|
||||
|
@ -24,7 +24,7 @@ class World(val importSource: ImportSource) {
|
||||
val tokenizer = Tokenizer(charSource)
|
||||
val tokenStream = tokenizer.tokenize()
|
||||
val parser = Parser(TokenStreamSource(tokenStream), DiscardNodeAttribution)
|
||||
val unit = parser.readCompilationUnit()
|
||||
val unit = parser.parseCompilationUnit()
|
||||
internalUnits[stableKey] = unit
|
||||
return unit
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ abstract class Tool {
|
||||
Tokenizer(createCharSource()).tokenize()
|
||||
|
||||
fun parse(attribution: NodeAttribution = DiscardNodeAttribution): CompilationUnit =
|
||||
Parser(TokenStreamSource(tokenize()), attribution).readCompilationUnit()
|
||||
Parser(TokenStreamSource(tokenize()), attribution).parseCompilationUnit()
|
||||
|
||||
fun highlight(scheme: HighlightScheme): List<Highlight> =
|
||||
Highlighter(scheme).highlight(tokenize())
|
||||
|
@ -2,214 +2,53 @@ package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.*
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
||||
private val unsanitizedSource = source
|
||||
class Parser(source: TokenSource, attribution: NodeAttribution) :
|
||||
ParserBase(source, attribution) {
|
||||
private var storedSymbol: Symbol? = null
|
||||
private var storedDefinitionModifiers: DefinitionModifiers? = null
|
||||
|
||||
private fun readNumberLiteral(): Expression = within {
|
||||
expect(TokenType.NumberLiteral) {
|
||||
if (it.text.contains(".")) {
|
||||
DoubleLiteral(it.text.toDouble())
|
||||
} else {
|
||||
val integer = it.text.toIntOrNull()
|
||||
if (integer != null) {
|
||||
return@expect IntegerLiteral(integer)
|
||||
}
|
||||
val long = it.text.toLongOrNull()
|
||||
if (long != null) {
|
||||
return@expect LongLiteral(long)
|
||||
}
|
||||
throw ParseError("Illegal integer value")
|
||||
}
|
||||
override fun parseBlock(): Block = guarded {
|
||||
expect(TokenType.LeftCurly)
|
||||
val items = collect(TokenType.RightCurly) {
|
||||
parseExpression()
|
||||
}
|
||||
expect(TokenType.RightCurly)
|
||||
Block(items)
|
||||
}
|
||||
|
||||
private fun readStringLiteral(): StringLiteral = within {
|
||||
expect(TokenType.StringLiteral) {
|
||||
val content = StringEscape.unescape(StringEscape.unquote(it.text))
|
||||
StringLiteral(content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readBooleanLiteral(): BooleanLiteral = within {
|
||||
expect(TokenType.True, TokenType.False) {
|
||||
BooleanLiteral(it.type == TokenType.True)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readListLiteral(): ListLiteral = within {
|
||||
expect(TokenType.LeftBracket)
|
||||
val items = collect(TokenType.RightBracket, TokenType.Comma) {
|
||||
readExpression()
|
||||
}
|
||||
expect(TokenType.RightBracket)
|
||||
ListLiteral(items)
|
||||
}
|
||||
|
||||
private fun readLetAssignment(): LetAssignment = within {
|
||||
expect(TokenType.Let)
|
||||
val symbol = readSymbolRaw()
|
||||
expect(TokenType.Equals)
|
||||
val value = readExpression()
|
||||
LetAssignment(symbol, value)
|
||||
}
|
||||
|
||||
private fun readVarAssignment(): VarAssignment = within {
|
||||
expect(TokenType.Var)
|
||||
val symbol = readSymbolRaw()
|
||||
expect(TokenType.Equals)
|
||||
val value = readExpression()
|
||||
VarAssignment(symbol, value)
|
||||
}
|
||||
|
||||
private fun readSymbolRaw(): Symbol = within {
|
||||
expect(TokenType.Symbol) { Symbol(it.text) }
|
||||
}
|
||||
|
||||
private fun readSymbolCases(): Expression = within {
|
||||
val symbol = readSymbolRaw()
|
||||
if (next(TokenType.LeftParentheses)) {
|
||||
val arguments = collect(TokenType.RightParentheses, TokenType.Comma) {
|
||||
readExpression()
|
||||
}
|
||||
expect(TokenType.RightParentheses)
|
||||
FunctionCall(symbol, arguments)
|
||||
} else {
|
||||
val reference = SymbolReference(symbol)
|
||||
if (peek(TokenType.PlusPlus, TokenType.MinusMinus)) {
|
||||
expect(TokenType.PlusPlus, TokenType.MinusMinus) {
|
||||
SuffixOperation(convertSuffixOperator(it), reference)
|
||||
}
|
||||
} else reference
|
||||
}
|
||||
}
|
||||
|
||||
private fun readParentheses(): Parentheses = within {
|
||||
expect(TokenType.LeftParentheses)
|
||||
val expression = readExpression()
|
||||
expect(TokenType.RightParentheses)
|
||||
Parentheses(expression)
|
||||
}
|
||||
|
||||
private fun readPrefixOperation(): PrefixOperation = within {
|
||||
expect(TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde) {
|
||||
PrefixOperation(convertPrefixOperator(it), readExpression())
|
||||
}
|
||||
}
|
||||
|
||||
private fun readIf(): If = within {
|
||||
expect(TokenType.If)
|
||||
val condition = readExpression()
|
||||
val thenBlock = readBlock()
|
||||
var elseBlock: Block? = null
|
||||
if (next(TokenType.Else)) {
|
||||
elseBlock = readBlock()
|
||||
}
|
||||
If(condition, thenBlock, elseBlock)
|
||||
}
|
||||
|
||||
private fun readWhile(): While = within {
|
||||
expect(TokenType.While)
|
||||
val condition = readExpression()
|
||||
val block = readBlock()
|
||||
While(condition, block)
|
||||
}
|
||||
|
||||
private fun readForIn(): ForIn = within {
|
||||
expect(TokenType.For)
|
||||
val symbol = readSymbolRaw()
|
||||
expect(TokenType.In)
|
||||
val value = readExpression()
|
||||
val block = readBlock()
|
||||
ForIn(symbol, value, block)
|
||||
}
|
||||
|
||||
private fun readNative(): Native = within {
|
||||
expect(TokenType.Native)
|
||||
val form = readSymbolRaw()
|
||||
val definition = readStringLiteral()
|
||||
Native(form, definition)
|
||||
}
|
||||
|
||||
fun readExpression(): Expression {
|
||||
override fun parseExpression(): Expression {
|
||||
val token = peek()
|
||||
val expression = when (token.type) {
|
||||
TokenType.NumberLiteral -> {
|
||||
readNumberLiteral()
|
||||
}
|
||||
|
||||
TokenType.StringLiteral -> {
|
||||
readStringLiteral()
|
||||
}
|
||||
|
||||
TokenType.True, TokenType.False -> {
|
||||
readBooleanLiteral()
|
||||
}
|
||||
|
||||
TokenType.LeftBracket -> {
|
||||
readListLiteral()
|
||||
}
|
||||
|
||||
TokenType.Let -> {
|
||||
readLetAssignment()
|
||||
}
|
||||
|
||||
TokenType.Var -> {
|
||||
readVarAssignment()
|
||||
}
|
||||
|
||||
TokenType.Symbol -> {
|
||||
readSymbolCases()
|
||||
}
|
||||
|
||||
TokenType.LeftParentheses -> {
|
||||
readParentheses()
|
||||
}
|
||||
|
||||
TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde -> {
|
||||
readPrefixOperation()
|
||||
}
|
||||
|
||||
TokenType.If -> {
|
||||
readIf()
|
||||
}
|
||||
|
||||
TokenType.While -> {
|
||||
readWhile()
|
||||
}
|
||||
|
||||
TokenType.For -> {
|
||||
readForIn()
|
||||
}
|
||||
|
||||
TokenType.Break -> {
|
||||
expect(TokenType.Break)
|
||||
Break()
|
||||
}
|
||||
|
||||
TokenType.Continue -> {
|
||||
expect(TokenType.Continue)
|
||||
Continue()
|
||||
}
|
||||
|
||||
TokenType.None -> {
|
||||
expect(TokenType.None)
|
||||
NoneLiteral()
|
||||
}
|
||||
TokenType.NumberLiteral -> parseNumberLiteral()
|
||||
TokenType.StringLiteral -> parseStringLiteral()
|
||||
TokenType.True, TokenType.False -> parseBooleanLiteral()
|
||||
TokenType.LeftBracket -> parseListLiteral()
|
||||
TokenType.Let -> parseLetAssignment()
|
||||
TokenType.Var -> parseVarAssignment()
|
||||
TokenType.Symbol -> parseSymbolCases()
|
||||
TokenType.LeftParentheses -> parseParentheses()
|
||||
TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde ->
|
||||
parsePrefixOperation()
|
||||
TokenType.If -> parseIf()
|
||||
TokenType.While -> parseWhile()
|
||||
TokenType.For -> parseForIn()
|
||||
TokenType.Break -> parseBreak()
|
||||
TokenType.Continue -> parseContinue()
|
||||
TokenType.None -> parseNoneLiteral()
|
||||
|
||||
else -> {
|
||||
throw ParseError(
|
||||
throw gay.pizza.pork.parser.ParseError(
|
||||
"Failed to parse token: ${token.type} '${token.text}' as" +
|
||||
" expression (index ${unsanitizedSource.currentIndex})"
|
||||
" expression (index ${source.currentIndex})"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (expression is SymbolReference && peek(TokenType.Equals)) {
|
||||
return within {
|
||||
return guarded {
|
||||
attribution.adopt(expression)
|
||||
expect(TokenType.Equals)
|
||||
val value = readExpression()
|
||||
val value = parseExpression()
|
||||
SetAssignment(expression.symbol, value)
|
||||
}
|
||||
}
|
||||
@ -234,31 +73,57 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
||||
TokenType.Or
|
||||
)
|
||||
) {
|
||||
within {
|
||||
guarded {
|
||||
val infixToken = next()
|
||||
val infixOperator = convertInfixOperator(infixToken)
|
||||
InfixOperation(expression, infixOperator, readExpression())
|
||||
val infixOperator = ParserHelpers.convertInfixOperator(infixToken)
|
||||
InfixOperation(expression, infixOperator, parseExpression())
|
||||
}
|
||||
} else expression
|
||||
}
|
||||
|
||||
private fun readBlock(): Block = within {
|
||||
expect(TokenType.LeftCurly)
|
||||
val items = collect(TokenType.RightCurly) {
|
||||
readExpression()
|
||||
override fun parseBooleanLiteral(): BooleanLiteral = guarded {
|
||||
if (next(TokenType.True)) {
|
||||
BooleanLiteral(true)
|
||||
} else if (next(TokenType.False)) {
|
||||
BooleanLiteral(false)
|
||||
} else {
|
||||
throw ParseError("Expected ")
|
||||
}
|
||||
expect(TokenType.RightCurly)
|
||||
Block(items)
|
||||
}
|
||||
|
||||
private fun readImportDeclaration(): ImportDeclaration = within {
|
||||
expect(TokenType.Import)
|
||||
val form = readSymbolRaw()
|
||||
val components = oneAndContinuedBy(TokenType.Dot) { readSymbolRaw() }
|
||||
ImportDeclaration(form, components)
|
||||
override fun parseBreak(): Break = guarded {
|
||||
expect(TokenType.Break)
|
||||
Break()
|
||||
}
|
||||
|
||||
private fun readDefinitionModifiers(): DefinitionModifiers {
|
||||
override fun parseCompilationUnit(): CompilationUnit = guarded {
|
||||
val declarations = mutableListOf<Declaration>()
|
||||
val definitions = mutableListOf<Definition>()
|
||||
var declarationAccepted = true
|
||||
|
||||
while (!peek(TokenType.EndOfFile)) {
|
||||
if (declarationAccepted) {
|
||||
val definition = maybeParseDefinition()
|
||||
if (definition != null) {
|
||||
declarationAccepted = false
|
||||
definitions.add(definition)
|
||||
continue
|
||||
}
|
||||
declarations.add(parseDeclaration())
|
||||
} else {
|
||||
definitions.add(parseDefinition())
|
||||
}
|
||||
}
|
||||
|
||||
CompilationUnit(declarations, definitions)
|
||||
}
|
||||
|
||||
override fun parseContinue(): Continue = guarded {
|
||||
expect(TokenType.Continue)
|
||||
Continue()
|
||||
}
|
||||
|
||||
private fun parseDefinitionModifiers(): DefinitionModifiers {
|
||||
val modifiers = DefinitionModifiers(export = false)
|
||||
while (true) {
|
||||
val token = peek()
|
||||
@ -273,12 +138,68 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
||||
return modifiers
|
||||
}
|
||||
|
||||
private fun readFunctionDeclaration(modifiers: DefinitionModifiers): FunctionDefinition = within {
|
||||
fun maybeParseDefinition(): Definition? {
|
||||
try {
|
||||
storedDefinitionModifiers = parseDefinitionModifiers()
|
||||
val token = peek()
|
||||
return when (token.type) {
|
||||
TokenType.Func -> parseFunctionDefinition()
|
||||
TokenType.Let -> parseLetDefinition()
|
||||
else -> null
|
||||
}
|
||||
} finally {
|
||||
storedDefinitionModifiers = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseDeclaration(): Declaration {
|
||||
val token = peek()
|
||||
return when (token.type) {
|
||||
TokenType.Import -> parseImportDeclaration()
|
||||
else -> throw gay.pizza.pork.parser.ParseError(
|
||||
"Failed to parse token: ${token.type} '${token.text}' as" +
|
||||
" declaration (index ${source.currentIndex})"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseDefinition(): Definition {
|
||||
return maybeParseDefinition() ?: throw ParseError("Unable to parse definition")
|
||||
}
|
||||
|
||||
override fun parseDoubleLiteral(): DoubleLiteral = guarded {
|
||||
DoubleLiteral(expect(TokenType.NumberLiteral).text.toDouble())
|
||||
}
|
||||
|
||||
override fun parseForIn(): ForIn = guarded {
|
||||
expect(TokenType.For)
|
||||
val symbol = parseSymbol()
|
||||
expect(TokenType.In)
|
||||
val value = parseExpression()
|
||||
val block = parseBlock()
|
||||
ForIn(symbol, value, block)
|
||||
}
|
||||
|
||||
override fun parseFunctionCall(): FunctionCall = guarded {
|
||||
parseFunctionCall(null)
|
||||
}
|
||||
|
||||
fun parseFunctionCall(target: Symbol?): FunctionCall = guarded {
|
||||
val symbol = target ?: parseSymbol()
|
||||
val arguments = collect(TokenType.RightParentheses, TokenType.Comma) {
|
||||
parseExpression()
|
||||
}
|
||||
expect(TokenType.RightParentheses)
|
||||
FunctionCall(symbol, arguments)
|
||||
}
|
||||
|
||||
override fun parseFunctionDefinition(): FunctionDefinition = guarded {
|
||||
val modifiers = storedDefinitionModifiers ?: parseDefinitionModifiers()
|
||||
expect(TokenType.Func)
|
||||
val name = readSymbolRaw()
|
||||
val name = parseSymbol()
|
||||
expect(TokenType.LeftParentheses)
|
||||
val arguments = collect(TokenType.RightParentheses, TokenType.Comma) {
|
||||
val symbol = readSymbolRaw()
|
||||
val symbol = parseSymbol()
|
||||
var multiple = false
|
||||
if (next(TokenType.DotDotDot)) {
|
||||
multiple = true
|
||||
@ -290,194 +211,167 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
|
||||
var native: Native? = null
|
||||
var block: Block? = null
|
||||
if (peek(TokenType.Native)) {
|
||||
native = readNative()
|
||||
native = parseNative()
|
||||
} else {
|
||||
block = readBlock()
|
||||
block = parseBlock()
|
||||
}
|
||||
FunctionDefinition(modifiers, name, arguments, block, native)
|
||||
}
|
||||
|
||||
private fun readLetDefinition(modifiers: DefinitionModifiers): LetDefinition = within {
|
||||
override fun parseIf(): If = guarded {
|
||||
expect(TokenType.If)
|
||||
val condition = parseExpression()
|
||||
val thenBlock = parseBlock()
|
||||
var elseBlock: Block? = null
|
||||
if (next(TokenType.Else)) {
|
||||
elseBlock = parseBlock()
|
||||
}
|
||||
If(condition, thenBlock, elseBlock)
|
||||
}
|
||||
|
||||
override fun parseImportDeclaration(): ImportDeclaration = guarded {
|
||||
expect(TokenType.Import)
|
||||
val form = parseSymbol()
|
||||
val components = oneAndContinuedBy(TokenType.Dot) {
|
||||
parseSymbol()
|
||||
}
|
||||
ImportDeclaration(form, components)
|
||||
}
|
||||
|
||||
override fun parseInfixOperation(): InfixOperation = guarded {
|
||||
val infixToken = next()
|
||||
val infixOperator = ParserHelpers.convertInfixOperator(infixToken)
|
||||
InfixOperation(parseExpression(), infixOperator, parseExpression())
|
||||
}
|
||||
|
||||
private fun parseNumberLiteral(): Expression = guarded {
|
||||
val token = peek()
|
||||
if (token.type != TokenType.NumberLiteral) {
|
||||
expect(TokenType.NumberLiteral)
|
||||
}
|
||||
|
||||
when {
|
||||
token.text.contains(".") -> parseDoubleLiteral()
|
||||
token.text.toIntOrNull() != null -> parseIntegerLiteral()
|
||||
token.text.toLongOrNull() != null -> parseLongLiteral()
|
||||
else -> throw ParseError("Invalid numeric literal")
|
||||
}
|
||||
}
|
||||
|
||||
override fun parseIntegerLiteral(): IntegerLiteral = guarded {
|
||||
IntegerLiteral(expect(TokenType.NumberLiteral).text.toInt())
|
||||
}
|
||||
|
||||
override fun parseLetAssignment(): LetAssignment = guarded {
|
||||
expect(TokenType.Let)
|
||||
val name = readSymbolRaw()
|
||||
val symbol = parseSymbol()
|
||||
expect(TokenType.Equals)
|
||||
val value = readExpression()
|
||||
LetDefinition(modifiers, name, value)
|
||||
val value = parseExpression()
|
||||
LetAssignment(symbol, value)
|
||||
}
|
||||
|
||||
private fun maybeReadDefinition(): Definition? {
|
||||
val modifiers = readDefinitionModifiers()
|
||||
val token = peek()
|
||||
return when (token.type) {
|
||||
TokenType.Func -> readFunctionDeclaration(modifiers)
|
||||
TokenType.Let -> readLetDefinition(modifiers)
|
||||
else -> null
|
||||
override fun parseLetDefinition(): LetDefinition = guarded {
|
||||
val definitionModifiers = storedDefinitionModifiers ?: parseDefinitionModifiers()
|
||||
expect(TokenType.Let)
|
||||
val name = parseSymbol()
|
||||
expect(TokenType.Equals)
|
||||
val value = parseExpression()
|
||||
LetDefinition(definitionModifiers, name, value)
|
||||
}
|
||||
|
||||
override fun parseListLiteral(): ListLiteral = guarded {
|
||||
expect(TokenType.LeftBracket)
|
||||
val items = collect(TokenType.RightBracket, TokenType.Comma) {
|
||||
parseExpression()
|
||||
}
|
||||
expect(TokenType.RightBracket)
|
||||
ListLiteral(items)
|
||||
}
|
||||
|
||||
override fun parseLongLiteral(): LongLiteral = guarded {
|
||||
LongLiteral(expect(TokenType.NumberLiteral).text.toLong())
|
||||
}
|
||||
|
||||
override fun parseNative(): Native = guarded {
|
||||
expect(TokenType.Native)
|
||||
val form = parseSymbol()
|
||||
val definition = parseStringLiteral()
|
||||
Native(form, definition)
|
||||
}
|
||||
|
||||
override fun parseNoneLiteral(): NoneLiteral = guarded {
|
||||
expect(TokenType.None)
|
||||
NoneLiteral()
|
||||
}
|
||||
|
||||
override fun parseParentheses(): Parentheses = guarded {
|
||||
expect(TokenType.LeftParentheses)
|
||||
val expression = parseExpression()
|
||||
expect(TokenType.RightParentheses)
|
||||
Parentheses(expression)
|
||||
}
|
||||
|
||||
override fun parsePrefixOperation(): PrefixOperation = guarded {
|
||||
expect(TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde) {
|
||||
PrefixOperation(ParserHelpers.convertPrefixOperator(it), parseExpression())
|
||||
}
|
||||
}
|
||||
|
||||
private fun readDefinition(): Definition {
|
||||
val definition = maybeReadDefinition()
|
||||
if (definition != null) {
|
||||
return definition
|
||||
}
|
||||
val token = peek()
|
||||
throw ParseError(
|
||||
"Failed to parse token: ${token.type} '${token.text}' as" +
|
||||
" definition (index ${unsanitizedSource.currentIndex})"
|
||||
)
|
||||
override fun parseSetAssignment(): SetAssignment = guarded {
|
||||
val symbol = storedSymbol ?: parseSymbol()
|
||||
expect(TokenType.Equals)
|
||||
val value = parseExpression()
|
||||
SetAssignment(symbol, value)
|
||||
}
|
||||
|
||||
fun readDeclaration(): Declaration {
|
||||
val token = peek()
|
||||
return when (token.type) {
|
||||
TokenType.Import -> readImportDeclaration()
|
||||
else -> throw ParseError(
|
||||
"Failed to parse token: ${token.type} '${token.text}' as" +
|
||||
" declaration (index ${unsanitizedSource.currentIndex})"
|
||||
)
|
||||
override fun parseStringLiteral(): StringLiteral = guarded {
|
||||
expect(TokenType.StringLiteral) {
|
||||
val content = StringEscape.unescape(StringEscape.unquote(it.text))
|
||||
StringLiteral(content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertInfixOperator(token: Token): InfixOperator = when (token.type) {
|
||||
TokenType.Plus -> InfixOperator.Plus
|
||||
TokenType.Minus -> InfixOperator.Minus
|
||||
TokenType.Multiply -> InfixOperator.Multiply
|
||||
TokenType.Divide -> InfixOperator.Divide
|
||||
TokenType.Ampersand -> InfixOperator.BinaryAnd
|
||||
TokenType.Pipe -> InfixOperator.BinaryOr
|
||||
TokenType.Caret -> InfixOperator.BinaryExclusiveOr
|
||||
TokenType.Equality -> InfixOperator.Equals
|
||||
TokenType.Inequality -> InfixOperator.NotEquals
|
||||
TokenType.Mod -> InfixOperator.EuclideanModulo
|
||||
TokenType.Rem -> InfixOperator.Remainder
|
||||
TokenType.Lesser -> InfixOperator.Lesser
|
||||
TokenType.Greater -> InfixOperator.Greater
|
||||
TokenType.LesserEqual -> InfixOperator.LesserEqual
|
||||
TokenType.GreaterEqual -> InfixOperator.GreaterEqual
|
||||
TokenType.And -> InfixOperator.BooleanAnd
|
||||
TokenType.Or -> InfixOperator.BooleanOr
|
||||
else -> throw ParseError("Unknown Infix Operator")
|
||||
override fun parseSuffixOperation(): SuffixOperation = guarded {
|
||||
val reference = parseSymbolReference()
|
||||
expect(TokenType.PlusPlus, TokenType.MinusMinus) {
|
||||
SuffixOperation(ParserHelpers.convertSuffixOperator(it), reference)
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertPrefixOperator(token: Token): PrefixOperator = when (token.type) {
|
||||
TokenType.Not -> PrefixOperator.BooleanNot
|
||||
TokenType.Plus -> PrefixOperator.UnaryPlus
|
||||
TokenType.Minus -> PrefixOperator.UnaryMinus
|
||||
TokenType.Tilde -> PrefixOperator.BinaryNot
|
||||
else -> throw ParseError("Unknown Prefix Operator")
|
||||
}
|
||||
|
||||
private fun convertSuffixOperator(token: Token): SuffixOperator = when (token.type) {
|
||||
TokenType.PlusPlus -> SuffixOperator.Increment
|
||||
TokenType.MinusMinus -> SuffixOperator.Decrement
|
||||
else -> throw ParseError("Unknown Suffix Operator")
|
||||
}
|
||||
|
||||
fun readCompilationUnit(): CompilationUnit = within {
|
||||
val declarations = mutableListOf<Declaration>()
|
||||
val definitions = mutableListOf<Definition>()
|
||||
var declarationAccepted = true
|
||||
|
||||
while (!peek(TokenType.EndOfFile)) {
|
||||
if (declarationAccepted) {
|
||||
val definition = maybeReadDefinition()
|
||||
if (definition != null) {
|
||||
declarationAccepted = false
|
||||
definitions.add(definition)
|
||||
continue
|
||||
private fun parseSymbolCases(): Expression = guarded {
|
||||
val symbol = parseSymbol()
|
||||
if (next(TokenType.LeftParentheses)) {
|
||||
parseFunctionCall(symbol)
|
||||
} else {
|
||||
val reference = SymbolReference(symbol)
|
||||
if (peek(TokenType.PlusPlus, TokenType.MinusMinus)) {
|
||||
expect(TokenType.PlusPlus, TokenType.MinusMinus) {
|
||||
SuffixOperation(ParserHelpers.convertSuffixOperator(it), reference)
|
||||
}
|
||||
declarations.add(readDeclaration())
|
||||
} else {
|
||||
definitions.add(readDefinition())
|
||||
}
|
||||
}
|
||||
|
||||
CompilationUnit(declarations, definitions)
|
||||
}
|
||||
|
||||
private fun <T> collect(
|
||||
peeking: TokenType,
|
||||
consuming: TokenType? = null,
|
||||
read: () -> T
|
||||
): List<T> {
|
||||
val items = mutableListOf<T>()
|
||||
while (!peek(peeking)) {
|
||||
val item = read()
|
||||
if (consuming != null) {
|
||||
if (!peek(peeking)) {
|
||||
expect(consuming)
|
||||
}
|
||||
}
|
||||
items.add(item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
private fun <T> oneAndContinuedBy(separator: TokenType, read: () -> T): List<T> {
|
||||
val items = mutableListOf<T>()
|
||||
items.add(read())
|
||||
while (peek(separator)) {
|
||||
expect(separator)
|
||||
items.add(read())
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
private fun peek(vararg types: TokenType): Boolean {
|
||||
val token = peek()
|
||||
return types.contains(token.type)
|
||||
}
|
||||
|
||||
private fun next(type: TokenType): Boolean {
|
||||
return if (peek(type)) {
|
||||
expect(type)
|
||||
true
|
||||
} else false
|
||||
}
|
||||
|
||||
private fun expect(vararg types: TokenType): Token {
|
||||
val token = next()
|
||||
if (!types.contains(token.type)) {
|
||||
throw ParseError(
|
||||
"Expected one of ${types.joinToString(", ")}" +
|
||||
" but got type ${token.type} '${token.text}'"
|
||||
)
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
private fun <T: Node> expect(vararg types: TokenType, consume: (Token) -> T): T =
|
||||
consume(expect(*types))
|
||||
|
||||
private fun next(): Token {
|
||||
while (true) {
|
||||
val token = unsanitizedSource.next()
|
||||
attribution.push(token)
|
||||
if (ignoredByParser(token.type)) {
|
||||
continue
|
||||
}
|
||||
return token
|
||||
} else reference
|
||||
}
|
||||
}
|
||||
|
||||
private fun peek(): Token {
|
||||
while (true) {
|
||||
val token = unsanitizedSource.peek()
|
||||
if (ignoredByParser(token.type)) {
|
||||
attribution.push(token)
|
||||
unsanitizedSource.next()
|
||||
continue
|
||||
}
|
||||
return token
|
||||
}
|
||||
override fun parseSymbol(): Symbol = guarded {
|
||||
expect(TokenType.Symbol) { Symbol(it.text) }
|
||||
}
|
||||
|
||||
fun <T: Node> within(block: () -> T): T = attribution.guarded(block)
|
||||
override fun parseSymbolReference(): SymbolReference = guarded {
|
||||
SymbolReference(parseSymbol())
|
||||
}
|
||||
|
||||
private fun ignoredByParser(type: TokenType): Boolean = when (type) {
|
||||
TokenType.BlockComment -> true
|
||||
TokenType.LineComment -> true
|
||||
TokenType.Whitespace -> true
|
||||
else -> false
|
||||
override fun parseVarAssignment(): VarAssignment = guarded {
|
||||
expect(TokenType.Var)
|
||||
val symbol = parseSymbol()
|
||||
expect(TokenType.Equals)
|
||||
val value = parseExpression()
|
||||
VarAssignment(symbol, value)
|
||||
}
|
||||
|
||||
override fun parseWhile(): While = guarded {
|
||||
expect(TokenType.While)
|
||||
val condition = parseExpression()
|
||||
val block = parseBlock()
|
||||
While(condition, block)
|
||||
}
|
||||
}
|
||||
|
94
parser/src/main/kotlin/gay/pizza/pork/parser/ParserBase.kt
Normal file
94
parser/src/main/kotlin/gay/pizza/pork/parser/ParserBase.kt
Normal file
@ -0,0 +1,94 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.ast.NodeParser
|
||||
|
||||
abstract class ParserBase(val source: TokenSource, val attribution: NodeAttribution) : NodeParser {
|
||||
open class ParseError(error: String) : RuntimeException(error)
|
||||
|
||||
class ExpectedTokenError(got: Token, vararg expectedTypes: TokenType) : ParseError(
|
||||
"Expected one of ${expectedTypes.joinToString(", ")}" +
|
||||
" but got type ${got.type} '${got.text}'"
|
||||
)
|
||||
|
||||
protected fun <T: Node> guarded(block: () -> T): T = attribution.guarded(block)
|
||||
|
||||
protected fun <T> collect(
|
||||
peeking: TokenType,
|
||||
consuming: TokenType? = null,
|
||||
read: () -> T
|
||||
): List<T> {
|
||||
val items = mutableListOf<T>()
|
||||
while (!peek(peeking)) {
|
||||
val item = read()
|
||||
if (consuming != null) {
|
||||
if (!peek(peeking)) {
|
||||
expect(consuming)
|
||||
}
|
||||
}
|
||||
items.add(item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
protected fun <T> oneAndContinuedBy(separator: TokenType, read: () -> T): List<T> {
|
||||
val items = mutableListOf<T>()
|
||||
items.add(read())
|
||||
while (peek(separator)) {
|
||||
expect(separator)
|
||||
items.add(read())
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
protected fun peek(vararg types: TokenType): Boolean {
|
||||
val token = peek()
|
||||
return types.contains(token.type)
|
||||
}
|
||||
|
||||
protected fun next(type: TokenType): Boolean {
|
||||
return if (peek(type)) {
|
||||
expect(type)
|
||||
true
|
||||
} else false
|
||||
}
|
||||
|
||||
protected fun expect(vararg types: TokenType): Token {
|
||||
val token = next()
|
||||
if (!types.contains(token.type)) {
|
||||
throw ExpectedTokenError(token, *types)
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
protected fun <T: Node> expect(vararg types: TokenType, consume: (Token) -> T): T =
|
||||
consume(expect(*types))
|
||||
|
||||
protected fun next(): Token {
|
||||
while (true) {
|
||||
val token = source.next()
|
||||
if (ignoredByParser(token.type)) {
|
||||
continue
|
||||
}
|
||||
return token
|
||||
}
|
||||
}
|
||||
|
||||
protected fun peek(): Token {
|
||||
while (true) {
|
||||
val token = source.peek()
|
||||
if (ignoredByParser(token.type)) {
|
||||
source.next()
|
||||
continue
|
||||
}
|
||||
return token
|
||||
}
|
||||
}
|
||||
|
||||
private fun ignoredByParser(type: TokenType): Boolean = when (type) {
|
||||
TokenType.BlockComment -> true
|
||||
TokenType.LineComment -> true
|
||||
TokenType.Whitespace -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package gay.pizza.pork.parser
|
||||
|
||||
import gay.pizza.pork.ast.InfixOperator
|
||||
import gay.pizza.pork.ast.PrefixOperator
|
||||
import gay.pizza.pork.ast.SuffixOperator
|
||||
|
||||
internal object ParserHelpers {
|
||||
fun convertInfixOperator(token: Token): InfixOperator = when (token.type) {
|
||||
TokenType.Plus -> InfixOperator.Plus
|
||||
TokenType.Minus -> InfixOperator.Minus
|
||||
TokenType.Multiply -> InfixOperator.Multiply
|
||||
TokenType.Divide -> InfixOperator.Divide
|
||||
TokenType.Ampersand -> InfixOperator.BinaryAnd
|
||||
TokenType.Pipe -> InfixOperator.BinaryOr
|
||||
TokenType.Caret -> InfixOperator.BinaryExclusiveOr
|
||||
TokenType.Equality -> InfixOperator.Equals
|
||||
TokenType.Inequality -> InfixOperator.NotEquals
|
||||
TokenType.Mod -> InfixOperator.EuclideanModulo
|
||||
TokenType.Rem -> InfixOperator.Remainder
|
||||
TokenType.Lesser -> InfixOperator.Lesser
|
||||
TokenType.Greater -> InfixOperator.Greater
|
||||
TokenType.LesserEqual -> InfixOperator.LesserEqual
|
||||
TokenType.GreaterEqual -> InfixOperator.GreaterEqual
|
||||
TokenType.And -> InfixOperator.BooleanAnd
|
||||
TokenType.Or -> InfixOperator.BooleanOr
|
||||
else -> throw ParserBase.ParseError("Unknown Infix Operator")
|
||||
}
|
||||
|
||||
fun convertPrefixOperator(token: Token): PrefixOperator = when (token.type) {
|
||||
TokenType.Not -> PrefixOperator.BooleanNot
|
||||
TokenType.Plus -> PrefixOperator.UnaryPlus
|
||||
TokenType.Minus -> PrefixOperator.UnaryMinus
|
||||
TokenType.Tilde -> PrefixOperator.BinaryNot
|
||||
else -> throw ParserBase.ParseError("Unknown Prefix Operator")
|
||||
}
|
||||
|
||||
fun convertSuffixOperator(token: Token): SuffixOperator = when (token.type) {
|
||||
TokenType.PlusPlus -> SuffixOperator.Increment
|
||||
TokenType.MinusMinus -> SuffixOperator.Decrement
|
||||
else -> throw ParserBase.ParseError("Unknown Suffix Operator")
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ class PorkParser : PsiParser {
|
||||
val source = PsiBuilderTokenSource(builder)
|
||||
val parser = Parser(source, psiBuilderMarkAttribution)
|
||||
try {
|
||||
parser.within { parser.readCompilationUnit() }
|
||||
parser.parseCompilationUnit()
|
||||
} catch (_: ExitParser) {}
|
||||
return builder.treeBuilt
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user