-
Notifications
You must be signed in to change notification settings - Fork 419
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
[WIP] Support parsing @_package
attribute
#1233
base: main
Are you sure you want to change the base?
Conversation
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 implementation looks good to me overall. I’ve got a few comments inline.
|
||
func testPackageAttribute() { | ||
AssertParse(#"@_package(path: "../my-package") import A"#) | ||
AssertParse(#"@_package(url: "https://example.com/package.git", from: "0.0.1") @_exported import A"#) |
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.
Do you think you could also add a few test cases for invalid Swift code? Ideas that come to my mind are
- misspelled argument labels
- missing commas or colons
- Using identifiers instead of string literals
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 didn't care of diagnostics for now, so some false syntax may be accepted by the current implementation. The error messages also seemed not helpful at all...
Anyway I'll do that some time. Thanks for your suggestion:)
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 adds some more valid test cases and I believe the parsing is robust enough now. It's time to dive into diagnostics...
Sources/SwiftParser/Attributes.swift
Outdated
(unexpectedBeforeRequirementLabel, requirementLabel) = (nil, nil) | ||
(unexpectedBeforeRequirementColon, requirementColon) = (nil, nil) | ||
} | ||
requirement = self.parseExpression() |
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.
Shouldn’t this also be in the if let label
branch?
Open question:
Do we want to allow arbitrary expressions here? If we only want to allow e.g. "1.1.0"
or "1.1.0"..<"1.2.0"
it might make sense to create a new syntax node for that kind of version requirement.
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.
Well, the current syntax handles requirement like this:
- If the given location is a
path
, there should be no requirement; otherwise we always have one. - If the label is
from
orexact
, it accepts a semantic version in string literal; - If the label is
branch
, it accepts a branch name in string literal; - If the label is
revision
, it accepts a commit hash in string literal. - If there's no label, it accepts either a range expression (eg.
"1.0.0"..<"1.1.0"
) or a member access expression (eg..upToNextMinor(from: "1.0.0")
).
I haven't decided if we want to simplify the interface (making it less like PackageDescription
), so we're now accepting arbitrary expressions here.
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.
Since this is only a draft, there're plenty of rooms for refactors, like:
- Extracting the logic of
@_package
into a separate file like@available
does; - Implementing fully semantical parsing logic including expression diagnostic and even semantics versioning;
- Introducing additional node types for package attribute;
- Consuming all parameters at a whole (just like a tuple) and implementing semantical error handling.
WDYT?
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.
- Extracting the logic of
@_package
into a separate file like@available
does;
I don’t think starting a new file makes sense for ~100 LOC. If things grow further,
- Implementing fully semantical parsing logic including expression diagnostic and even semantics versioning
What do you mean by “fully semantic parsing logic including expression diagnostics”.
- Introducing additional node types for package attribute;
There’s always a trade-off here between expressibility and trying to keep the syntax tree simple. The main consideration would be if there are invariants in the syntax tree that clients might care about but which are not expressed in the syntax tree at the moment (e.g. if two options are mutually exclusive). I don’t see anything like that at the moment, so maybe it’s fine as-is.
- Consuming all parameters at a whole (just like a tuple) and implementing semantical error handling.
My gut feeling is that we’ll save ourselves trouble by implementing as much as reasonably possible in the parser. We get a lot of diagnostics for free in the parser and whatever client consumes these nodes doesn’t need to worry about them. Also, eventually we might get automatic code completion based on the keywords in the syntax tree.
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.
Now I've refactored the support and it grows to ~120 loc. Parser implementation should look better with new nodes added.
After checking PackageDescription
source, I found that wildcard requirement was deprecated in SwiftPM 5.6, so for a new feature it makes sense to drop the support. This means although the node is a plain Expr
at the time, we can further assert it to be a range expression ( semantic-version-low ( '..<' | '...' ) semantic-version-high
).
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.
If we just allow semantic-version-low ( '..<' | '...' ) semantic-version-high
, I think it would make sense to represent the version requirement in the syntax tree as three nodes VersionTuple
, BinaryOperator
and VersionTuple
.
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.
VersionTuple
doesn't fully mimic a semantic version (which is rather complex and better handed over to other tools). I’m going to use StringLiteralExpr
instead. Thanks for your suggestions on BinaryOperator
, but I didn’t have idea on how to diagnose wrong operator here🤔 Should that be handled elsewhere?
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.
Handling the semantic version somewhere else sounds good to me. The binary operator could be anything. There isn’t any way to restrict the kinds of operators we allow in the SwiftSyntax tree.
f579c5c
to
310c9b8
Compare
93bc170
to
f6057d6
Compare
91aaff8
to
af2977a
Compare
This is a very, very early (partial) demo implementation of SwiftPM support for Swift scripts, which expects feedback from both the compiler &
SwiftSyntax
team as I'm new to implement a compiler-related feature.