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

Add require node(s) to the parse tree #4210

Open
wants to merge 6 commits into
base: trunk
Choose a base branch
from

Conversation

gysddn
Copy link
Contributor

@gysddn gysddn commented Aug 9, 2024

Added new nodes to the parse tree to handle require declarations

Require is a new bracketed parse node with the following structure:

Require
-Impls (New node for expr impls expr statements)
- AnyExpr
- AnyExpr
-RequireIntroducer (Bracket node)

Two test cases added for the usage in the interfaces.

Added new nodes to the parse tree to handle require declarations

`Require` is a new bracketed parse node with the following structure:

Require
  -Impls (New node for `expr impls expr` statement)
    - AnyExpr
    - AnyExpr
  -RequireIntroducer (Bracket node)

Two test cases added for the usage in the interfaces.
Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

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

@josh11b I'm trying to figure out how to review this. Looking at the generics design, I see examples of its use, but I'm having trouble finding what the full syntax is. Is the syntax in the design somewhere that I'm missing? Some of the examples include where, does this overlap with the where parsing you've been looking at?

@gysddn FYI, the items on Toolchain tasks are things that are closer to our development focus. I'm going to need some time to figure out what the syntax is intended to be before I can really review, but I've left some comments regarding testing since those are more general comments not specific to this change. It's important to be testing both success cases and failure cases.

Comment on lines 15 to 17
interface Bar {
require i32 impls Foo;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add tests of incorrect syntax? There are a lot of possible typos here, and we should make sure error handling is working.

Just as a few examples:

// Missing components.
require;
require impls Foo;
require i32;
require i32 impls;

// Extra expressions.
require i32 i32 impls Foo;
require i32 impls Foo Foo;

Plus, what happens when there's a missing semicolon?

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like you've added most of these, but is there a test case with a missing semicolon?

e.g.:

interface Foo {
  require i32 impls Bar
}

I expect this to work fine, but having tests is important to both catch unexpected results and prevent regressions.

@josh11b
Copy link
Contributor

josh11b commented Aug 9, 2024

@josh11b I'm trying to figure out how to review this. Looking at the generics design, I see examples of its use, but I'm having trouble finding what the full syntax is. Is the syntax in the design somewhere that I'm missing? Some of the examples include where, does this overlap with the where parsing you've been looking at?

The argument to require is supposed to match the argument to where, which I recently was working on -- see #4075 . The arguments are described in https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#where-constraints -- though the description is spread out across that whole section, without a short summary of just the syntax.

One thing to note, though, that in discussions we've decided that the argument to a where clause is not an expression, and so it has its own distinct interpretation of symbols like == that appear in ordinary expressions.

@jonmeow
Copy link
Contributor

jonmeow commented Aug 15, 2024

The argument to require is supposed to match the argument to where, which I recently was working on -- see #4075 . The arguments are described in https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#where-constraints -- though the description is spread out across that whole section, without a short summary of just the syntax.

So to be sure I understand correctly, require actually has a single argument, and that argument is the same as an argument to where? i.e., the impls just happens to be in all the examples?

(if that understanding is correct, probably this change should be reverted since josh11b is already working on where syntax, and this change isn't going to provide the right support)

@josh11b
Copy link
Contributor

josh11b commented Aug 15, 2024

The argument to require is supposed to match the argument to where, which I recently was working on -- see #4075 . The arguments are described in https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#where-constraints -- though the description is spread out across that whole section, without a short summary of just the syntax.

So to be sure I understand correctly, require actually has a single argument, and that argument is the same as an argument to where? i.e., the impls just happens to be in all the examples?

(if that understanding is correct, probably this change should be reverted since josh11b is already working on where syntax, and this change isn't going to provide the right support)

https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2760.md#proposal

For now, only the impls forms of where clauses are permitted after require.

Eventually my expectation is that we would accept any kind of where clause after require when parsing, and then add restrictions in the check stage; but for now it is totally fine to only accept impls after require in parse.

@gysddn
Copy link
Contributor Author

gysddn commented Aug 16, 2024

So to be sure I understand correctly, require actually has a single argument, and that argument is the same as an argument to where? i.e., the impls just happens to be in all the examples?

Yeah, I didn't really realize this while making these changes.
If the syntax will be provided by @josh11b changes, then I can update this PR or just make another one.

@jonmeow
Copy link
Contributor

jonmeow commented Aug 16, 2024

To be sure we're all on the same page:

  1. Josh is fine with the basic syntax support being added.
    • That is, require <expr> impls <expr>;.
  2. Per my comments, edge cases and incorrect syntax must be tested.
    • The parse tree must be balanced even for parse trees that contain error nodes.

- Merge tests into one file
- Add more cases to cover incorrect syntax
- Make `Require` node to be a fixed children size type
(.child_count = 2) instead of bracketed.
Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

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

Thanks! I think the behavior looks good.

I'm suggesting changes to the state.def comments in order to try and match the file's style better. If I'm misreading something there, please let me know.

auto state = context.PopState();

if (auto impls = context.ConsumeIf(Lex::TokenKind::Impls)) {
// context.AddNode(NodeKind::ImplsTypeAs, *impls, state.has_error);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// context.AddNode(NodeKind::ImplsTypeAs, *impls, state.has_error);

Was this leftover from work? Should it be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh yeah, sorry about that 😅

Comment on lines 313 to 317
// require ...
// ^~~~~~~
// 1. Require
// 2. DeclScopeLoop
//
Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at surrounding entries, we're adding them lexically (alias, base, choice, etc). Can you please match that style, placing after package?

//
CARBON_PARSE_STATE(Impls)

// Finishes impls processing
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Finishes impls processing
// Finishes `impls` processing.
//

As above. Also, fix punctuation.

CARBON_PARSE_STATE(Require)

// Handles the processing of `impls` in a `require` declaration after the type
// expression.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// expression.
// expression.
//

Similar to other comments, let's put a blank line separating comment from example.


CARBON_PARSE_STATE(ImplsFinish)

// Finishes `require` processing
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Finishes `require` processing
// Finishes `require` processing.
//

As above.

// 1. Expr
// 2. Impls
// 3. RequireFinish
//
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
//

We typically don't put blank lines at the end of a comment block.

Comment on lines 761 to 766
// impls ...
// ^~~~~
//
// 1. Expr
// 2. ImplsFinish
//
Copy link
Contributor

Choose a reason for hiding this comment

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

The syntax you're documenting here is for the error case, but you have it for the expression case. Let's document both paths.

Also note this suggestion is fixing extra blank lines.

Suggested change
// impls ...
// ^~~~~
//
// 1. Expr
// 2. ImplsFinish
//
// expr impls ...
// ^~~~~
// 1. Expr
// 2. ImplsFinish
//
// expr ???
// ^
// (state done)

Comment on lines 770 to 771
// impls type_expression ...
// ^
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// impls type_expression ...
// ^
// expr impls expr
// ^

Let's include the expr before impls here.

// ^
// (state done)
//

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

Comment on lines 770 to 773
// impls type_expression ...
// ^
// (state done)
//
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// impls type_expression ...
// ^
// (state done)
//
// expr impls expr
// ^
// (state done)

Similar to impls, I think the syntax example can be more specific. When there is no following syntax handled, we omit the trailing "...". Also, since parsing only checks for an expression, let's only say "expr".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated the comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants