Skip to content
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

[prelude] Parse: readAspect + spaced + readWhile + by-name parsers #843

Merged
merged 2 commits into from
Nov 15, 2024

Conversation

fwbrasil
Copy link
Collaborator

No description provided.

* An Aspect that transforms from Const[Text] to Maybe[(Text, C)]
*/
val readAspect: Aspect[Const[Text], [C] =>> Maybe[(Text, C)], Parse] =
Aspect.init(using Frame.internal)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses #839 to define an aspect with a generic type parameter for the parsed value.

@@ -28,9 +37,9 @@ object Parse:
* @return
* Parsed value if successful, drops the current parse branch if unsuccessful
*/
def read[A, S](f: Text => Maybe[(Text, A)] < S)(using Frame): A < (Parse & S) =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the support for extra S effects in the read function since Aspect needs to know what effects will be used beforehand. It was also unused.

Var.use[State] { state =>
f(state.remaining).map {
readAspect(state.remaining)(f).map {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aspect is applied only to the read function. It enables users to customize the reading behavior for an entire computation like in the new Parse.spaced.

@@ -77,43 +120,162 @@ object Parse:
def anyOf[A, S](seq: (A < (Parse & S))*)(using Frame): A < (Parse & S) =
Choice.eval(seq)(identity)

private def firstOf[A: Flat, S](seq: Seq[() => A < (Parse & S)])(using Frame): A < (Parse & S) =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had issues in a parser I've been working on with recursion generating stack overflows. The issue isn't in the monadic execution but in wiring parsers with circular dependencies via methods that might short circuit execution like firstOf. I've updated the methods to take by-name computations instead and made the version taking Seq private since the usage isn't straightforward with thunks.

*/
def select[A: Flat, S, S2](seq: (A < (Parse & S))*)(f: ((State, A), (State, A)) => Maybe[(State, A)] < S2)(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided to remove Parse.select, Parse.shortest, and Parse.longest. I though I was going to need it but I won't. It's also possible to achieve the same behavior via Parse.attempt.

/** Consumes whitespace characters
*
* @return
* Unit after consuming whitespace
*/
def whitespaces(using Frame): Unit < Parse =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had made a few methods return Unit so users wouldn't need to discard values manually. We're now discarding values in the APIs themselves like in Parse.between and andThen works even for non-Unit computations so it's more ergonomic to return values.


/** Consumes any single character
*
* @return
* The character consumed
*/
def anyChar(using Frame): Char < Parse =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few renamings so it's easier to find parsers via auto complete.

@@ -47,6 +47,246 @@ class ParseTest extends Test:
assert(result == 3)
}
}

"handles recursive parsers" in run {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scenario that reproduces the stack overflow issue I was having.

@fwbrasil
Copy link
Collaborator Author

The build for Scala Native is failing with the same issue as #839 because of the use of Aspect in Parse. I've moved ParseTest to JVM only as a workaround.

@fwbrasil fwbrasil merged commit 719957c into main Nov 15, 2024
3 checks passed
@fwbrasil fwbrasil deleted the parse-spaced branch November 15, 2024 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants