Skip to content

Commit de7975a

Browse files
authored
Bring back SourceFile.EndOfFileToken (#1257)
1 parent baf813f commit de7975a

File tree

90 files changed

+888
-968
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+888
-968
lines changed

CHANGES.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@ CHANGES.md lists intentional changes between the Strada (Typescript) and Corsa (
66

77
## Parser
88

9-
1. Source files do not contain an EndOfFile token as their last child.
10-
2. Malformed `...T?` at the end of a tuple now fails with a parse error instead of a grammar error.
11-
3. Malformed string ImportSpecifiers (`import x as "OOPS" from "y"`) now contain the string's text instead of an empty identifier.
12-
4. Empty binding elements no longer have a separate kind for OmittedExpression. Instead they have Kind=BindingElement with a nil Initialiser, Name and DotDotDotToken.
13-
5. ShorthandPropertyAssignment no longer includes an EqualsToken as a child when it has an ObjectAssignmentInitializer.
14-
6. JSDoc nodes now include leading whitespace in their location.
15-
7. The parser always parses a JSDocText node for comments in JSDoc. `string` is no longer part of the type of `comment`.
16-
8. In cases where Strada did produce a JSDocText node, Corsa no longer (incorrectly) includes all leading and trailing whitespace/asterisks, as well as initial `/**`.
17-
9. JSDocMemberName is now parsed as QualifiedName. These two nodes previously only differed by type, and now QualifiedName has a much less restrictive type for its left child.
9+
1. Malformed `...T?` at the end of a tuple now fails with a parse error instead of a grammar error.
10+
2. Malformed string ImportSpecifiers (`import x as "OOPS" from "y"`) now contain the string's text instead of an empty identifier.
11+
3. Empty binding elements no longer have a separate kind for OmittedExpression. Instead they have Kind=BindingElement with a nil Initialiser, Name and DotDotDotToken.
12+
4. ShorthandPropertyAssignment no longer includes an EqualsToken as a child when it has an ObjectAssignmentInitializer.
13+
5. JSDoc nodes now include leading whitespace in their location.
14+
6. The parser always parses a JSDocText node for comments in JSDoc. `string` is no longer part of the type of `comment`.
15+
7. In cases where Strada did produce a JSDocText node, Corsa no longer (incorrectly) includes all leading and trailing whitespace/asterisks, as well as initial `/**`.
16+
8. JSDocMemberName is now parsed as QualifiedName. These two nodes previously only differed by type, and now QualifiedName has a much less restrictive type for its left child.
1817

1918
JSDoc types are parsed in normal type annotation position but show a grammar error. Corsa no longer parses the JSDoc types below, giving a parse error instead of a grammar error.
2019

_packages/api/src/node.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ declare module "@typescript/ast" {
2020
const popcount8 = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8];
2121

2222
const childProperties: Readonly<Partial<Record<SyntaxKind, readonly string[]>>> = {
23+
[SyntaxKind.SourceFile]: ["statements", "endOfFileToken"],
2324
[SyntaxKind.QualifiedName]: ["left", "right"],
2425
[SyntaxKind.TypeParameter]: ["modifiers", "name", "constraint", "defaultType"],
2526
[SyntaxKind.IfStatement]: ["expression", "thenStatement", "elseStatement"],
@@ -221,7 +222,7 @@ export class RemoteNodeBase {
221222

222223
protected get childMask(): number {
223224
if (this.dataType !== NODE_DATA_TYPE_CHILDREN) {
224-
return 0;
225+
return -1;
225226
}
226227
return this.data & NODE_CHILD_MASK;
227228
}
@@ -674,6 +675,9 @@ export class RemoteNode extends RemoteNodeBase implements Node {
674675
get elseStatement(): RemoteNode | undefined {
675676
return this.getNamedChild("elseStatement") as RemoteNode;
676677
}
678+
get endOfFileToken(): RemoteNode | undefined {
679+
return this.getNamedChild("endOfFileToken") as RemoteNode;
680+
}
677681
get equalsGreaterThanToken(): RemoteNode | undefined {
678682
return this.getNamedChild("equalsGreaterThanToken") as RemoteNode;
679683
}

_packages/api/test/api.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe("SourceFile", () => {
109109
nodeCount++;
110110
node.forEachChild(visit);
111111
});
112-
assert.equal(nodeCount, 7);
112+
assert.equal(nodeCount, 8);
113113
});
114114
});
115115

_packages/ast/src/nodes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface Node extends ReadonlyTextRange {
1414
export interface SourceFile extends Node {
1515
readonly kind: SyntaxKind.SourceFile;
1616
readonly statements: NodeArray<Statement>;
17+
readonly endOfFileToken: EndOfFile;
1718
readonly text: string;
1819
readonly fileName: string;
1920
}

internal/ast/ast.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10017,10 +10017,11 @@ type SourceFile struct {
1001710017
compositeNodeBase
1001810018

1001910019
// Fields set by NewSourceFile
10020-
fileName string // For debugging convenience
10021-
parseOptions SourceFileParseOptions
10022-
text string
10023-
Statements *NodeList // NodeList[*Statement]
10020+
fileName string // For debugging convenience
10021+
parseOptions SourceFileParseOptions
10022+
text string
10023+
Statements *NodeList // NodeList[*Statement]
10024+
EndOfFileToken *TokenNode // TokenNode[*EndOfFileToken]
1002410025

1002510026
// Fields set by parser
1002610027
diagnostics []*Diagnostic
@@ -10070,7 +10071,7 @@ type SourceFile struct {
1007010071
declarationMap map[string][]*Node
1007110072
}
1007210073

10073-
func (f *NodeFactory) NewSourceFile(opts SourceFileParseOptions, text string, statements *NodeList) *Node {
10074+
func (f *NodeFactory) NewSourceFile(opts SourceFileParseOptions, text string, statements *NodeList, endOfFileToken *TokenNode) *Node {
1007410075
if (tspath.GetEncodedRootLength(opts.FileName) == 0 && !strings.HasPrefix(opts.FileName, "^/")) || opts.FileName != tspath.NormalizePath(opts.FileName) {
1007510076
panic(fmt.Sprintf("fileName should be normalized and absolute: %q", opts.FileName))
1007610077
}
@@ -10079,6 +10080,7 @@ func (f *NodeFactory) NewSourceFile(opts SourceFileParseOptions, text string, st
1007910080
data.parseOptions = opts
1008010081
data.text = text
1008110082
data.Statements = statements
10083+
data.EndOfFileToken = endOfFileToken
1008210084
return f.newNode(KindSourceFile, data)
1008310085
}
1008410086

@@ -10139,11 +10141,11 @@ func (node *SourceFile) SetBindDiagnostics(diags []*Diagnostic) {
1013910141
}
1014010142

1014110143
func (node *SourceFile) ForEachChild(v Visitor) bool {
10142-
return visitNodeList(v, node.Statements)
10144+
return visitNodeList(v, node.Statements) || visit(v, node.EndOfFileToken)
1014310145
}
1014410146

1014510147
func (node *SourceFile) VisitEachChild(v *NodeVisitor) *Node {
10146-
return v.Factory.UpdateSourceFile(node, v.visitTopLevelStatements(node.Statements))
10148+
return v.Factory.UpdateSourceFile(node, v.visitTopLevelStatements(node.Statements), v.visitToken(node.EndOfFileToken))
1014710149
}
1014810150

1014910151
func (node *SourceFile) IsJS() bool {
@@ -10171,7 +10173,7 @@ func (node *SourceFile) copyFrom(other *SourceFile) {
1017110173
}
1017210174

1017310175
func (node *SourceFile) Clone(f NodeFactoryCoercible) *Node {
10174-
updated := f.AsNodeFactory().NewSourceFile(node.parseOptions, node.text, node.Statements)
10176+
updated := f.AsNodeFactory().NewSourceFile(node.parseOptions, node.text, node.Statements, node.EndOfFileToken)
1017510177
newFile := updated.AsSourceFile()
1017610178
newFile.copyFrom(node)
1017710179
return cloneNode(updated, node.AsNode(), f.AsNodeFactory().hooks)
@@ -10181,9 +10183,9 @@ func (node *SourceFile) computeSubtreeFacts() SubtreeFacts {
1018110183
return propagateNodeListSubtreeFacts(node.Statements, propagateSubtreeFacts)
1018210184
}
1018310185

10184-
func (f *NodeFactory) UpdateSourceFile(node *SourceFile, statements *StatementList) *Node {
10185-
if statements != node.Statements {
10186-
updated := f.NewSourceFile(node.parseOptions, node.text, statements).AsSourceFile()
10186+
func (f *NodeFactory) UpdateSourceFile(node *SourceFile, statements *StatementList, endOfFileToken *TokenNode) *Node {
10187+
if statements != node.Statements || endOfFileToken != node.EndOfFileToken {
10188+
updated := f.NewSourceFile(node.parseOptions, node.text, statements, endOfFileToken).AsSourceFile()
1018710189
updated.copyFrom(node)
1018810190
return updateNode(updated.AsNode(), node.AsNode(), f.hooks)
1018910191
}

internal/astnav/tokens.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func getTokenAtPosition(
4949
left := 0
5050

5151
testNode := func(node *ast.Node) int {
52-
if node.End() == position && includePrecedingTokenAtEndPosition != nil {
52+
if node.Kind != ast.KindEndOfFile && node.End() == position && includePrecedingTokenAtEndPosition != nil {
5353
prevSubtree = node
5454
}
5555

@@ -247,7 +247,7 @@ func FindPrecedingToken(sourceFile *ast.SourceFile, position int) *ast.Node {
247247
func FindPrecedingTokenEx(sourceFile *ast.SourceFile, position int, startNode *ast.Node, excludeJSDoc bool) *ast.Node {
248248
var find func(node *ast.Node) *ast.Node
249249
find = func(n *ast.Node) *ast.Node {
250-
if ast.IsNonWhitespaceToken(n) {
250+
if ast.IsNonWhitespaceToken(n) && n.Kind != ast.KindEndOfFile {
251251
return n
252252
}
253253

internal/astnav/tokens_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import (
2020
)
2121

2222
var testFiles = []string{
23-
// !!! EOFToken JSDoc parsing is missing
24-
// filepath.Join(repo.TestDataPath, "fixtures/astnav/eofJSDoc.ts"),
2523
filepath.Join(repo.TypeScriptSubmodulePath, "src/services/mapCode.ts"),
2624
}
2725

internal/binder/binder.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,8 +1637,9 @@ func (b *Binder) bindChildren(node *ast.Node) {
16371637
// case *JSDocImportTag:
16381638
// b.bindJSDocImportTag(node)
16391639
case ast.KindSourceFile:
1640-
b.bindEachStatementFunctionsFirst(node.AsSourceFile().Statements)
1641-
// b.bind(node.endOfFileToken)
1640+
sourceFile := node.AsSourceFile()
1641+
b.bindEachStatementFunctionsFirst(sourceFile.Statements)
1642+
b.bind(sourceFile.EndOfFileToken)
16421643
case ast.KindBlock:
16431644
b.bindEachStatementFunctionsFirst(node.AsBlock().Statements)
16441645
case ast.KindModuleBlock:

internal/fourslash/_scripts/failingTests.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
TestAsOperatorCompletion
21
TestAutoImportsWithRootDirsAndRootedPath01
32
TestClosedCommentsInConstructor
43
TestCodeCompletionEscaping

internal/fourslash/tests/gen/asOperatorCompletion_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
func TestAsOperatorCompletion(t *testing.T) {
1111
t.Parallel()
12-
t.Skip()
12+
1313
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
1414
const content = `type T = number;
1515
var x;

0 commit comments

Comments
 (0)