-
Notifications
You must be signed in to change notification settings - Fork 59
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
Conversation
* 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) |
There was a problem hiding this comment.
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) = |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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) = |
There was a problem hiding this comment.
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)( |
There was a problem hiding this comment.
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 = |
There was a problem hiding this comment.
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 = |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
The build for Scala Native is failing with the same issue as #839 because of the use of |
No description provided.