-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Convert ParseNode to struct #1534
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1534 +/- ##
==========================================
- Coverage 84.14% 84.11% -0.03%
==========================================
Files 79 79
Lines 4565 4558 -7
Branches 803 803
==========================================
- Hits 3841 3834 -7
Misses 629 629
Partials 95 95
Continue to review full report at Codecov.
|
d23be88
to
7fdc103
Compare
Cool. This is going to take some time to review. I will attempt to do so tomorrow evening. Also, we can put other PRs that make code changes on hold until this get's merged. |
src/ParseNode.js
Outdated
ParseNode<"sqrt"> | | ||
ParseNode<"underline"> | | ||
ParseNode<"xArrow">; | ||
export type AnyParseNode = $Values<ParseNodeTypes>; |
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.
Is it possible to deduplicate mode
and loc
using intersection types( object spread? (facebook/flow#2626)&
)
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.
diff --git a/src/ParseNode.js b/src/ParseNode.js
index 26b2bbe..7f8cc10 100644
--- a/src/ParseNode.js
+++ b/src/ParseNode.js
@@ -7,7 +7,14 @@ import type {Token} from "./Token";
import type {Measurement} from "./units";
export type NodeType = $Keys<ParseNodeTypes>;
-export type ParseNode<TYPE: NodeType> = $ElementType<ParseNodeTypes, TYPE>;
+type ParseNodeBase ={|
+ mode: Mode,
+ loc?: ?SourceLocation,
+|}
+export type ParseNode<TYPE: NodeType> = {|
+ ...$ElementType<ParseNodeTypes, TYPE>,
+ ...ParseNodeBase
+|};
export type LeftRightDelimType = {|
type: "leftright",
@@ -31,20 +38,19 @@ export type SymbolParseNode =
ParseNode<"textord">;
// Union of all possible `ParseNode<>` types.
-export type AnyParseNode = $Values<ParseNodeTypes>;
+export type AnyParseNode = {|
+ ...$Values<ParseNodeTypes>,
+ ...ParseNodeBase
+|};
seems to work, not sure it's correct.
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.
Nice find on the type spread operator!
Regarding the ParseNode
definition above.
-
I would really like
ParseNode
to be covariant with itsTYPE
parameter. This means not looking up the value type within its definition. I think that might have been the cause of a lot of "___ is not compatible with ___" style errors which are completely unhelpful. Flow seems to be able to deal with an explicit union of explicitly-defined structs quite easily. An alternative is to replicate...ParseNodeBase
in every definition, which I can do. -
As a minor nit: if we not make
ParseNodeBase
a strict object type, then everyParseNode<TYPE>: ParseNodeBase
as well. Not sure if we would every use that fact, though. -
The
AnyParseNode
as defined above is not technically a union of all the structs and the behavior of Flow's type checking (especially when it gives an error) might get very confusing in such cases. E.g. Flow will allow you to do the following with a union that type it won't with the type defined above.type AllTypes = {| type: "foo", foo: number |} | {| type: "bar", bar: string |}; function(val: AllTypes) { let len; if (val.type === "foo") { len = val.foo + 1; } else { len = val.bar.length; } }
I was thus hoping to eventually change uses of
checkNodeType
to be simpletype
checks.
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.
@ylemkimon Actually, using
type ParseNodeBase = {
mode: Mode,
loc?: ?SourceLocation,
};
type ParseNodeTypes = {
"array": {|
type: "array",
...ParseNodeBase,
value: ArrayEnvNodeData,
|},
... // and same on the rest
seems to freeze the flow type checker very consistently (it's stuck at 24% progress at 100% CPU utilization). So let's skip that for now...
As we don't have |
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 code LGTM.
@ylemkimon IMO, But I'm open to any feedback you may have on any advantages of splitting it up. |
@marcianx I was thinking the PascalCase file name may give an impression that it default-exports a class named |
That's a valid concern. How about |
I think P.S. Sorry, I merged #1529 before seeing @kevinbarabash's suggestion to hold off on code changes. |
7fdc103
to
49da6e0
Compare
SGTM. Renamed to |
Sorry I had a social function this evening that I forgot about. @ylemkimon once the tests pass, feel free to approve the review if you feel comfortable. |
49da6e0
to
a67dcd0
Compare
This was towards #1492. |
@ylemkimon thanks for reviewing and approving. |
ParseNode
to flat objects per Port Parser.js to @flow #892 and fixes additional type errors discovered by flow.NodeValue<TYPE>
used to constrain flow's reasoning sometimes).ParseNode
s are created in the source code.NOTE: This PR has a higher chance of conflicts due to the unavoidable extensiveness of this change. So I'd like to get this in sooner rather than later. This does NOT flatten the objects yet! This reduces the area of merge conflict; and also, flattening is a rabbit hole since sometimes a handful of
ParseNode
types need to be converted together.