-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using Grammars as Parsers seems to fail. #44
Comments
I'm not sure if you ever figured this out, but I was able to make this work. It does seem that the tokens from the reference grammar aren't being added to the current grammar. I'm not sure if this a proper work around but here is an example: object IPv4Grammar : Grammar<IPv4Address>() {
// Don't actually do this, I haven't figured out how to control look ahead, so this is a hack
val quad by regexToken("25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]")
val dot by literalToken(".")
val qnum by quad map { it.text.toUByte() }
override val rootParser by (quad and skip(dot) and quad and skip(dot) and quad and skip(dot) and quad)
}
object ExampleGrammar : Grammar<IPv4Address>() {
val header by literalToken("ip4:")
// Reference the other grammar here
val ip by IPv4Grammar
// This is the magic. I think you might have to reference all your declared tokens here
override val tokens = listOf(header) + IPv4Grammar.tokens
override val rootParser by skip(header) and ip
} I would assume that since Grammar inherits from Parser that this should work without manually merging tokens, so I'm not sure if this is intended behavior or just a bug. |
Good find @zacharygrafton! I think the "fix" to enable this behavior automatically would then be around here: better-parse/src/commonMain/kotlin/com/github/h0tk3y/betterParse/grammar/Grammar.kt Lines 40 to 53 in 29ed5f2
We would want to add: protected operator fun <T> Grammar<T>.provideDelegate(thisRef: Grammar<*>, property: KProperty<*>): Grammar<T> = this
.also { _tokens.add(it.tokens) }
.also { _parsers.add(it) }
protected operator fun <T> Grammar<T>.getValue(thisRef: Grammar<*>, property: KProperty<*>): Grammar<T> = this This should support using |
The suggested code seems to fix both use cases. I had the first extension function in the fork I was working off of to correct the issue, but I was missing the second extension function. Adding the second function makes my expanded test suite pass. Nice work. |
@zacharygrafton I'm not actually having success with my proposed solution 🤔 Do you have an updated fork with the working tests? |
@dan-lugg Apparently you are correct. I ran This is the fork I have that fixes the way I combine parsers, however, it is still broken in the case of inheritance. I think it has something to do with the token matching priority. Tokens are matched based on the order in which they are added to a grammar. In the inheritance case, all the tokens end up in the same list, but in your original example, the After looking at it further, I'm not sure if this even fixes the example I provided. It passes my test case, but I think that is because the tokens don't really overlap. In the case you provided, every token overlaps since they are shared. We may need to look closer at |
Any news on this? I have script grammar which I separated into two Here is the one using another one called class LogicScriptFileGrammar : Grammar<ScriptedLogic<Civilisation>>() {
private val space by regexToken("\\s+", ignore = true)
private val newLine by literalToken("\n", ignore = true)
private val scriptKeyword by literalToken("logic")
private val scriptName by regexToken("^[a-z_]+")
private val statementParser by ScriptStatementGrammar()
private val scriptHeadParser by -scriptKeyword * scriptName use { ScriptHead(text) }
override val rootParser by (scriptHeadParser * statementParser) map { (scriptHead, statements) ->
ScriptedLogic<Civilisation>(scriptHead.name) { context ->
statements.forEach { statement ->
if (statement.context == "actors") {
if (statement.mutationType == "urge") {
if (statement.mutationTarget == "eat") {
if (statement.mutationOperation == "plus") {
context.actors.forEach {
it.urges.increaseUrge(
statement.mutationTarget,
statement.mutationOperationArgument.toDouble()
)
}
}
}
}
}
}
}
}
internal class ScriptHead(
val name: String
)
} |
I started working on a parser combinator library (implementation heavily influenced from here) to build on / extend the capabilities of this awesomeness, but it's sitting abandoned because life. Really hope @h0tk3y can come back to this again. I'll fork and make some PRs when I have some time. |
Seeing that
Grammar<T>
extendsParser<T>
, I figured I should be able to delegate to aGrammar<T>
, such as:However, it doesn't seem to behave as expected. The following is a small SSCCE to demonstrate:
And the output:
As you can see, the third attempt to parse the grammar-combined input of
A { X, Y, Z }
errors out.InnerTestGrammar
andOuterTestGrammar
, having extended fromTestGrammarBase
can see the shared member tokens/parsers, but seem to get confused (or perhaps I'm confused).Is this not an intended use of
Grammar
?The text was updated successfully, but these errors were encountered: