better-parse
better-parse copied to clipboard
ClassCastException when combining a Tuple2 parser
Hello,
The following code :
val typePrefix by (type * -znws * parser(this::referenceParser) * -znws * -assign)
// ...
val traitFunction by parser(this::functionSignature) use { CyanTraitDeclaration.Element.Function(CyanFunctionDeclaration(this, null), span) }
val traitProperty by structProperty use { CyanTraitDeclaration.Element.Property(ident, type, span) }
val traitElement by (traitFunction or traitProperty)
val traitDeclaration by (typePrefix * -znws * -trait * -znws * -lcur * -znws * (separatedTerms(traitElement, newLine)
.use { toTypedArray() }) * -znws * -rcur) use { CyanTraitDeclaration(t2, t3, span(t1, t3.last())) }
Yields the following exception :
com.github.h0tk3y.betterParse.utils.Tuple2 cannot be cast to com.github.h0tk3y.betterParse.lexer.TokenMatch
java.lang.ClassCastException: com.github.h0tk3y.betterParse.utils.Tuple2 cannot be cast to com.github.h0tk3y.betterParse.lexer.TokenMatch
at cyan.compiler.parser.CyanModuleParser$$special$$inlined$and2Operator$2.invoke(andFunctions.kt:9)
at cyan.compiler.parser.CyanModuleParser$$special$$inlined$and2Operator$2.invoke(andFunctions.kt)
at com.github.h0tk3y.betterParse.combinators.AndCombinator.tryParse(AndCombinator.kt:60)
at com.github.h0tk3y.betterParse.combinators.MapCombinator.tryParse(MapCombinator.kt:14)
at com.github.h0tk3y.betterParse.combinators.OrCombinator.tryParse(OrCombinator.kt:13)
at com.github.h0tk3y.betterParse.combinators.AndCombinator.tryParse(AndCombinator.kt:40)
at com.github.h0tk3y.betterParse.combinators.AndCombinator.tryParse(AndCombinator.kt:40)
at com.github.h0tk3y.betterParse.combinators.SeparatedCombinator.tryParse(Separated.kt:16)
at com.github.h0tk3y.betterParse.combinators.MapCombinator.tryParse(MapCombinator.kt:14)
at com.github.h0tk3y.betterParse.combinators.MapCombinator.tryParse(MapCombinator.kt:14)
at com.github.h0tk3y.betterParse.combinators.AndCombinator.tryParse(AndCombinator.kt:40)
at com.github.h0tk3y.betterParse.combinators.MapCombinator.tryParse(MapCombinator.kt:14)
at com.github.h0tk3y.betterParse.parser.ParserKt.tryParseToEnd(Parser.kt:18)
at com.github.h0tk3y.betterParse.parser.ParserKt.parseToEnd(Parser.kt:29)
at com.github.h0tk3y.betterParse.grammar.GrammarKt.parseToEnd(Grammar.kt:65)
at cyan.compiler.parser.StatementsTest.doTest(StatementsTest.kt:29)
at cyan.compiler.parser.StatementsTest.access$doTest(StatementsTest.kt:24)
at cyan.compiler.parser.StatementsTest$TypeDeclarations.trait with one function(StatementsTest.kt:34)
<...>
From a quick look into the code, it seems like in andFunctions.kt
this is function is called for the first * operator in typePrefix * -znws * -trait
:
@JvmName("and2") inline infix fun <reified T1, reified T2, reified T3>
AndCombinator<Tuple2<T1, T2>>.and(p3: Parser<T3>) =
AndCombinator(consumers + p3, {
Tuple3(it[0] as T1, it[1] as T2, it[2] as T3)
})
But looking at the debugger, I see values packed into a tuple and not "flat mapped" (don't know if that makess sense, couldn't think of a better way to put it) :
Here, t1
of element 0 (which is the result of typePrefix
) is the match for token type
, and t2
is from parser(this::referenceParser)
. Yet, the code thinks t1
is element 0, and t2
is element 1, while they are in fact both inside element 0. This obviously causes a ClassCastException
when it tries to cast element 0
into what I assume reified type parameter T1
is (TokenMatch
).
I couldn't figure out which part of the library laid out those elements like that, which is where I'm stuck.
I hope this all made sense, and thanks in advance.
@Benjozork did you manage to solve this for Cyan? I've run into exactly the same problem, on a much smaller grammar
I think the issue is that the SkipParser
throws away type information, so the reified types don't propagate, and for some reason Kotlin doesn't complain.
public class SkipParser(public val innerParser: Parser<*>)
Can't this be made generic?
Hey, it's been a long time since I worked on cyan and I think I just reshuffled the parser a bit to where it wasn't causing an issue and forgot about it. Sorry I don't have a more useful solution 😬