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

formatter continued 01 #22

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

formatter continued 01 #22

wants to merge 17 commits into from

Conversation

FredTheDino
Copy link
Collaborator

I continued my routine of trying to parse purescript code and fixing what is missing or broken.

During my fixing I added more debug info to the tests and handled crashes more transparently so they'll be easier trouble shooted in the future - the code is a bit ugly but I think it does the jobb.

We also have trouble with infinet loops in the parser - I've found one of them and did something that might or might not be a fix. I check the number of tokens we've eaten and if it stays constant we're stuck and I simply break out of the loop - now this method is not that sophisticated but solved some of the problems I have.

I also noticed we don't check that we've parsed the entire file when we generate our tests, that's something that we should look into if we are striving for correctness.

@@ -363,6 +363,7 @@ fn expr_binding(parser: &mut Parser, separator: SyntaxKind) {
expr_where(parser);
marker.end(parser, SyntaxKind::UnconditionalBinding);
} else {
// NOTE[et]: We get an infinet loop here since `expr_guarded` needs to beable to match an empty expression, so we just abort this loop if we have looped. It's a crude solution but it works to eliminate infinet loops in the parser. This logic lies inside the `one_or_more` parser
Copy link
Owner

Choose a reason for hiding this comment

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

Do you have an example file that can cause this infinite loop?

Copy link
Owner

Choose a reason for hiding this comment

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

A minimum reproduction that I conjured is:

b | if 0 else 1 then 2 = 0

This fails due to how expr_if is defined:

fn expr_if(parser: &mut Parser) {
    let mut marker = parser.start();

    parser.expect(SyntaxKind::IfKw);
    expr_0(parser);

    parser.expect(SyntaxKind::ThenKw);
    expr_0(parser);

    parser.expect(SyntaxKind::ElseKw);
    expr_0(parser);

    marker.end(parser, SyntaxKind::IfThenElseExpression);
}

More specifically, expect is basically eat but it emits an error if it isn't able to consume the current token. The new expect_recover function is more suitable for this, where it eats the current token indiscriminately while also emitting an error node for the CST.

That being said, loop-safety in the parser is definitely something we should strive for; checking if the parser made progress is a good solution, and I think we should also look into "recovering" as much as possible in the parsing rules.

Start { kind: ConstrainedType }
Start { kind: TypeOperatorChain }
Copy link
Owner

Choose a reason for hiding this comment

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

Since => is built-in and cannot be re-defined, I think this should be parsed as ConstrainedType. I haven't implemented desugaring for TypeOperatorChain in the analyzer yet but ConstrainedType and ArrowType should be kept as-is.

@purefunctor
Copy link
Owner

Looks good so far, though I'd advise staying away from the combinators in favor of the new separated/repeat APIs like what #21 is currently doing.

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