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

Enabling scoping mechanism #35

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

Enabling scoping mechanism #35

wants to merge 13 commits into from

Conversation

npenin
Copy link

@npenin npenin commented Mar 16, 2021

Hi seb,

One more pull request that allows scoped parsers (that required an adaptation to the parsercontext). That allows registering variable declarations in a block statement before actually waiting for the parser to complete

@sebastienros
Copy link
Owner

Not opposed to it. Right now the solution is to pass a custom instance inheriting from ParserContext and cast it in a Then() call. See https://github.com/sebastienros/fluid/blob/main/Fluid/FluidParser.cs#L193

@npenin
Copy link
Author

npenin commented Mar 17, 2021

Maybe I missed something, but I see 1 major problem with this: how do you handle nested scopes ? the approach I suggested is most likely not the best, but it at least helps solving this problem which sounds like a common use case for parsers.

splitted ParseContext and ParseContext.Untyped
@lahma
Copy link
Collaborator

lahma commented Mar 20, 2021

Generic TParseContext will also probably open possibility to use struct type by restricting to new IParseContext interface and consumers like Fluid can use their own type.

@npenin
Copy link
Author

npenin commented Mar 22, 2021

The other "small" change I made is to make an IParser interface for better variance/covariance (I never remember which one is which) support which, does not work well with classes.

@sebastienros
Copy link
Owner

@npenin That's great! I had to remove the interfaces at some point because it was preventing me from doing some Fluent things in places. I had an IParser and all classes had to implement it, but it would make them have to return an object and that was a pain.

for better variance/covariance

Had a quick look and I couldn't find that. Ideally IParser<T> should be castable to IParser<object>. That would allow to remove some Then<> calls to have all parsers in a sequence to return the same exact type.

Can you split this PR in two, one with the Scoped parser and one with the interfaces? I want to deal with the changes independently.

@npenin
Copy link
Author

npenin commented Mar 24, 2021

Unfortunately, I don't think so. If I split it, it will have to still contain all my changes for the typed parsercontext, otherwise, that would be a completely different implementation.

Regarding the variance/covariance, there is a flaw in .NET that would prevent from casting a Task<IList> to Task<IEnumerable> because Task is a class and variance/covariance only works with interfaces (and delegates ?).

@sebastienros
Copy link
Owner

Now that I have merged compilation I will be able to focus on your PRs.

@npenin
Copy link
Author

npenin commented Apr 30, 2021

it took me quite some time to get it compile again after your compilation changes. I hope I will not have to do it again ;)

/// </summary>
/// <typeparam name="T">The input parser type.</typeparam>
/// <typeparam name="TParseContext">The parse context type.</typeparam>
public sealed class Then<T, TParseContext> : Parser<T, TParseContext>, ICompilable<TParseContext>
Copy link
Owner

Choose a reason for hiding this comment

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

That's a new one right?
I assume to just be able to pass an action that can change the context only?

Copy link
Author

Choose a reason for hiding this comment

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

indeed

@sebastienros
Copy link
Owner

Ran the benchmarks, slower by 10%.

@npenin
Copy link
Author

npenin commented May 1, 2021

do you know where exactly or is it just a general slowness ?

@sebastienros
Copy link
Owner

Global regression due to interface dispatch, @lahma ?

@sebastienros
Copy link
Owner

Though if there is no possibility of using a "common" IParser interface or using co-variance, then why not just remove all interfaces like it was before and only keep the Parser<T, TParseContext> part?

@lahma
Copy link
Collaborator

lahma commented May 2, 2021

Global regression due to interface dispatch, @lahma ?

That would be my guess. Interface dispatch is a lot more costly than regular virtual member call.

@npenin
Copy link
Author

npenin commented May 2, 2021

Indeed, I removed the interface and earned back the 10%.

@sebastienros
Copy link
Owner

https://twitter.com/badamczewski01/status/1390390252435611654

@sebastienros
Copy link
Owner

The new SkipWhiteSpace parser needs to be updated

@@ -5,22 +5,31 @@

namespace Parlot.Fluent
{
public abstract partial class Parser<T>
public partial class Parsers
Copy link
Owner

Choose a reason for hiding this comment

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

Like there is public static class ParserExtensions for TryParse it should be a ParserExtensions for Compile. Maybe both as partial classes.


namespace Parlot.Fluent
{
public partial class ParseContext
Copy link
Owner

Choose a reason for hiding this comment

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

I don't understand why it should be part of the library. This PR allows to change the type of ParseContext, so any project could then create their own, and have one that takes a dictionary if they need, or custom properties.

Copy link
Author

Choose a reason for hiding this comment

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

indeed, I just thought having an example and the possiblity to use such a parser straight ahead would be the right thing to do. but I agree with you

src/Parlot/Fluent/ParseContext.Scoped.cs Outdated Show resolved Hide resolved
@@ -32,7 +32,7 @@ public ParseContext(Scanner scanner, bool useNewLines = false)
/// <summary>
/// The parser that is used to parse whitespaces and comments.
/// </summary>
public Parser<TextSpan> WhiteSpaceParser { get; set;}
public Parser<TextSpan, ParseContext> WhiteSpaceParser { get; set; }
Copy link
Owner

Choose a reason for hiding this comment

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

This looks like it could now be in a custom ParseContext that deals with char, since it doesn't make sense for byte based parsers. Then the Literals or Terms based parsers could use this new context type, to drive the other parsers generic type. There would then be a new set of binary parsers with another corresponding type.

Or maybe it's a Scanner concern too.

Copy link
Author

Choose a reason for hiding this comment

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

I think you mixed this comment with my other PR. BTW, it is done as such in my other PR (see StringParseContext).

@npenin
Copy link
Author

npenin commented Oct 5, 2021

@sebastienros up ?

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.

3 participants