vendor tsgo

This commit is contained in:
2026-07-09 16:50:43 -04:00
parent c06ea2e5a4
commit 98978e4930
5804 changed files with 1556156 additions and 101 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
package ast
// CheckFlags
type CheckFlags uint32
const (
CheckFlagsNone CheckFlags = 0
CheckFlagsInstantiated CheckFlags = 1 << 0 // Instantiated symbol
CheckFlagsSyntheticProperty CheckFlags = 1 << 1 // Property in union or intersection type
CheckFlagsSyntheticMethod CheckFlags = 1 << 2 // Method in union or intersection type
CheckFlagsReadonly CheckFlags = 1 << 3 // Readonly transient symbol
CheckFlagsReadPartial CheckFlags = 1 << 4 // Synthetic property present in some but not all constituents
CheckFlagsWritePartial CheckFlags = 1 << 5 // Synthetic property present in some but only satisfied by an index signature in others
CheckFlagsHasNonUniformType CheckFlags = 1 << 6 // Synthetic property with non-uniform type in constituents
CheckFlagsHasLiteralType CheckFlags = 1 << 7 // Synthetic property with at least one literal type in constituents
CheckFlagsContainsPublic CheckFlags = 1 << 8 // Synthetic property with public constituent(s)
CheckFlagsContainsProtected CheckFlags = 1 << 9 // Synthetic property with protected constituent(s)
CheckFlagsContainsPrivate CheckFlags = 1 << 10 // Synthetic property with private constituent(s)
CheckFlagsContainsStatic CheckFlags = 1 << 11 // Synthetic property with static constituent(s)
CheckFlagsLate CheckFlags = 1 << 12 // Late-bound symbol for a computed property with a dynamic name
CheckFlagsReverseMapped CheckFlags = 1 << 13 // Property of reverse-inferred homomorphic mapped type
CheckFlagsOptionalParameter CheckFlags = 1 << 14 // Optional parameter
CheckFlagsRestParameter CheckFlags = 1 << 15 // Rest parameter
CheckFlagsDeferredType CheckFlags = 1 << 16 // Calculation of the type of this symbol is deferred due to processing costs, should be fetched with `getTypeOfSymbolWithDeferredType`
CheckFlagsHasNeverType CheckFlags = 1 << 17 // Synthetic property with at least one never type in constituents
CheckFlagsMapped CheckFlags = 1 << 18 // Property of mapped type
CheckFlagsStripOptional CheckFlags = 1 << 19 // Strip optionality in mapped property
CheckFlagsUnresolved CheckFlags = 1 << 20 // Unresolved type alias symbol
CheckFlagsIsDiscriminantComputed CheckFlags = 1 << 21 // IsDiscriminant flags has been computed
CheckFlagsIsDiscriminant CheckFlags = 1 << 22 // Discriminant property
CheckFlagsIndexSymbol CheckFlags = 1 << 23 // Synthetic property created from index signature
CheckFlagsSynthetic = CheckFlagsSyntheticProperty | CheckFlagsSyntheticMethod
CheckFlagsNonUniformAndLiteral = CheckFlagsHasNonUniformType | CheckFlagsHasLiteralType
CheckFlagsPartial = CheckFlagsReadPartial | CheckFlagsWritePartial
)

View File

@@ -0,0 +1,86 @@
package ast
import "github.com/microsoft/typescript-go/internal/core"
// Ideally, this would get cached on the node factory so there's only ever one set of closures made per factory
func getDeepCloneVisitor(f *NodeFactory, syntheticLocation bool) *NodeVisitor {
var visitor *NodeVisitor
visitor = NewNodeVisitor(
func(node *Node) *Node {
visited := visitor.VisitEachChild(node)
if visited != node {
if syntheticLocation {
visited.Loc = core.NewTextRange(-1, -1)
}
return visited
}
c := node.Clone(f) // forcibly clone leaf nodes, which will then cascade new nodes/arrays upwards via `update` calls
// In strada, `factory.cloneNode` was dynamic and did _not_ clone positions for any "special cases", meanwhile
// Node.Clone in corsa reliably uses `Update` calls for all nodes and so copies locations by default.
// Deep clones are done to copy a node across files, so here, we explicitly make the location range synthetic on all cloned nodes
if syntheticLocation {
c.Loc = core.NewTextRange(-1, -1)
}
return c
},
f,
NodeVisitorHooks{
VisitNodes: func(nodes *NodeList, v *NodeVisitor) *NodeList {
if nodes == nil {
return nil
}
visited := v.VisitNodes(nodes)
var newList *NodeList
if visited != nodes {
newList = visited
} else {
newList = nodes.Clone(v.Factory)
}
if syntheticLocation {
newList.Loc = core.NewTextRange(-1, -1)
if nodes.HasTrailingComma() {
newList.Nodes[len(newList.Nodes)-1].Loc = core.NewTextRange(-2, -2)
}
}
return newList
},
VisitModifiers: func(nodes *ModifierList, v *NodeVisitor) *ModifierList {
if nodes == nil {
return nil
}
visited := v.VisitModifiers(nodes)
var newList *ModifierList
if visited != nodes {
newList = visited
} else {
newList = nodes.Clone(v.Factory)
}
if syntheticLocation {
newList.Loc = core.NewTextRange(-1, -1)
if nodes.HasTrailingComma() {
newList.Nodes[len(newList.Nodes)-1].Loc = core.NewTextRange(-2, -2)
}
}
return newList
},
},
)
return visitor
}
func (f *NodeFactory) DeepCloneNode(node *Node) *Node {
return getDeepCloneVisitor(f, true /*syntheticLocation*/).VisitNode(node)
}
func (f *NodeFactory) DeepCloneReparse(node *Node) *Node {
if node != nil {
node = getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitNode(node)
SetParentInChildren(node)
node.Flags |= NodeFlagsReparsed
}
return node
}
func (f *NodeFactory) DeepCloneReparseModifiers(modifiers *ModifierList) *ModifierList {
return getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitModifiers(modifiers)
}

View File

@@ -0,0 +1,599 @@
package ast_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/testutil/parsetestutil"
"gotest.tools/v3/assert"
)
type NodeComparisonWorkItem struct {
original *ast.Node
copy *ast.Node
}
func getChildren(node *ast.Node) []*ast.Node {
children := []*ast.Node{}
node.VisitEachChild(ast.NewNodeVisitor(func(node *ast.Node) *ast.Node {
children = append(children, node)
return node
}, nil, ast.NodeVisitorHooks{}))
return children
}
func TestDeepCloneNodeSanityCheck(t *testing.T) {
t.Parallel()
data := []struct {
title string
input string
jsx bool
}{
{title: "StringLiteral#1", input: `;"test"`},
{title: "StringLiteral#2", input: `;'test'`},
{title: "NumericLiteral", input: `0`},
{title: "BigIntLiteral", input: `0n`},
{title: "BooleanLiteral#1", input: `true`},
{title: "BooleanLiteral#2", input: `false`},
{title: "NoSubstitutionTemplateLiteral", input: "``"},
{title: "RegularExpressionLiteral#1", input: `/a/`},
{title: "RegularExpressionLiteral#2", input: `/a/g`},
{title: "NullLiteral", input: `null`},
{title: "ThisExpression", input: `this`},
{title: "SuperExpression", input: `super()`},
{title: "ImportExpression", input: `import()`},
{title: "PropertyAccess#1", input: `a.b`},
{title: "PropertyAccess#2", input: `a.#b`},
{title: "PropertyAccess#3", input: `a?.b`},
{title: "PropertyAccess#4", input: `a?.b.c`},
{title: "PropertyAccess#5", input: `1..b`},
{title: "PropertyAccess#6", input: `1.0.b`},
{title: "PropertyAccess#7", input: `0x1.b`},
{title: "PropertyAccess#8", input: `0b1.b`},
{title: "PropertyAccess#9", input: `0o1.b`},
{title: "PropertyAccess#10", input: `10e1.b`},
{title: "PropertyAccess#11", input: `10E1.b`},
{title: "ElementAccess#1", input: `a[b]`},
{title: "ElementAccess#2", input: `a?.[b]`},
{title: "ElementAccess#3", input: `a?.[b].c`},
{title: "CallExpression#1", input: `a()`},
{title: "CallExpression#2", input: `a<T>()`},
{title: "CallExpression#3", input: `a(b)`},
{title: "CallExpression#4", input: `a<T>(b)`},
{title: "CallExpression#5", input: `a(b).c`},
{title: "CallExpression#6", input: `a<T>(b).c`},
{title: "CallExpression#7", input: `a?.(b)`},
{title: "CallExpression#8", input: `a?.<T>(b)`},
{title: "CallExpression#9", input: `a?.(b).c`},
{title: "CallExpression#10", input: `a?.<T>(b).c`},
{title: "CallExpression#11", input: `a<T, U>()`},
{title: "CallExpression#12", input: `a<T,>()`},
{title: "NewExpression#1", input: `new a`},
{title: "NewExpression#2", input: `new a.b`},
{title: "NewExpression#3", input: `new a()`},
{title: "NewExpression#4", input: `new a.b()`},
{title: "NewExpression#5", input: `new a<T>()`},
{title: "NewExpression#6", input: `new a.b<T>()`},
{title: "NewExpression#7", input: `new a(b)`},
{title: "NewExpression#8", input: `new a.b(c)`},
{title: "NewExpression#9", input: `new a<T>(b)`},
{title: "NewExpression#10", input: `new a.b<T>(c)`},
{title: "NewExpression#11", input: `new a(b).c`},
{title: "NewExpression#12", input: `new a<T>(b).c`},
{title: "TaggedTemplateExpression#1", input: "tag``"},
{title: "TaggedTemplateExpression#2", input: "tag<T>``"},
{title: "TypeAssertionExpression#1", input: `<T>a`},
{title: "FunctionExpression#1", input: `(function(){})`},
{title: "FunctionExpression#2", input: `(function f(){})`},
{title: "FunctionExpression#3", input: `(function*f(){})`},
{title: "FunctionExpression#4", input: `(async function f(){})`},
{title: "FunctionExpression#5", input: `(async function*f(){})`},
{title: "FunctionExpression#6", input: `(function<T>(){})`},
{title: "FunctionExpression#7", input: `(function(a){})`},
{title: "FunctionExpression#8", input: `(function():T{})`},
{title: "ArrowFunction#1", input: `a=>{}`},
{title: "ArrowFunction#2", input: `()=>{}`},
{title: "ArrowFunction#3", input: `(a)=>{}`},
{title: "ArrowFunction#4", input: `<T>(a)=>{}`},
{title: "ArrowFunction#5", input: `async a=>{}`},
{title: "ArrowFunction#6", input: `async()=>{}`},
{title: "ArrowFunction#7", input: `async<T>()=>{}`},
{title: "ArrowFunction#8", input: `():T=>{}`},
{title: "ArrowFunction#9", input: `()=>a`},
{title: "DeleteExpression", input: `delete a`},
{title: "TypeOfExpression", input: `typeof a`},
{title: "VoidExpression", input: `void a`},
{title: "AwaitExpression", input: `await a`},
{title: "PrefixUnaryExpression#1", input: `+a`},
{title: "PrefixUnaryExpression#2", input: `++a`},
{title: "PrefixUnaryExpression#3", input: `+ +a`},
{title: "PrefixUnaryExpression#4", input: `+ ++a`},
{title: "PrefixUnaryExpression#5", input: `-a`},
{title: "PrefixUnaryExpression#6", input: `--a`},
{title: "PrefixUnaryExpression#7", input: `- -a`},
{title: "PrefixUnaryExpression#8", input: `- --a`},
{title: "PrefixUnaryExpression#9", input: `+-a`},
{title: "PrefixUnaryExpression#10", input: `+--a`},
{title: "PrefixUnaryExpression#11", input: `-+a`},
{title: "PrefixUnaryExpression#12", input: `-++a`},
{title: "PrefixUnaryExpression#13", input: `~a`},
{title: "PrefixUnaryExpression#14", input: `!a`},
{title: "PostfixUnaryExpression#1", input: `a++`},
{title: "PostfixUnaryExpression#2", input: `a--`},
{title: "BinaryExpression#1", input: `a,b`},
{title: "BinaryExpression#2", input: `a+b`},
{title: "BinaryExpression#3", input: `a**b`},
{title: "BinaryExpression#4", input: `a instanceof b`},
{title: "BinaryExpression#5", input: `a in b`},
{title: "ConditionalExpression", input: `a?b:c`},
{title: "TemplateExpression#1", input: "`a${b}c`"},
{title: "TemplateExpression#2", input: "`a${b}c${d}e`"},
{title: "YieldExpression#1", input: `(function*() { yield })`},
{title: "YieldExpression#2", input: `(function*() { yield a })`},
{title: "YieldExpression#3", input: `(function*() { yield*a })`},
{title: "SpreadElement", input: `[...a]`},
{title: "ClassExpression#1", input: `(class {})`},
{title: "ClassExpression#2", input: `(class a {})`},
{title: "ClassExpression#3", input: `(class<T>{})`},
{title: "ClassExpression#4", input: `(class a<T>{})`},
{title: "ClassExpression#5", input: `(class extends b {})`},
{title: "ClassExpression#6", input: `(class a extends b {})`},
{title: "ClassExpression#7", input: `(class implements b {})`},
{title: "ClassExpression#8", input: `(class a implements b {})`},
{title: "ClassExpression#9", input: `(class implements b, c {})`},
{title: "ClassExpression#10", input: `(class a implements b, c {})`},
{title: "ClassExpression#11", input: `(class extends b implements c, d {})`},
{title: "ClassExpression#12", input: `(class a extends b implements c, d {})`},
{title: "ClassExpression#13", input: `(@a class {})`},
{title: "OmittedExpression", input: `[,]`},
{title: "ExpressionWithTypeArguments", input: `a<T>`},
{title: "AsExpression", input: `a as T`},
{title: "SatisfiesExpression", input: `a satisfies T`},
{title: "NonNullExpression", input: `a!`},
{title: "MetaProperty#1", input: `new.target`},
{title: "MetaProperty#2", input: `import.meta`},
{title: "ArrayLiteralExpression#1", input: `[]`},
{title: "ArrayLiteralExpression#2", input: `[a]`},
{title: "ArrayLiteralExpression#3", input: `[a,]`},
{title: "ArrayLiteralExpression#4", input: `[,a]`},
{title: "ArrayLiteralExpression#5", input: `[...a]`},
{title: "ObjectLiteralExpression#1", input: `({})`},
{title: "ObjectLiteralExpression#2", input: `({a,})`},
{title: "ShorthandPropertyAssignment", input: `({a})`},
{title: "PropertyAssignment", input: `({a:b})`},
{title: "SpreadAssignment", input: `({...a})`},
{title: "Block", input: `{}`},
{title: "VariableStatement#1", input: `var a`},
{title: "VariableStatement#2", input: `let a`},
{title: "VariableStatement#3", input: `const a = b`},
{title: "VariableStatement#4", input: `using a = b`},
{title: "VariableStatement#5", input: `await using a = b`},
{title: "EmptyStatement", input: `;`},
{title: "IfStatement#1", input: `if(a);`},
{title: "IfStatement#2", input: `if(a);else;`},
{title: "IfStatement#3", input: `if(a);else{}`},
{title: "IfStatement#4", input: `if(a);else if(b);`},
{title: "IfStatement#5", input: `if(a);else if(b) {}`},
{title: "IfStatement#6", input: `if(a) {}`},
{title: "IfStatement#7", input: `if(a) {} else;`},
{title: "IfStatement#8", input: `if(a) {} else {}`},
{title: "IfStatement#9", input: `if(a) {} else if(b);`},
{title: "IfStatement#10", input: `if(a) {} else if(b){}`},
{title: "DoStatement#1", input: `do;while(a);`},
{title: "DoStatement#2", input: `do {} while(a);`},
{title: "WhileStatement#1", input: `while(a);`},
{title: "WhileStatement#2", input: `while(a) {}`},
{title: "ForStatement#1", input: `for(;;);`},
{title: "ForStatement#2", input: `for(a;;);`},
{title: "ForStatement#3", input: `for(var a;;);`},
{title: "ForStatement#4", input: `for(;a;);`},
{title: "ForStatement#5", input: `for(;;a);`},
{title: "ForStatement#6", input: `for(;;){}`},
{title: "ForInStatement#1", input: `for(a in b);`},
{title: "ForInStatement#2", input: `for(var a in b);`},
{title: "ForInStatement#3", input: `for(a in b){}`},
{title: "ForOfStatement#1", input: `for(a of b);`},
{title: "ForOfStatement#2", input: `for(var a of b);`},
{title: "ForOfStatement#3", input: `for(a of b){}`},
{title: "ForOfStatement#4", input: `for await(a of b);`},
{title: "ForOfStatement#5", input: `for await(var a of b);`},
{title: "ForOfStatement#6", input: `for await(a of b){}`},
{title: "ContinueStatement#1", input: `continue`},
{title: "ContinueStatement#2", input: `continue a`},
{title: "BreakStatement#1", input: `break`},
{title: "BreakStatement#2", input: `break a`},
{title: "ReturnStatement#1", input: `return`},
{title: "ReturnStatement#2", input: `return a`},
{title: "WithStatement#1", input: `with(a);`},
{title: "WithStatement#2", input: `with(a){}`},
{title: "SwitchStatement", input: `switch (a) {}`},
{title: "CaseClause#1", input: `switch (a) {case b:}`},
{title: "CaseClause#2", input: `switch (a) {case b:;}`},
{title: "DefaultClause#1", input: `switch (a) {default:}`},
{title: "DefaultClause#2", input: `switch (a) {default:;}`},
{title: "LabeledStatement", input: `a:;`},
{title: "ThrowStatement", input: `throw a`},
{title: "TryStatement#1", input: `try {} catch {}`},
{title: "TryStatement#2", input: `try {} finally {}`},
{title: "TryStatement#3", input: `try {} catch {} finally {}`},
{title: "DebuggerStatement", input: `debugger`},
{title: "FunctionDeclaration#1", input: `export default function(){}`},
{title: "FunctionDeclaration#2", input: `function f(){}`},
{title: "FunctionDeclaration#3", input: `function*f(){}`},
{title: "FunctionDeclaration#4", input: `async function f(){}`},
{title: "FunctionDeclaration#5", input: `async function*f(){}`},
{title: "FunctionDeclaration#6", input: `function f<T>(){}`},
{title: "FunctionDeclaration#7", input: `function f(a){}`},
{title: "FunctionDeclaration#8", input: `function f():T{}`},
{title: "FunctionDeclaration#9", input: `function f();`},
{title: "ClassDeclaration#1", input: `class a {}`},
{title: "ClassDeclaration#2", input: `class a<T>{}`},
{title: "ClassDeclaration#3", input: `class a extends b {}`},
{title: "ClassDeclaration#4", input: `class a implements b {}`},
{title: "ClassDeclaration#5", input: `class a implements b, c {}`},
{title: "ClassDeclaration#6", input: `class a extends b implements c, d {}`},
{title: "ClassDeclaration#7", input: `export default class {}`},
{title: "ClassDeclaration#8", input: `export default class<T>{}`},
{title: "ClassDeclaration#9", input: `export default class extends b {}`},
{title: "ClassDeclaration#10", input: `export default class implements b {}`},
{title: "ClassDeclaration#11", input: `export default class implements b, c {}`},
{title: "ClassDeclaration#12", input: `export default class extends b implements c, d {}`},
{title: "ClassDeclaration#13", input: `@a class b {}`},
{title: "ClassDeclaration#14", input: `@a export class b {}`},
{title: "ClassDeclaration#15", input: `export @a class b {}`},
{title: "InterfaceDeclaration#1", input: `interface a {}`},
{title: "InterfaceDeclaration#2", input: `interface a<T>{}`},
{title: "InterfaceDeclaration#3", input: `interface a extends b {}`},
{title: "InterfaceDeclaration#4", input: `interface a extends b, c {}`},
{title: "TypeAliasDeclaration#1", input: `type a = b`},
{title: "TypeAliasDeclaration#2", input: `type a<T> = b`},
{title: "EnumDeclaration#1", input: `enum a{}`},
{title: "EnumDeclaration#2", input: `enum a{b}`},
{title: "EnumDeclaration#3", input: `enum a{b=c}`},
{title: "ModuleDeclaration#1", input: `module a{}`},
{title: "ModuleDeclaration#2", input: `module a.b{}`},
{title: "ModuleDeclaration#3", input: `module "a";`},
{title: "ModuleDeclaration#4", input: `module "a"{}`},
{title: "ModuleDeclaration#5", input: `namespace a{}`},
{title: "ModuleDeclaration#6", input: `namespace a.b{}`},
{title: "ModuleDeclaration#7", input: `global;`},
{title: "ModuleDeclaration#8", input: `global{}`},
{title: "ImportEqualsDeclaration#1", input: `import a = b`},
{title: "ImportEqualsDeclaration#2", input: `import a = b.c`},
{title: "ImportEqualsDeclaration#3", input: `import a = require("b")`},
{title: "ImportEqualsDeclaration#4", input: `export import a = b`},
{title: "ImportEqualsDeclaration#5", input: `export import a = require("b")`},
{title: "ImportEqualsDeclaration#6", input: `import type a = b`},
{title: "ImportEqualsDeclaration#7", input: `import type a = b.c`},
{title: "ImportEqualsDeclaration#8", input: `import type a = require("b")`},
{title: "ImportDeclaration#1", input: `import "a"`},
{title: "ImportDeclaration#2", input: `import a from "b"`},
{title: "ImportDeclaration#3", input: `import type a from "b"`},
{title: "ImportDeclaration#4", input: `import * as a from "b"`},
{title: "ImportDeclaration#5", input: `import type * as a from "b"`},
{title: "ImportDeclaration#6", input: `import {} from "b"`},
{title: "ImportDeclaration#7", input: `import type {} from "b"`},
{title: "ImportDeclaration#8", input: `import { a } from "b"`},
{title: "ImportDeclaration#9", input: `import type { a } from "b"`},
{title: "ImportDeclaration#8", input: `import { a as b } from "c"`},
{title: "ImportDeclaration#9", input: `import type { a as b } from "c"`},
{title: "ImportDeclaration#10", input: `import { "a" as b } from "c"`},
{title: "ImportDeclaration#11", input: `import type { "a" as b } from "c"`},
{title: "ImportDeclaration#12", input: `import a, {} from "b"`},
{title: "ImportDeclaration#13", input: `import a, * as b from "c"`},
{title: "ImportDeclaration#14", input: `import {} from "a" with {}`},
{title: "ImportDeclaration#15", input: `import {} from "a" with { b: "c" }`},
{title: "ImportDeclaration#16", input: `import {} from "a" with { "b": "c" }`},
{title: "ExportAssignment#1", input: `export = a`},
{title: "ExportAssignment#2", input: `export default a`},
{title: "NamespaceExportDeclaration", input: `export as namespace a`},
{title: "ExportDeclaration#1", input: `export * from "a"`},
{title: "ExportDeclaration#2", input: `export type * from "a"`},
{title: "ExportDeclaration#3", input: `export * as a from "b"`},
{title: "ExportDeclaration#4", input: `export type * as a from "b"`},
{title: "ExportDeclaration#5", input: `export { } from "a"`},
{title: "ExportDeclaration#6", input: `export type { } from "a"`},
{title: "ExportDeclaration#7", input: `export { a } from "b"`},
{title: "ExportDeclaration#8", input: `export { type a } from "b"`},
{title: "ExportDeclaration#9", input: `export type { a } from "b"`},
{title: "ExportDeclaration#10", input: `export { a as b } from "c"`},
{title: "ExportDeclaration#11", input: `export { type a as b } from "c"`},
{title: "ExportDeclaration#12", input: `export type { a as b } from "c"`},
{title: "ExportDeclaration#13", input: `export { a as "b" } from "c"`},
{title: "ExportDeclaration#14", input: `export { type a as "b" } from "c"`},
{title: "ExportDeclaration#15", input: `export type { a as "b" } from "c"`},
{title: "ExportDeclaration#16", input: `export { "a" } from "b"`},
{title: "ExportDeclaration#17", input: `export { type "a" } from "b"`},
{title: "ExportDeclaration#18", input: `export type { "a" } from "b"`},
{title: "ExportDeclaration#19", input: `export { "a" as b } from "c"`},
{title: "ExportDeclaration#20", input: `export { type "a" as b } from "c"`},
{title: "ExportDeclaration#21", input: `export type { "a" as b } from "c"`},
{title: "ExportDeclaration#22", input: `export { "a" as "b" } from "c"`},
{title: "ExportDeclaration#23", input: `export { type "a" as "b" } from "c"`},
{title: "ExportDeclaration#24", input: `export type { "a" as "b" } from "c"`},
{title: "ExportDeclaration#25", input: `export { }`},
{title: "ExportDeclaration#26", input: `export type { }`},
{title: "ExportDeclaration#27", input: `export { a }`},
{title: "ExportDeclaration#28", input: `export { type a }`},
{title: "ExportDeclaration#29", input: `export type { a }`},
{title: "ExportDeclaration#30", input: `export { a as b }`},
{title: "ExportDeclaration#31", input: `export { type a as b }`},
{title: "ExportDeclaration#32", input: `export type { a as b }`},
{title: "ExportDeclaration#33", input: `export { a as "b" }`},
{title: "ExportDeclaration#34", input: `export { type a as "b" }`},
{title: "ExportDeclaration#35", input: `export type { a as "b" }`},
{title: "ExportDeclaration#36", input: `export {} from "a" with {}`},
{title: "ExportDeclaration#37", input: `export {} from "a" with { b: "c" }`},
{title: "ExportDeclaration#38", input: `export {} from "a" with { "b": "c" }`},
{title: "KeywordTypeNode#1", input: `type T = any`},
{title: "KeywordTypeNode#2", input: `type T = unknown`},
{title: "KeywordTypeNode#3", input: `type T = never`},
{title: "KeywordTypeNode#4", input: `type T = void`},
{title: "KeywordTypeNode#5", input: `type T = undefined`},
{title: "KeywordTypeNode#6", input: `type T = null`},
{title: "KeywordTypeNode#7", input: `type T = object`},
{title: "KeywordTypeNode#8", input: `type T = string`},
{title: "KeywordTypeNode#9", input: `type T = symbol`},
{title: "KeywordTypeNode#10", input: `type T = number`},
{title: "KeywordTypeNode#11", input: `type T = bigint`},
{title: "KeywordTypeNode#12", input: `type T = boolean`},
{title: "KeywordTypeNode#13", input: `type T = intrinsic`},
{title: "TypePredicateNode#1", input: `function f(): asserts a`},
{title: "TypePredicateNode#2", input: `function f(): asserts a is b`},
{title: "TypePredicateNode#3", input: `function f(): asserts this`},
{title: "TypePredicateNode#4", input: `function f(): asserts this is b`},
{title: "TypeReferenceNode#1", input: `type T = a`},
{title: "TypeReferenceNode#2", input: `type T = a.b`},
{title: "TypeReferenceNode#3", input: `type T = a<U>`},
{title: "TypeReferenceNode#4", input: `type T = a.b<U>`},
{title: "FunctionTypeNode#1", input: `type T = () => a`},
{title: "FunctionTypeNode#2", input: `type T = <T>() => a`},
{title: "FunctionTypeNode#3", input: `type T = (a) => b`},
{title: "ConstructorTypeNode#1", input: `type T = new () => a`},
{title: "ConstructorTypeNode#2", input: `type T = new <T>() => a`},
{title: "ConstructorTypeNode#3", input: `type T = new (a) => b`},
{title: "ConstructorTypeNode#4", input: `type T = abstract new () => a`},
{title: "TypeQueryNode#1", input: `type T = typeof a`},
{title: "TypeQueryNode#2", input: `type T = typeof a.b`},
{title: "TypeQueryNode#3", input: `type T = typeof a<U>`},
{title: "TypeLiteralNode#1", input: `type T = {}`},
{title: "TypeLiteralNode#2", input: `type T = {a}`},
{title: "ArrayTypeNode", input: `type T = a[]`},
{title: "TupleTypeNode#1", input: `type T = []`},
{title: "TupleTypeNode#2", input: `type T = [a]`},
{title: "TupleTypeNode#3", input: `type T = [a,]`},
{title: "RestTypeNode", input: `type T = [...a]`},
{title: "OptionalTypeNode", input: `type T = [a?]`},
{title: "NamedTupleMember#1", input: `type T = [a: b]`},
{title: "NamedTupleMember#2", input: `type T = [a?: b]`},
{title: "NamedTupleMember#3", input: `type T = [...a: b]`},
{title: "UnionTypeNode#1", input: `type T = a | b`},
{title: "UnionTypeNode#2", input: `type T = a | b | c`},
{title: "UnionTypeNode#3", input: `type T = | a | b`},
{title: "IntersectionTypeNode#1", input: `type T = a & b`},
{title: "IntersectionTypeNode#2", input: `type T = a & b & c`},
{title: "IntersectionTypeNode#3", input: `type T = & a & b`},
{title: "ConditionalTypeNode", input: `type T = a extends b ? c : d`},
{title: "InferTypeNode#1", input: `type T = a extends infer b ? c : d`},
{title: "InferTypeNode#2", input: `type T = a extends infer b extends c ? d : e`},
{title: "ParenthesizedTypeNode", input: `type T = (U)`},
{title: "ThisTypeNode", input: `type T = this`},
{title: "TypeOperatorNode#1", input: `type T = keyof U`},
{title: "TypeOperatorNode#2", input: `type T = readonly U[]`},
{title: "TypeOperatorNode#3", input: `type T = unique symbol`},
{title: "IndexedAccessTypeNode", input: `type T = a[b]`},
{title: "MappedTypeNode#1", input: `type T = { [a in b]: c }`},
{title: "MappedTypeNode#2", input: `type T = { [a in b as c]: d }`},
{title: "MappedTypeNode#3", input: `type T = { readonly [a in b]: c }`},
{title: "MappedTypeNode#4", input: `type T = { +readonly [a in b]: c }`},
{title: "MappedTypeNode#5", input: `type T = { -readonly [a in b]: c }`},
{title: "MappedTypeNode#6", input: `type T = { [a in b]?: c }`},
{title: "MappedTypeNode#7", input: `type T = { [a in b]+?: c }`},
{title: "MappedTypeNode#8", input: `type T = { [a in b]-?: c }`},
{title: "MappedTypeNode#9", input: `type T = { [a in b]: c; d }`},
{title: "LiteralTypeNode#1", input: `type T = null`},
{title: "LiteralTypeNode#2", input: `type T = true`},
{title: "LiteralTypeNode#3", input: `type T = false`},
{title: "LiteralTypeNode#4", input: `type T = ""`},
{title: "LiteralTypeNode#5", input: "type T = ''"},
{title: "LiteralTypeNode#6", input: "type T = ``"},
{title: "LiteralTypeNode#7", input: `type T = 0`},
{title: "LiteralTypeNode#8", input: `type T = 0n`},
{title: "LiteralTypeNode#9", input: `type T = -0`},
{title: "LiteralTypeNode#10", input: `type T = -0n`},
{title: "TemplateTypeNode#1", input: "type T = `a${b}c`"},
{title: "TemplateTypeNode#2", input: "type T = `a${b}c${d}e`"},
{title: "ImportTypeNode#1", input: `type T = import(a)`},
{title: "ImportTypeNode#2", input: `type T = import(a).b`},
{title: "ImportTypeNode#3", input: `type T = import(a).b<U>`},
{title: "ImportTypeNode#4", input: `type T = typeof import(a)`},
{title: "ImportTypeNode#5", input: `type T = typeof import(a).b`},
{title: "ImportTypeNode#6", input: `type T = import(a, { with: { } })`},
{title: "ImportTypeNode#6", input: `type T = import(a, { with: { b: "c" } })`},
{title: "ImportTypeNode#7", input: `type T = import(a, { with: { "b": "c" } })`},
{title: "PropertySignature#1", input: "interface I {a}"},
{title: "PropertySignature#2", input: "interface I {readonly a}"},
{title: "PropertySignature#3", input: "interface I {\"a\"}"},
{title: "PropertySignature#4", input: "interface I {'a'}"},
{title: "PropertySignature#5", input: "interface I {0}"},
{title: "PropertySignature#6", input: "interface I {0n}"},
{title: "PropertySignature#7", input: "interface I {[a]}"},
{title: "PropertySignature#8", input: "interface I {a?}"},
{title: "PropertySignature#9", input: "interface I {a: b}"},
{title: "MethodSignature#1", input: "interface I {a()}"},
{title: "MethodSignature#2", input: "interface I {\"a\"()}"},
{title: "MethodSignature#3", input: "interface I {'a'()}"},
{title: "MethodSignature#4", input: "interface I {0()}"},
{title: "MethodSignature#5", input: "interface I {0n()}"},
{title: "MethodSignature#6", input: "interface I {[a]()}"},
{title: "MethodSignature#7", input: "interface I {a?()}"},
{title: "MethodSignature#8", input: "interface I {a<T>()}"},
{title: "MethodSignature#9", input: "interface I {a(): b}"},
{title: "MethodSignature#10", input: "interface I {a(b): c}"},
{title: "CallSignature#1", input: "interface I {()}"},
{title: "CallSignature#2", input: "interface I {():a}"},
{title: "CallSignature#3", input: "interface I {(p)}"},
{title: "CallSignature#4", input: "interface I {<T>()}"},
{title: "ConstructSignature#1", input: "interface I {new ()}"},
{title: "ConstructSignature#2", input: "interface I {new ():a}"},
{title: "ConstructSignature#3", input: "interface I {new (p)}"},
{title: "ConstructSignature#4", input: "interface I {new <T>()}"},
{title: "IndexSignatureDeclaration#1", input: "interface I {[a]}"},
{title: "IndexSignatureDeclaration#2", input: "interface I {[a: b]}"},
{title: "IndexSignatureDeclaration#3", input: "interface I {[a: b]: c}"},
{title: "PropertyDeclaration#1", input: "class C {a}"},
{title: "PropertyDeclaration#2", input: "class C {readonly a}"},
{title: "PropertyDeclaration#3", input: "class C {static a}"},
{title: "PropertyDeclaration#4", input: "class C {accessor a}"},
{title: "PropertyDeclaration#5", input: "class C {\"a\"}"},
{title: "PropertyDeclaration#6", input: "class C {'a'}"},
{title: "PropertyDeclaration#7", input: "class C {0}"},
{title: "PropertyDeclaration#8", input: "class C {0n}"},
{title: "PropertyDeclaration#9", input: "class C {[a]}"},
{title: "PropertyDeclaration#10", input: "class C {#a}"},
{title: "PropertyDeclaration#11", input: "class C {a?}"},
{title: "PropertyDeclaration#12", input: "class C {a!}"},
{title: "PropertyDeclaration#13", input: "class C {a: b}"},
{title: "PropertyDeclaration#14", input: "class C {a = b}"},
{title: "PropertyDeclaration#15", input: "class C {@a b}"},
{title: "MethodDeclaration#1", input: "class C {a()}"},
{title: "MethodDeclaration#2", input: "class C {\"a\"()}"},
{title: "MethodDeclaration#3", input: "class C {'a'()}"},
{title: "MethodDeclaration#4", input: "class C {0()}"},
{title: "MethodDeclaration#5", input: "class C {0n()}"},
{title: "MethodDeclaration#6", input: "class C {[a]()}"},
{title: "MethodDeclaration#7", input: "class C {#a()}"},
{title: "MethodDeclaration#8", input: "class C {a?()}"},
{title: "MethodDeclaration#9", input: "class C {a<T>()}"},
{title: "MethodDeclaration#10", input: "class C {a(): b}"},
{title: "MethodDeclaration#11", input: "class C {a(b): c}"},
{title: "MethodDeclaration#12", input: "class C {a() {} }"},
{title: "MethodDeclaration#13", input: "class C {@a b() {} }"},
{title: "MethodDeclaration#14", input: "class C {static a() {} }"},
{title: "MethodDeclaration#15", input: "class C {async a() {} }"},
{title: "GetAccessorDeclaration#1", input: "class C {get a()}"},
{title: "GetAccessorDeclaration#2", input: "class C {get \"a\"()}"},
{title: "GetAccessorDeclaration#3", input: "class C {get 'a'()}"},
{title: "GetAccessorDeclaration#4", input: "class C {get 0()}"},
{title: "GetAccessorDeclaration#5", input: "class C {get 0n()}"},
{title: "GetAccessorDeclaration#6", input: "class C {get [a]()}"},
{title: "GetAccessorDeclaration#7", input: "class C {get #a()}"},
{title: "GetAccessorDeclaration#8", input: "class C {get a(): b}"},
{title: "GetAccessorDeclaration#9", input: "class C {get a(b): c}"},
{title: "GetAccessorDeclaration#10", input: "class C {get a() {} }"},
{title: "GetAccessorDeclaration#11", input: "class C {@a get b() {} }"},
{title: "GetAccessorDeclaration#12", input: "class C {static get a() {} }"},
{title: "SetAccessorDeclaration#1", input: "class C {set a()}"},
{title: "SetAccessorDeclaration#2", input: "class C {set \"a\"()}"},
{title: "SetAccessorDeclaration#3", input: "class C {set 'a'()}"},
{title: "SetAccessorDeclaration#4", input: "class C {set 0()}"},
{title: "SetAccessorDeclaration#5", input: "class C {set 0n()}"},
{title: "SetAccessorDeclaration#6", input: "class C {set [a]()}"},
{title: "SetAccessorDeclaration#7", input: "class C {set #a()}"},
{title: "SetAccessorDeclaration#8", input: "class C {set a(): b}"},
{title: "SetAccessorDeclaration#9", input: "class C {set a(b): c}"},
{title: "SetAccessorDeclaration#10", input: "class C {set a() {} }"},
{title: "SetAccessorDeclaration#11", input: "class C {@a set b() {} }"},
{title: "SetAccessorDeclaration#12", input: "class C {static set a() {} }"},
{title: "ConstructorDeclaration#1", input: "class C {constructor()}"},
{title: "ConstructorDeclaration#2", input: "class C {constructor(): b}"},
{title: "ConstructorDeclaration#3", input: "class C {constructor(b): c}"},
{title: "ConstructorDeclaration#4", input: "class C {constructor() {} }"},
{title: "ConstructorDeclaration#5", input: "class C {@a constructor() {} }"},
{title: "ConstructorDeclaration#6", input: "class C {private constructor() {} }"},
{title: "ClassStaticBlockDeclaration", input: "class C {static { }}"},
{title: "SemicolonClassElement#1", input: "class C {;}"},
{title: "ParameterDeclaration#1", input: "function f(a)"},
{title: "ParameterDeclaration#2", input: "function f(a: b)"},
{title: "ParameterDeclaration#3", input: "function f(a = b)"},
{title: "ParameterDeclaration#4", input: "function f(a?)"},
{title: "ParameterDeclaration#5", input: "function f(...a)"},
{title: "ParameterDeclaration#6", input: "function f(this)"},
{title: "ParameterDeclaration#7", input: "function f(a,)"},
{title: "ObjectBindingPattern#1", input: "function f({})"},
{title: "ObjectBindingPattern#2", input: "function f({a})"},
{title: "ObjectBindingPattern#3", input: "function f({a = b})"},
{title: "ObjectBindingPattern#4", input: "function f({a: b})"},
{title: "ObjectBindingPattern#5", input: "function f({a: b = c})"},
{title: "ObjectBindingPattern#6", input: "function f({\"a\": b})"},
{title: "ObjectBindingPattern#7", input: "function f({'a': b})"},
{title: "ObjectBindingPattern#8", input: "function f({0: b})"},
{title: "ObjectBindingPattern#9", input: "function f({[a]: b})"},
{title: "ObjectBindingPattern#10", input: "function f({...a})"},
{title: "ObjectBindingPattern#11", input: "function f({a: {}})"},
{title: "ObjectBindingPattern#12", input: "function f({a: []})"},
{title: "ArrayBindingPattern#1", input: "function f([])"},
{title: "ArrayBindingPattern#2", input: "function f([,])"},
{title: "ArrayBindingPattern#3", input: "function f([a])"},
{title: "ArrayBindingPattern#4", input: "function f([a, b])"},
{title: "ArrayBindingPattern#5", input: "function f([a, , b])"},
{title: "ArrayBindingPattern#6", input: "function f([a = b])"},
{title: "ArrayBindingPattern#7", input: "function f([...a])"},
{title: "ArrayBindingPattern#8", input: "function f([{}])"},
{title: "ArrayBindingPattern#9", input: "function f([[]])"},
{title: "TypeParameterDeclaration#1", input: "function f<T>();"},
{title: "TypeParameterDeclaration#2", input: "function f<in T>();"},
{title: "TypeParameterDeclaration#3", input: "function f<T extends U>();"},
{title: "TypeParameterDeclaration#4", input: "function f<T = U>();"},
{title: "TypeParameterDeclaration#5", input: "function f<T extends U = V>();"},
{title: "TypeParameterDeclaration#6", input: "function f<T, U>();"},
{title: "TypeParameterDeclaration#7", input: "function f<T,>();"},
{title: "JsxElement1", input: "<a></a>"},
{title: "JsxElement2", input: "<this></this>"},
{title: "JsxElement3", input: "<a:b></a:b>"},
{title: "JsxElement4", input: "<a.b></a.b>"},
{title: "JsxElement5", input: "<a<b>></a>"},
{title: "JsxElement6", input: "<a b></a>"},
{title: "JsxElement7", input: "<a>b</a>"},
{title: "JsxElement8", input: "<a>{b}</a>"},
{title: "JsxElement9", input: "<a><b></b></a>"},
{title: "JsxElement10", input: "<a><b /></a>"},
{title: "JsxElement11", input: "<a><></></a>"},
{title: "JsxSelfClosingElement1", input: "<a />"},
{title: "JsxSelfClosingElement2", input: "<this />"},
{title: "JsxSelfClosingElement3", input: "<a:b />"},
{title: "JsxSelfClosingElement4", input: "<a.b />"},
{title: "JsxSelfClosingElement5", input: "<a<b> />"},
{title: "JsxSelfClosingElement6", input: "<a b/>"},
{title: "JsxFragment1", input: "<></>"},
{title: "JsxFragment2", input: "<>b</>"},
{title: "JsxFragment3", input: "<>{b}</>"},
{title: "JsxFragment4", input: "<><b></b></>"},
{title: "JsxFragment5", input: "<><b /></>"},
{title: "JsxFragment6", input: "<><></></>"},
{title: "JsxAttribute1", input: "<a b/>"},
{title: "JsxAttribute2", input: "<a b:c/>"},
{title: "JsxAttribute3", input: "<a b=\"c\"/>"},
{title: "JsxAttribute4", input: "<a b='c'/>"},
{title: "JsxAttribute5", input: "<a b={c}/>"},
{title: "JsxAttribute6", input: "<a b=<c></c>/>"},
{title: "JsxAttribute7", input: "<a b=<c />/>"},
{title: "JsxAttribute8", input: "<a b=<></>/>"},
{title: "JsxSpreadAttribute", input: "<a {...b}/>"},
}
for _, rec := range data {
t.Run("Clone "+rec.title, func(t *testing.T) {
t.Parallel()
factory := &ast.NodeFactory{}
file := parsetestutil.ParseTypeScript(rec.input, false).AsNode()
clone := factory.DeepCloneNode(file.AsNode()).AsNode()
work := []NodeComparisonWorkItem{{file, clone}}
for len(work) > 0 {
nextWork := []NodeComparisonWorkItem{}
for _, item := range work {
assert.Assert(t, item.original != item.copy)
originalChildren := getChildren(item.original)
copyChildren := getChildren(item.copy)
assert.Equal(t, len(originalChildren), len(copyChildren))
for i, child := range originalChildren {
nextWork = append(nextWork, NodeComparisonWorkItem{child, copyChildren[i]})
}
}
work = nextWork
}
})
}
}

View File

@@ -0,0 +1,362 @@
package ast
import (
"slices"
"strings"
"sync"
"github.com/microsoft/typescript-go/internal/collections"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/diagnostics"
"github.com/microsoft/typescript-go/internal/locale"
)
// RepopulateDiagnosticKind indicates the kind of repopulation for a diagnostic chain entry.
type RepopulateDiagnosticKind int
const (
RepopulateModeMismatch RepopulateDiagnosticKind = 1
RepopulateModuleNotFound RepopulateDiagnosticKind = 2
)
// RepopulateDiagnosticInfo stores information needed to recompute a diagnostic chain entry
// during incremental builds when the program state may have changed.
type RepopulateDiagnosticInfo struct {
Kind RepopulateDiagnosticKind
ModuleReference string
Mode core.ResolutionMode
PackageName string
}
// Diagnostic
type Diagnostic struct {
file *SourceFile
loc core.TextRange
code int32
category diagnostics.Category
// Original message; may be nil.
message *diagnostics.Message
messageKey diagnostics.Key
messageArgs []string
messageChain []*Diagnostic
relatedInformation []*Diagnostic
reportsUnnecessary bool
reportsDeprecated bool
skippedOnNoEmit bool
repopulateInfo *RepopulateDiagnosticInfo
}
func (d *Diagnostic) File() *SourceFile { return d.file }
func (d *Diagnostic) Pos() int { return d.loc.Pos() }
func (d *Diagnostic) End() int { return d.loc.End() }
func (d *Diagnostic) Len() int { return d.loc.Len() }
func (d *Diagnostic) Loc() core.TextRange { return d.loc }
func (d *Diagnostic) Code() int32 { return d.code }
func (d *Diagnostic) Category() diagnostics.Category { return d.category }
func (d *Diagnostic) MessageKey() diagnostics.Key { return d.messageKey }
func (d *Diagnostic) MessageArgs() []string { return d.messageArgs }
func (d *Diagnostic) MessageChain() []*Diagnostic { return d.messageChain }
func (d *Diagnostic) RelatedInformation() []*Diagnostic { return d.relatedInformation }
func (d *Diagnostic) ReportsUnnecessary() bool { return d.reportsUnnecessary }
func (d *Diagnostic) ReportsDeprecated() bool { return d.reportsDeprecated }
func (d *Diagnostic) SkippedOnNoEmit() bool { return d.skippedOnNoEmit }
func (d *Diagnostic) RepopulateInfo() *RepopulateDiagnosticInfo { return d.repopulateInfo }
func (d *Diagnostic) SetFile(file *SourceFile) { d.file = file }
func (d *Diagnostic) SetLocation(loc core.TextRange) { d.loc = loc }
func (d *Diagnostic) SetCategory(category diagnostics.Category) { d.category = category }
func (d *Diagnostic) SetSkippedOnNoEmit() { d.skippedOnNoEmit = true }
func (d *Diagnostic) SetRepopulateInfo(info *RepopulateDiagnosticInfo) { d.repopulateInfo = info }
func (d *Diagnostic) SetMessageChain(messageChain []*Diagnostic) *Diagnostic {
d.messageChain = messageChain
return d
}
func (d *Diagnostic) AddMessageChain(messageChain *Diagnostic) *Diagnostic {
if messageChain != nil {
d.messageChain = append(d.messageChain, messageChain)
}
return d
}
func (d *Diagnostic) SetRelatedInfo(relatedInformation []*Diagnostic) *Diagnostic {
d.relatedInformation = relatedInformation
return d
}
func (d *Diagnostic) AddRelatedInfo(relatedInformation *Diagnostic) *Diagnostic {
if relatedInformation != nil {
d.relatedInformation = append(d.relatedInformation, relatedInformation)
}
return d
}
func (d *Diagnostic) Clone() *Diagnostic {
result := *d
return &result
}
func (d *Diagnostic) Localize(locale locale.Locale) string {
return diagnostics.Localize(locale, d.message, d.messageKey, d.messageArgs...)
}
// For debugging only.
func (d *Diagnostic) String() string {
return diagnostics.Localize(locale.Default, d.message, d.messageKey, d.messageArgs...)
}
func NewDiagnosticFromSerialized(
file *SourceFile,
loc core.TextRange,
code int32,
category diagnostics.Category,
messageKey diagnostics.Key,
messageArgs []string,
messageChain []*Diagnostic,
relatedInformation []*Diagnostic,
reportsUnnecessary bool,
reportsDeprecated bool,
skippedOnNoEmit bool,
) *Diagnostic {
return &Diagnostic{
file: file,
loc: loc,
code: code,
category: category,
messageKey: messageKey,
messageArgs: messageArgs,
messageChain: messageChain,
relatedInformation: relatedInformation,
reportsUnnecessary: reportsUnnecessary,
reportsDeprecated: reportsDeprecated,
skippedOnNoEmit: skippedOnNoEmit,
}
}
func NewDiagnostic(file *SourceFile, loc core.TextRange, message *diagnostics.Message, args ...any) *Diagnostic {
return &Diagnostic{
file: file,
loc: loc,
code: message.Code(),
category: message.Category(),
message: message,
messageKey: message.Key(),
messageArgs: diagnostics.StringifyArgs(args),
reportsUnnecessary: message.ReportsUnnecessary(),
reportsDeprecated: message.ReportsDeprecated(),
}
}
func NewDiagnosticChain(chain *Diagnostic, message *diagnostics.Message, args ...any) *Diagnostic {
if chain != nil {
return NewDiagnostic(chain.file, chain.loc, message, args...).AddMessageChain(chain).SetRelatedInfo(chain.relatedInformation)
}
return NewDiagnostic(nil, core.TextRange{}, message, args...)
}
func NewCompilerDiagnostic(message *diagnostics.Message, args ...any) *Diagnostic {
return NewDiagnostic(nil, core.UndefinedTextRange(), message, args...)
}
type DiagnosticsCollection struct {
mu sync.Mutex
count int
fileDiagnostics map[string][]*Diagnostic
fileDiagnosticsSorted collections.Set[string]
nonFileDiagnostics []*Diagnostic
nonFileDiagnosticsSorted bool
}
func (c *DiagnosticsCollection) Add(diagnostic *Diagnostic) {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
if diagnostic.File() != nil {
fileName := diagnostic.File().FileName()
if c.fileDiagnostics == nil {
c.fileDiagnostics = make(map[string][]*Diagnostic)
}
c.fileDiagnostics[fileName] = append(c.fileDiagnostics[fileName], diagnostic)
c.fileDiagnosticsSorted.Delete(fileName)
} else {
c.nonFileDiagnostics = append(c.nonFileDiagnostics, diagnostic)
c.nonFileDiagnosticsSorted = false
}
}
func (c *DiagnosticsCollection) Lookup(diagnostic *Diagnostic) *Diagnostic {
c.mu.Lock()
defer c.mu.Unlock()
var diagnostics []*Diagnostic
if diagnostic.File() != nil {
diagnostics = c.getDiagnosticsForFileLocked(diagnostic.File().FileName())
} else {
diagnostics = c.getGlobalDiagnosticsLocked()
}
if i, ok := slices.BinarySearchFunc(diagnostics, diagnostic, CompareDiagnostics); ok {
return diagnostics[i]
}
return nil
}
func (c *DiagnosticsCollection) GetGlobalDiagnostics() []*Diagnostic {
c.mu.Lock()
defer c.mu.Unlock()
return c.getGlobalDiagnosticsLocked()
}
func (c *DiagnosticsCollection) getGlobalDiagnosticsLocked() []*Diagnostic {
if !c.nonFileDiagnosticsSorted {
slices.SortStableFunc(c.nonFileDiagnostics, CompareDiagnostics)
c.nonFileDiagnosticsSorted = true
}
return slices.Clone(c.nonFileDiagnostics)
}
func (c *DiagnosticsCollection) GetDiagnosticsForFile(fileName string) []*Diagnostic {
c.mu.Lock()
defer c.mu.Unlock()
return c.getDiagnosticsForFileLocked(fileName)
}
func (c *DiagnosticsCollection) getDiagnosticsForFileLocked(fileName string) []*Diagnostic {
if !c.fileDiagnosticsSorted.Has(fileName) {
slices.SortStableFunc(c.fileDiagnostics[fileName], CompareDiagnostics)
c.fileDiagnosticsSorted.Add(fileName)
}
return slices.Clone(c.fileDiagnostics[fileName])
}
func (c *DiagnosticsCollection) GetDiagnostics() []*Diagnostic {
c.mu.Lock()
defer c.mu.Unlock()
diagnostics := make([]*Diagnostic, 0, c.count)
diagnostics = append(diagnostics, c.nonFileDiagnostics...)
for _, diags := range c.fileDiagnostics {
diagnostics = append(diagnostics, diags...)
}
slices.SortFunc(diagnostics, CompareDiagnostics)
return diagnostics
}
func getDiagnosticPath(d *Diagnostic) string {
if d.File() != nil {
return d.File().FileName()
}
return ""
}
func EqualDiagnostics(d1, d2 *Diagnostic) bool {
if d1 == d2 {
return true
}
return EqualDiagnosticsNoRelatedInfo(d1, d2) &&
slices.EqualFunc(d1.RelatedInformation(), d2.RelatedInformation(), EqualDiagnostics)
}
func EqualDiagnosticsNoRelatedInfo(d1, d2 *Diagnostic) bool {
if d1 == d2 {
return true
}
return getDiagnosticPath(d1) == getDiagnosticPath(d2) &&
d1.Loc() == d2.Loc() &&
d1.Code() == d2.Code() &&
slices.Equal(d1.MessageArgs(), d2.MessageArgs()) &&
slices.EqualFunc(d1.MessageChain(), d2.MessageChain(), equalMessageChain)
}
func equalMessageChain(c1, c2 *Diagnostic) bool {
if c1 == c2 {
return true
}
return c1.Code() == c2.Code() &&
slices.Equal(c1.MessageArgs(), c2.MessageArgs()) &&
slices.EqualFunc(c1.MessageChain(), c2.MessageChain(), equalMessageChain)
}
func compareMessageChainSize(c1, c2 []*Diagnostic) int {
c := len(c2) - len(c1)
if c != 0 {
return c
}
for i := range c1 {
c = compareMessageChainSize(c1[i].MessageChain(), c2[i].MessageChain())
if c != 0 {
return c
}
}
return 0
}
func compareMessageChainContent(c1, c2 []*Diagnostic) int {
for i := range c1 {
c := slices.Compare(c1[i].MessageArgs(), c2[i].MessageArgs())
if c != 0 {
return c
}
if c1[i].MessageChain() != nil {
c = compareMessageChainContent(c1[i].MessageChain(), c2[i].MessageChain())
if c != 0 {
return c
}
}
}
return 0
}
func compareRelatedInfo(r1, r2 []*Diagnostic) int {
c := len(r2) - len(r1)
if c != 0 {
return c
}
for i := range r1 {
c = CompareDiagnostics(r1[i], r2[i])
if c != 0 {
return c
}
}
return 0
}
func CompareDiagnostics(d1, d2 *Diagnostic) int {
if d1 == d2 {
return 0
}
c := strings.Compare(getDiagnosticPath(d1), getDiagnosticPath(d2))
if c != 0 {
return c
}
c = d1.Loc().Pos() - d2.Loc().Pos()
if c != 0 {
return c
}
c = d1.Loc().End() - d2.Loc().End()
if c != 0 {
return c
}
c = int(d1.Code()) - int(d2.Code())
if c != 0 {
return c
}
c = slices.Compare(d1.MessageArgs(), d2.MessageArgs())
if c != 0 {
return c
}
c = compareMessageChainSize(d1.MessageChain(), d2.MessageChain())
if c != 0 {
return c
}
c = compareMessageChainContent(d1.MessageChain(), d2.MessageChain())
if c != 0 {
return c
}
return compareRelatedInfo(d1.RelatedInformation(), d2.RelatedInformation())
}

View File

@@ -0,0 +1,75 @@
package ast
// FlowFlags
type FlowFlags uint32
const (
FlowFlagsUnreachable FlowFlags = 1 << 0 // Unreachable code
FlowFlagsStart FlowFlags = 1 << 1 // Start of flow graph
FlowFlagsBranchLabel FlowFlags = 1 << 2 // Non-looping junction
FlowFlagsLoopLabel FlowFlags = 1 << 3 // Looping junction
FlowFlagsAssignment FlowFlags = 1 << 4 // Assignment
FlowFlagsTrueCondition FlowFlags = 1 << 5 // Condition known to be true
FlowFlagsFalseCondition FlowFlags = 1 << 6 // Condition known to be false
FlowFlagsSwitchClause FlowFlags = 1 << 7 // Switch statement clause
FlowFlagsArrayMutation FlowFlags = 1 << 8 // Potential array mutation
FlowFlagsCall FlowFlags = 1 << 9 // Potential assertion call
FlowFlagsReduceLabel FlowFlags = 1 << 10 // Temporarily reduce antecedents of label
FlowFlagsReferenced FlowFlags = 1 << 11 // Referenced as antecedent once
FlowFlagsShared FlowFlags = 1 << 12 // Referenced as antecedent more than once
FlowFlagsLabel = FlowFlagsBranchLabel | FlowFlagsLoopLabel
FlowFlagsCondition = FlowFlagsTrueCondition | FlowFlagsFalseCondition
)
// FlowNode
type FlowNode struct {
Flags FlowFlags
Node *Node // Associated AST node
Antecedent *FlowNode // Antecedent for all but FlowLabel
Antecedents *FlowList // Linked list of antecedents for FlowLabel
}
type FlowList struct {
Flow *FlowNode
Next *FlowList
}
type FlowLabel = FlowNode
// FlowSwitchClauseData (synthetic AST node for FlowFlagsSwitchClause)
type FlowSwitchClauseData struct {
NodeBase
SwitchStatement *Node
ClauseStart int32 // Start index of case/default clause range
ClauseEnd int32 // End index of case/default clause range
}
func NewFlowSwitchClauseData(switchStatement *Node, clauseStart int, clauseEnd int) *Node {
node := &FlowSwitchClauseData{}
node.SwitchStatement = switchStatement
node.ClauseStart = int32(clauseStart)
node.ClauseEnd = int32(clauseEnd)
return newNode(KindUnknown, node, NodeFactoryHooks{})
}
func (node *FlowSwitchClauseData) IsEmpty() bool {
return node.ClauseStart == node.ClauseEnd
}
// FlowReduceLabelData (synthetic AST node for FlowFlagsReduceLabel)
type FlowReduceLabelData struct {
NodeBase
Target *FlowLabel // Target label
Antecedents *FlowList // Temporary antecedent list
}
func NewFlowReduceLabelData(target *FlowLabel, antecedents *FlowList) *Node {
node := &FlowReduceLabelData{}
node.Target = target
node.Antecedents = antecedents
return newNode(KindUnknown, node, NodeFactoryHooks{})
}

View File

@@ -0,0 +1,37 @@
package ast
type FunctionFlags uint32
const (
FunctionFlagsNormal FunctionFlags = 0
FunctionFlagsGenerator FunctionFlags = 1 << 0
FunctionFlagsAsync FunctionFlags = 1 << 1
FunctionFlagsInvalid FunctionFlags = 1 << 2
FunctionFlagsAsyncGenerator FunctionFlags = FunctionFlagsAsync | FunctionFlagsGenerator
)
func GetFunctionFlags(node *Node) FunctionFlags {
if node == nil {
return FunctionFlagsInvalid
}
data := node.BodyData()
if data == nil {
return FunctionFlagsInvalid
}
flags := FunctionFlagsNormal
switch node.Kind {
case KindFunctionDeclaration, KindFunctionExpression, KindMethodDeclaration:
if data.AsteriskToken != nil {
flags |= FunctionFlagsGenerator
}
fallthrough
case KindArrowFunction:
if HasSyntacticModifier(node, ModifierFlagsAsync) {
flags |= FunctionFlagsAsync
}
}
if data.Body == nil {
flags |= FunctionFlagsInvalid
}
return flags
}

View File

@@ -0,0 +1,6 @@
package ast
type (
NodeId uint64
SymbolId uint64
)

View File

@@ -0,0 +1,463 @@
// Code generated by _scripts/generate-go-ast.ts. DO NOT EDIT.
package ast
//go:generate go tool golang.org/x/tools/cmd/stringer -type=Kind -output=kind_stringer_generated.go
//go:generate npx dprint fmt kind_stringer_generated.go
type Kind int16
const (
KindUnknown Kind = iota
KindEndOfFile
KindSingleLineCommentTrivia
KindMultiLineCommentTrivia
KindNewLineTrivia
KindWhitespaceTrivia
KindConflictMarkerTrivia
KindNonTextFileMarkerTrivia
KindNumericLiteral
KindBigIntLiteral
KindStringLiteral
KindJsxText
KindJsxTextAllWhiteSpaces
KindRegularExpressionLiteral
KindNoSubstitutionTemplateLiteral
// Pseudo-literals
KindTemplateHead
KindTemplateMiddle
KindTemplateTail
// Punctuation
KindOpenBraceToken
KindCloseBraceToken
KindOpenParenToken
KindCloseParenToken
KindOpenBracketToken
KindCloseBracketToken
KindDotToken
KindDotDotDotToken
KindSemicolonToken
KindCommaToken
KindQuestionDotToken
KindLessThanToken
KindLessThanSlashToken
KindGreaterThanToken
KindLessThanEqualsToken
KindGreaterThanEqualsToken
KindEqualsEqualsToken
KindExclamationEqualsToken
KindEqualsEqualsEqualsToken
KindExclamationEqualsEqualsToken
KindEqualsGreaterThanToken
KindPlusToken
KindMinusToken
KindAsteriskToken
KindAsteriskAsteriskToken
KindSlashToken
KindPercentToken
KindPlusPlusToken
KindMinusMinusToken
KindLessThanLessThanToken
KindGreaterThanGreaterThanToken
KindGreaterThanGreaterThanGreaterThanToken
KindAmpersandToken
KindBarToken
KindCaretToken
KindExclamationToken
KindTildeToken
KindAmpersandAmpersandToken
KindBarBarToken
KindQuestionToken
KindColonToken
KindAtToken
KindQuestionQuestionToken
// Only the JSDoc scanner produces BacktickToken. The normal scanner produces NoSubstitutionTemplateLiteral and related kinds.
KindBacktickToken
// Only the JSDoc scanner produces HashToken. The normal scanner produces PrivateIdentifier.
KindHashToken
// Assignments
KindEqualsToken
KindPlusEqualsToken
KindMinusEqualsToken
KindAsteriskEqualsToken
KindAsteriskAsteriskEqualsToken
KindSlashEqualsToken
KindPercentEqualsToken
KindLessThanLessThanEqualsToken
KindGreaterThanGreaterThanEqualsToken
KindGreaterThanGreaterThanGreaterThanEqualsToken
KindAmpersandEqualsToken
KindBarEqualsToken
KindBarBarEqualsToken
KindAmpersandAmpersandEqualsToken
KindQuestionQuestionEqualsToken
KindCaretEqualsToken
// Identifiers and PrivateIdentifier
KindIdentifier
KindPrivateIdentifier
KindJSDocCommentTextToken
// Reserved words
KindBreakKeyword
KindCaseKeyword
KindCatchKeyword
KindClassKeyword
KindConstKeyword
KindContinueKeyword
KindDebuggerKeyword
KindDefaultKeyword
KindDeleteKeyword
KindDoKeyword
KindElseKeyword
KindEnumKeyword
KindExportKeyword
KindExtendsKeyword
KindFalseKeyword
KindFinallyKeyword
KindForKeyword
KindFunctionKeyword
KindIfKeyword
KindImportKeyword
KindInKeyword
KindInstanceOfKeyword
KindNewKeyword
KindNullKeyword
KindReturnKeyword
KindSuperKeyword
KindSwitchKeyword
KindThisKeyword
KindThrowKeyword
KindTrueKeyword
KindTryKeyword
KindTypeOfKeyword
KindVarKeyword
KindVoidKeyword
KindWhileKeyword
KindWithKeyword
// Strict mode reserved words
KindImplementsKeyword
KindInterfaceKeyword
KindLetKeyword
KindPackageKeyword
KindPrivateKeyword
KindProtectedKeyword
KindPublicKeyword
KindStaticKeyword
KindYieldKeyword
// Contextual keywords
KindAbstractKeyword
KindAccessorKeyword
KindAsKeyword
KindAssertsKeyword
KindAssertKeyword
KindAnyKeyword
KindAsyncKeyword
KindAwaitKeyword
KindBooleanKeyword
KindConstructorKeyword
KindDeclareKeyword
KindGetKeyword
KindImmediateKeyword
KindInferKeyword
KindIntrinsicKeyword
KindIsKeyword
KindKeyOfKeyword
KindModuleKeyword
KindNamespaceKeyword
KindNeverKeyword
KindOutKeyword
KindReadonlyKeyword
KindRequireKeyword
KindNumberKeyword
KindObjectKeyword
KindSatisfiesKeyword
KindSetKeyword
KindStringKeyword
KindSymbolKeyword
KindTypeKeyword
KindUndefinedKeyword
KindUniqueKeyword
KindUnknownKeyword
KindUsingKeyword
KindFromKeyword
KindGlobalKeyword
KindBigIntKeyword
KindOverrideKeyword
KindOfKeyword
KindDeferKeyword // LastKeyword and LastToken and LastContextualKeyword
// Parse tree nodes
// Names
KindQualifiedName
KindComputedPropertyName
// Signature elements
KindTypeParameter
KindParameter
KindDecorator
// TypeMember
KindPropertySignature
KindPropertyDeclaration
KindMethodSignature
KindMethodDeclaration
KindClassStaticBlockDeclaration
KindConstructor
KindGetAccessor
KindSetAccessor
KindCallSignature
KindConstructSignature
KindIndexSignature
// Type
KindTypePredicate
KindTypeReference
KindFunctionType
KindConstructorType
KindTypeQuery
KindTypeLiteral
KindArrayType
KindTupleType
KindOptionalType
KindRestType
KindUnionType
KindIntersectionType
KindConditionalType
KindInferType
KindParenthesizedType
KindThisType
KindTypeOperator
KindIndexedAccessType
KindMappedType
KindLiteralType
KindNamedTupleMember
KindTemplateLiteralType
KindTemplateLiteralTypeSpan
KindImportType
// Binding patterns
KindObjectBindingPattern
KindArrayBindingPattern
KindBindingElement
// Expression
KindArrayLiteralExpression
KindObjectLiteralExpression
KindPropertyAccessExpression
KindElementAccessExpression
KindCallExpression
KindNewExpression
KindTaggedTemplateExpression
KindTypeAssertionExpression
KindParenthesizedExpression
KindFunctionExpression
KindArrowFunction
KindDeleteExpression
KindTypeOfExpression
KindVoidExpression
KindAwaitExpression
KindPrefixUnaryExpression
KindPostfixUnaryExpression
KindBinaryExpression
KindConditionalExpression
KindTemplateExpression
KindYieldExpression
KindSpreadElement
KindClassExpression
KindOmittedExpression
KindExpressionWithTypeArguments
KindAsExpression
KindNonNullExpression
KindMetaProperty
KindSyntheticExpression
KindSatisfiesExpression
// Misc
KindTemplateSpan
KindSemicolonClassElement
// Element
KindBlock
KindEmptyStatement
KindVariableStatement
KindExpressionStatement
KindIfStatement
KindDoStatement
KindWhileStatement
KindForStatement
KindForInStatement
KindForOfStatement
KindContinueStatement
KindBreakStatement
KindReturnStatement
KindWithStatement
KindSwitchStatement
KindLabeledStatement
KindThrowStatement
KindTryStatement
KindDebuggerStatement
KindVariableDeclaration
KindVariableDeclarationList
KindFunctionDeclaration
KindClassDeclaration
KindInterfaceDeclaration
KindTypeAliasDeclaration
KindEnumDeclaration
KindModuleDeclaration
KindModuleBlock
KindCaseBlock
KindNamespaceExportDeclaration
KindImportEqualsDeclaration
KindImportDeclaration
KindImportClause
KindNamespaceImport
KindNamedImports
KindImportSpecifier
KindExportAssignment
KindExportDeclaration
KindNamedExports
KindNamespaceExport
KindExportSpecifier
KindMissingDeclaration
// Module references
KindExternalModuleReference
// JSX
KindJsxElement
KindJsxSelfClosingElement
KindJsxOpeningElement
KindJsxClosingElement
KindJsxFragment
KindJsxOpeningFragment
KindJsxClosingFragment
KindJsxAttribute
KindJsxAttributes
KindJsxSpreadAttribute
KindJsxExpression
KindJsxNamespacedName
// Clauses
KindCaseClause
KindDefaultClause
KindHeritageClause
KindCatchClause
// Import attributes
KindImportAttributes
KindImportAttribute
// Property assignments
KindPropertyAssignment
KindShorthandPropertyAssignment
KindSpreadAssignment
// Enum
KindEnumMember
// Top-level nodes
KindSourceFile
// JSDoc nodes
KindJSDocTypeExpression
KindJSDocNameReference
KindJSDocAllType // The * type
KindJSDocNullableType
KindJSDocNonNullableType
KindJSDocOptionalType
KindJSDocVariadicType
KindJSDoc
KindJSDocText
KindJSDocTypeLiteral
KindJSDocSignature
KindJSDocLink
KindJSDocLinkCode
KindJSDocLinkPlain
KindJSDocUnknownTag
KindJSDocAugmentsTag
KindJSDocImplementsTag
KindJSDocDeprecatedTag
KindJSDocPublicTag
KindJSDocPrivateTag
KindJSDocProtectedTag
KindJSDocReadonlyTag
KindJSDocOverrideTag
KindJSDocCallbackTag
KindJSDocOverloadTag
KindJSDocParameterTag
KindJSDocReturnTag
KindJSDocThisTag
KindJSDocTypeTag
KindJSDocTemplateTag
KindJSDocTypedefTag
KindJSDocSeeTag
KindJSDocPropertyTag
KindJSDocThrowsTag
KindJSDocSatisfiesTag
KindJSDocImportTag
// Synthesized list
KindSyntaxList
// Reparsed JS nodes
KindJSTypeAliasDeclaration
KindJSImportDeclaration
// Transformation nodes
KindNotEmittedStatement
KindPartiallyEmittedExpression
KindSyntheticReferenceExpression
KindNotEmittedTypeElement
KindCount
KindFirstAssignment = KindEqualsToken
KindLastAssignment = KindCaretEqualsToken
KindFirstCompoundAssignment = KindPlusEqualsToken
KindLastCompoundAssignment = KindCaretEqualsToken
KindFirstReservedWord = KindBreakKeyword
KindLastReservedWord = KindWithKeyword
KindFirstKeyword = KindBreakKeyword
KindLastKeyword = KindDeferKeyword
KindFirstFutureReservedWord = KindImplementsKeyword
KindLastFutureReservedWord = KindYieldKeyword
KindFirstTypeNode = KindTypePredicate
KindLastTypeNode = KindImportType
KindFirstPunctuation = KindOpenBraceToken
KindLastPunctuation = KindCaretEqualsToken
KindFirstToken = KindUnknown
KindLastToken = KindLastKeyword
KindFirstLiteralToken = KindNumericLiteral
KindLastLiteralToken = KindNoSubstitutionTemplateLiteral
KindFirstTemplateToken = KindNoSubstitutionTemplateLiteral
KindLastTemplateToken = KindTemplateTail
KindFirstBinaryOperator = KindLessThanToken
KindLastBinaryOperator = KindCaretEqualsToken
KindFirstStatement = KindVariableStatement
KindLastStatement = KindDebuggerStatement
KindFirstNode = KindQualifiedName
KindFirstJSDocNode = KindJSDocTypeExpression
KindLastJSDocNode = KindJSDocImportTag
KindFirstJSDocTagNode = KindJSDocUnknownTag
KindLastJSDocTagNode = KindJSDocImportTag
KindFirstContextualKeyword = KindAbstractKeyword
KindLastContextualKeyword = KindDeferKeyword
KindLastUnaryOperator = KindTildeToken
KindFirstTriviaToken = KindSingleLineCommentTrivia
KindLastTriviaToken = KindConflictMarkerTrivia
)
type (
TriviaSyntaxKind = Kind // KindSingleLineCommentTrivia | KindMultiLineCommentTrivia | KindNewLineTrivia | KindWhitespaceTrivia | KindConflictMarkerTrivia
LiteralSyntaxKind = Kind // KindNumericLiteral | KindBigIntLiteral | KindStringLiteral | KindJsxText | KindJsxTextAllWhiteSpaces | KindRegularExpressionLiteral | KindNoSubstitutionTemplateLiteral
PseudoLiteralSyntaxKind = Kind // KindTemplateHead | KindTemplateMiddle | KindTemplateTail
PunctuationSyntaxKind = Kind // KindOpenBraceToken | KindCloseBraceToken | KindOpenParenToken | KindCloseParenToken | KindOpenBracketToken | KindCloseBracketToken | KindDotToken | KindDotDotDotToken | KindSemicolonToken | KindCommaToken | KindQuestionDotToken | KindLessThanToken | KindLessThanSlashToken | KindGreaterThanToken | KindLessThanEqualsToken | KindGreaterThanEqualsToken | KindEqualsEqualsToken | KindExclamationEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindEqualsGreaterThanToken | KindPlusToken | KindMinusToken | KindAsteriskToken | KindAsteriskAsteriskToken | KindSlashToken | KindPercentToken | KindPlusPlusToken | KindMinusMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindExclamationToken | KindTildeToken | KindAmpersandAmpersandToken | KindBarBarToken | KindQuestionToken | KindColonToken | KindAtToken | KindQuestionQuestionToken | KindBacktickToken | KindHashToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskEqualsToken | KindAsteriskAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken | KindCaretEqualsToken
KeywordSyntaxKind = Kind // KindBreakKeyword | KindCaseKeyword | KindCatchKeyword | KindClassKeyword | KindConstKeyword | KindContinueKeyword | KindDebuggerKeyword | KindDefaultKeyword | KindDeleteKeyword | KindDoKeyword | KindElseKeyword | KindEnumKeyword | KindExportKeyword | KindExtendsKeyword | KindFalseKeyword | KindFinallyKeyword | KindForKeyword | KindFunctionKeyword | KindIfKeyword | KindImportKeyword | KindInKeyword | KindInstanceOfKeyword | KindNewKeyword | KindNullKeyword | KindReturnKeyword | KindSuperKeyword | KindSwitchKeyword | KindThisKeyword | KindThrowKeyword | KindTrueKeyword | KindTryKeyword | KindTypeOfKeyword | KindVarKeyword | KindVoidKeyword | KindWhileKeyword | KindWithKeyword | KindImplementsKeyword | KindInterfaceKeyword | KindLetKeyword | KindPackageKeyword | KindPrivateKeyword | KindProtectedKeyword | KindPublicKeyword | KindStaticKeyword | KindYieldKeyword | KindAbstractKeyword | KindAccessorKeyword | KindAsKeyword | KindAssertsKeyword | KindAssertKeyword | KindAnyKeyword | KindAsyncKeyword | KindAwaitKeyword | KindBooleanKeyword | KindConstructorKeyword | KindDeclareKeyword | KindGetKeyword | KindImmediateKeyword | KindInferKeyword | KindIntrinsicKeyword | KindIsKeyword | KindKeyOfKeyword | KindModuleKeyword | KindNamespaceKeyword | KindNeverKeyword | KindOutKeyword | KindReadonlyKeyword | KindRequireKeyword | KindNumberKeyword | KindObjectKeyword | KindSatisfiesKeyword | KindSetKeyword | KindStringKeyword | KindSymbolKeyword | KindTypeKeyword | KindUndefinedKeyword | KindUniqueKeyword | KindUnknownKeyword | KindUsingKeyword | KindFromKeyword | KindGlobalKeyword | KindBigIntKeyword | KindOverrideKeyword | KindOfKeyword | KindDeferKeyword
ModifierSyntaxKind = Kind // KindAbstractKeyword | KindAccessorKeyword | KindAsyncKeyword | KindConstKeyword | KindDeclareKeyword | KindDefaultKeyword | KindExportKeyword | KindInKeyword | KindPrivateKeyword | KindProtectedKeyword | KindPublicKeyword | KindReadonlyKeyword | KindOutKeyword | KindOverrideKeyword | KindStaticKeyword
KeywordTypeSyntaxKind = Kind // KindAnyKeyword | KindBigIntKeyword | KindBooleanKeyword | KindIntrinsicKeyword | KindNeverKeyword | KindNumberKeyword | KindObjectKeyword | KindStringKeyword | KindSymbolKeyword | KindUndefinedKeyword | KindUnknownKeyword | KindVoidKeyword
KeywordExpressionSyntaxKind = Kind // KindNullKeyword | KindTrueKeyword | KindFalseKeyword | KindThisKeyword | KindSuperKeyword | KindImportKeyword
TokenSyntaxKind = Kind // KindUnknown | KindEndOfFile | KindSingleLineCommentTrivia | KindMultiLineCommentTrivia | KindNewLineTrivia | KindWhitespaceTrivia | KindConflictMarkerTrivia | KindNonTextFileMarkerTrivia | KindNumericLiteral | KindBigIntLiteral | KindStringLiteral | KindJsxText | KindJsxTextAllWhiteSpaces | KindRegularExpressionLiteral | KindNoSubstitutionTemplateLiteral | KindTemplateHead | KindTemplateMiddle | KindTemplateTail | KindOpenBraceToken | KindCloseBraceToken | KindOpenParenToken | KindCloseParenToken | KindOpenBracketToken | KindCloseBracketToken | KindDotToken | KindDotDotDotToken | KindSemicolonToken | KindCommaToken | KindQuestionDotToken | KindLessThanToken | KindLessThanSlashToken | KindGreaterThanToken | KindLessThanEqualsToken | KindGreaterThanEqualsToken | KindEqualsEqualsToken | KindExclamationEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindEqualsGreaterThanToken | KindPlusToken | KindMinusToken | KindAsteriskToken | KindAsteriskAsteriskToken | KindSlashToken | KindPercentToken | KindPlusPlusToken | KindMinusMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindExclamationToken | KindTildeToken | KindAmpersandAmpersandToken | KindBarBarToken | KindQuestionToken | KindColonToken | KindAtToken | KindQuestionQuestionToken | KindBacktickToken | KindHashToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskEqualsToken | KindAsteriskAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken | KindCaretEqualsToken | KindIdentifier | KindPrivateIdentifier | KindJSDocCommentTextToken | KindBreakKeyword | KindCaseKeyword | KindCatchKeyword | KindClassKeyword | KindConstKeyword | KindContinueKeyword | KindDebuggerKeyword | KindDefaultKeyword | KindDeleteKeyword | KindDoKeyword | KindElseKeyword | KindEnumKeyword | KindExportKeyword | KindExtendsKeyword | KindFalseKeyword | KindFinallyKeyword | KindForKeyword | KindFunctionKeyword | KindIfKeyword | KindImportKeyword | KindInKeyword | KindInstanceOfKeyword | KindNewKeyword | KindNullKeyword | KindReturnKeyword | KindSuperKeyword | KindSwitchKeyword | KindThisKeyword | KindThrowKeyword | KindTrueKeyword | KindTryKeyword | KindTypeOfKeyword | KindVarKeyword | KindVoidKeyword | KindWhileKeyword | KindWithKeyword | KindImplementsKeyword | KindInterfaceKeyword | KindLetKeyword | KindPackageKeyword | KindPrivateKeyword | KindProtectedKeyword | KindPublicKeyword | KindStaticKeyword | KindYieldKeyword | KindAbstractKeyword | KindAccessorKeyword | KindAsKeyword | KindAssertsKeyword | KindAssertKeyword | KindAnyKeyword | KindAsyncKeyword | KindAwaitKeyword | KindBooleanKeyword | KindConstructorKeyword | KindDeclareKeyword | KindGetKeyword | KindImmediateKeyword | KindInferKeyword | KindIntrinsicKeyword | KindIsKeyword | KindKeyOfKeyword | KindModuleKeyword | KindNamespaceKeyword | KindNeverKeyword | KindOutKeyword | KindReadonlyKeyword | KindRequireKeyword | KindNumberKeyword | KindObjectKeyword | KindSatisfiesKeyword | KindSetKeyword | KindStringKeyword | KindSymbolKeyword | KindTypeKeyword | KindUndefinedKeyword | KindUniqueKeyword | KindUnknownKeyword | KindUsingKeyword | KindFromKeyword | KindGlobalKeyword | KindBigIntKeyword | KindOverrideKeyword | KindOfKeyword | KindDeferKeyword
JsxTokenSyntaxKind = Kind // KindLessThanSlashToken | KindEndOfFile | KindConflictMarkerTrivia | KindJsxText | KindJsxTextAllWhiteSpaces | KindOpenBraceToken | KindLessThanToken
JSDocNodeSyntaxKind = Kind // KindJSDocTypeExpression | KindJSDocNameReference | KindJSDocAllType | KindJSDocNullableType | KindJSDocNonNullableType | KindJSDocOptionalType | KindJSDocVariadicType | KindJSDoc | KindJSDocText | KindJSDocTypeLiteral | KindJSDocSignature | KindJSDocLink | KindJSDocLinkCode | KindJSDocLinkPlain | KindJSDocUnknownTag | KindJSDocAugmentsTag | KindJSDocImplementsTag | KindJSDocDeprecatedTag | KindJSDocPublicTag | KindJSDocPrivateTag | KindJSDocProtectedTag | KindJSDocReadonlyTag | KindJSDocOverrideTag | KindJSDocCallbackTag | KindJSDocOverloadTag | KindJSDocParameterTag | KindJSDocReturnTag | KindJSDocThisTag | KindJSDocTypeTag | KindJSDocTemplateTag | KindJSDocTypedefTag | KindJSDocSeeTag | KindJSDocPropertyTag | KindJSDocThrowsTag | KindJSDocSatisfiesTag | KindJSDocImportTag
ImportPhaseModifierSyntaxKind = Kind // KindTypeKeyword | KindDeferKeyword
PostfixUnaryOperator = Kind // KindPlusPlusToken | KindMinusMinusToken
PrefixUnaryOperator = Kind // KindPlusToken | KindMinusToken | KindTildeToken | KindExclamationToken | KindPlusPlusToken | KindMinusMinusToken
AssignmentOperator = Kind // KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken
BinaryOperator = Kind // KindQuestionQuestionToken | KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindAmpersandAmpersandToken | KindBarBarToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken | KindCommaToken
ExponentiationOperator = Kind // KindAsteriskAsteriskToken
MultiplicativeOperator = Kind // KindAsteriskToken | KindSlashToken | KindPercentToken
MultiplicativeOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken
AdditiveOperator = Kind // KindPlusToken | KindMinusToken
AdditiveOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken
ShiftOperator = Kind // KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken
ShiftOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken
RelationalOperator = Kind // KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword
RelationalOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword
EqualityOperator = Kind // KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken
EqualityOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken
BitwiseOperator = Kind // KindAmpersandToken | KindBarToken | KindCaretToken
BitwiseOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken
LogicalOperator = Kind // KindAmpersandAmpersandToken | KindBarBarToken
LogicalOperatorOrHigher = Kind // KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindAmpersandAmpersandToken | KindBarBarToken
CompoundAssignmentOperator = Kind // KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken
AssignmentOperatorOrHigher = Kind // KindQuestionQuestionToken | KindAsteriskAsteriskToken | KindAsteriskToken | KindSlashToken | KindPercentToken | KindPlusToken | KindMinusToken | KindLessThanLessThanToken | KindGreaterThanGreaterThanToken | KindGreaterThanGreaterThanGreaterThanToken | KindLessThanToken | KindLessThanEqualsToken | KindGreaterThanToken | KindGreaterThanEqualsToken | KindInstanceOfKeyword | KindInKeyword | KindEqualsEqualsToken | KindEqualsEqualsEqualsToken | KindExclamationEqualsEqualsToken | KindExclamationEqualsToken | KindAmpersandToken | KindBarToken | KindCaretToken | KindAmpersandAmpersandToken | KindBarBarToken | KindEqualsToken | KindPlusEqualsToken | KindMinusEqualsToken | KindAsteriskAsteriskEqualsToken | KindAsteriskEqualsToken | KindSlashEqualsToken | KindPercentEqualsToken | KindAmpersandEqualsToken | KindBarEqualsToken | KindCaretEqualsToken | KindLessThanLessThanEqualsToken | KindGreaterThanGreaterThanGreaterThanEqualsToken | KindGreaterThanGreaterThanEqualsToken | KindBarBarEqualsToken | KindAmpersandAmpersandEqualsToken | KindQuestionQuestionEqualsToken
LogicalOrCoalescingAssignmentOperator = Kind // KindAmpersandAmpersandEqualsToken | KindBarBarEqualsToken | KindQuestionQuestionEqualsToken
)

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,53 @@
package ast
type ModifierFlags uint32
const (
ModifierFlagsNone ModifierFlags = 0
// Syntactic/JSDoc modifiers
ModifierFlagsPublic ModifierFlags = 1 << 0 // Property/Method
ModifierFlagsPrivate ModifierFlags = 1 << 1 // Property/Method
ModifierFlagsProtected ModifierFlags = 1 << 2 // Property/Method
ModifierFlagsReadonly ModifierFlags = 1 << 3 // Property/Method
ModifierFlagsOverride ModifierFlags = 1 << 4 // Override method
// Syntactic-only modifiers
ModifierFlagsExport ModifierFlags = 1 << 5 // Declarations
ModifierFlagsAbstract ModifierFlags = 1 << 6 // Class/Method/ConstructSignature
ModifierFlagsAmbient ModifierFlags = 1 << 7 // Declarations (declare keyword)
ModifierFlagsStatic ModifierFlags = 1 << 8 // Property/Method
ModifierFlagsAccessor ModifierFlags = 1 << 9 // Property
ModifierFlagsAsync ModifierFlags = 1 << 10 // Property/Method/Function
ModifierFlagsDefault ModifierFlags = 1 << 11 // Function/Class (export default declaration)
ModifierFlagsConst ModifierFlags = 1 << 12 // Const enum
ModifierFlagsIn ModifierFlags = 1 << 13 // Contravariance modifier
ModifierFlagsOut ModifierFlags = 1 << 14 // Covariance modifier
ModifierFlagsDecorator ModifierFlags = 1 << 15 // Contains a decorator
// JSDoc-only modifiers
ModifierFlagsDeprecated ModifierFlags = 1 << 16 // Deprecated tag
// Cache-only JSDoc-modifiers. Should match order of Syntactic/JSDoc modifiers, above.
ModifierFlagsJSDocPublic ModifierFlags = 1 << 23 // if this value changes, `selectEffectiveModifierFlags` must change accordingly
ModifierFlagsJSDocPrivate ModifierFlags = 1 << 24
ModifierFlagsJSDocProtected ModifierFlags = 1 << 25
ModifierFlagsJSDocReadonly ModifierFlags = 1 << 26
ModifierFlagsJSDocOverride ModifierFlags = 1 << 27
ModifierFlagsHasComputedJSDocModifiers ModifierFlags = 1 << 28 // Indicates the computed modifier flags include modifiers from JSDoc.
ModifierFlagsHasComputedFlags ModifierFlags = 1 << 29 // Modifier flags have been computed
ModifierFlagsSyntacticOrJSDocModifiers = ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsReadonly | ModifierFlagsOverride
ModifierFlagsSyntacticOnlyModifiers = ModifierFlagsExport | ModifierFlagsAmbient | ModifierFlagsAbstract | ModifierFlagsStatic | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault | ModifierFlagsConst | ModifierFlagsIn | ModifierFlagsOut | ModifierFlagsDecorator
ModifierFlagsSyntacticModifiers = ModifierFlagsSyntacticOrJSDocModifiers | ModifierFlagsSyntacticOnlyModifiers
ModifierFlagsJSDocCacheOnlyModifiers = ModifierFlagsJSDocPublic | ModifierFlagsJSDocPrivate | ModifierFlagsJSDocProtected | ModifierFlagsJSDocReadonly | ModifierFlagsJSDocOverride
ModifierFlagsJSDocOnlyModifiers = ModifierFlagsDeprecated
ModifierFlagsNonCacheOnlyModifiers = ModifierFlagsSyntacticOrJSDocModifiers | ModifierFlagsSyntacticOnlyModifiers | ModifierFlagsJSDocOnlyModifiers
ModifierFlagsAccessibilityModifier = ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected
// Accessibility modifiers and 'readonly' can be attached to a parameter in a constructor to make it a property.
ModifierFlagsParameterPropertyModifier = ModifierFlagsAccessibilityModifier | ModifierFlagsReadonly | ModifierFlagsOverride
ModifierFlagsNonPublicAccessibilityModifier = ModifierFlagsPrivate | ModifierFlagsProtected
ModifierFlagsTypeScriptModifier = ModifierFlagsAmbient | ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsReadonly | ModifierFlagsAbstract | ModifierFlagsConst | ModifierFlagsOverride | ModifierFlagsIn | ModifierFlagsOut
ModifierFlagsExportDefault = ModifierFlagsExport | ModifierFlagsDefault
ModifierFlagsAll = ModifierFlagsExport | ModifierFlagsAmbient | ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsStatic | ModifierFlagsReadonly | ModifierFlagsAbstract | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault | ModifierFlagsConst | ModifierFlagsDeprecated | ModifierFlagsOverride | ModifierFlagsIn | ModifierFlagsOut | ModifierFlagsDecorator
ModifierFlagsModifier = ModifierFlagsAll & ^ModifierFlagsDecorator
ModifierFlagsJavaScript = ModifierFlagsExport | ModifierFlagsStatic | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault
)

View File

@@ -0,0 +1,73 @@
package ast
type NodeFlags uint32
const (
NodeFlagsNone NodeFlags = 0
NodeFlagsLet NodeFlags = 1 << 0 // Variable declaration
NodeFlagsConst NodeFlags = 1 << 1 // Variable declaration
NodeFlagsUsing NodeFlags = 1 << 2 // Variable declaration
NodeFlagsReparsed NodeFlags = 1 << 3 // Node was synthesized during parsing
NodeFlagsSynthesized NodeFlags = 1 << 4 // Node was synthesized during transformation
NodeFlagsOptionalChain NodeFlags = 1 << 5 // Chained MemberExpression rooted to a pseudo-OptionalExpression
NodeFlagsExportContext NodeFlags = 1 << 6 // Export context (initialized by binding)
NodeFlagsContainsThis NodeFlags = 1 << 7 // Interface contains references to "this"
NodeFlagsHasImplicitReturn NodeFlags = 1 << 8 // If function implicitly returns on one of codepaths (initialized by binding)
NodeFlagsHasExplicitReturn NodeFlags = 1 << 9 // If function has explicit reachable return on one of codepaths (initialized by binding)
NodeFlagsDisallowInContext NodeFlags = 1 << 10 // If node was parsed in a context where 'in-expressions' are not allowed
NodeFlagsYieldContext NodeFlags = 1 << 11 // If node was parsed in the 'yield' context created when parsing a generator
NodeFlagsDecoratorContext NodeFlags = 1 << 12 // If node was parsed as part of a decorator
NodeFlagsAwaitContext NodeFlags = 1 << 13 // If node was parsed in the 'await' context created when parsing an async function
NodeFlagsDisallowConditionalTypesContext NodeFlags = 1 << 14 // If node was parsed in a context where conditional types are not allowed
NodeFlagsThisNodeHasError NodeFlags = 1 << 15 // If the parser encountered an error when parsing the code that created this node
NodeFlagsJavaScriptFile NodeFlags = 1 << 16 // If node was parsed in a JavaScript
NodeFlagsThisNodeOrAnySubNodesHasError NodeFlags = 1 << 17 // If this node or any of its children had an error
NodeFlagsHasAsyncFunctions NodeFlags = 1 << 18 // If the file has async functions (initialized by binding)
// NodeFlagsHasAggregatedChildData is deprecated. Use `subtreeFacts` instead.
// These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid
// walking the tree if the flags are not set. However, these flags are just a approximation
// (hence why it's named "PossiblyContainsDynamicImport") because once set, the flags never get cleared.
// During editing, if a dynamic import is removed, incremental parsing will *NOT* clear this flag.
// This means that the tree will always be traversed during module resolution, or when looking for external module indicators.
// However, the removal operation should not occur often and in the case of the
// removal, it is likely that users will add the import anyway.
// The advantage of this approach is its simplicity. For the case of batch compilation,
// we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
NodeFlagsPossiblyContainsDynamicImport NodeFlags = 1 << 19
NodeFlagsPossiblyContainsImportMeta NodeFlags = 1 << 20
NodeFlagsHasJSDoc NodeFlags = 1 << 21 // If node has preceding JSDoc comment(s)
NodeFlagsJSDoc NodeFlags = 1 << 22 // If node was parsed inside jsdoc
NodeFlagsAmbient NodeFlags = 1 << 23 // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
NodeFlagsInWithStatement NodeFlags = 1 << 24 // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
NodeFlagsJsonFile NodeFlags = 1 << 25 // If node was parsed in a Json
NodeFlagsPossiblyContainsDeprecatedTag NodeFlags = 1 << 26 // Set during parse if comment text contains '@deprecated'; must confirm via JSDoc lookup
NodeFlagsUnreachable NodeFlags = 1 << 27 // If node is unreachable according to the binder
NodeFlagsReparserTransformedLiteral NodeFlags = 1 << 28 // If node was transformed during parsing, making its' naive text source not match the AST
NodeFlagsBlockScoped = NodeFlagsLet | NodeFlagsConst | NodeFlagsUsing
NodeFlagsConstant = NodeFlagsConst | NodeFlagsUsing
NodeFlagsAwaitUsing = NodeFlagsConst | NodeFlagsUsing // Variable declaration (NOTE: on a single node these flags would otherwise be mutually exclusive)
NodeFlagsReachabilityCheckFlags = NodeFlagsHasImplicitReturn | NodeFlagsHasExplicitReturn
NodeFlagsReachabilityAndEmitFlags = NodeFlagsReachabilityCheckFlags | NodeFlagsHasAsyncFunctions
// Parsing context flags
NodeFlagsContextFlags NodeFlags = NodeFlagsDisallowInContext | NodeFlagsDisallowConditionalTypesContext | NodeFlagsYieldContext | NodeFlagsDecoratorContext | NodeFlagsAwaitContext | NodeFlagsJavaScriptFile | NodeFlagsInWithStatement | NodeFlagsAmbient
// Exclude these flags when parsing a Type
NodeFlagsTypeExcludesFlags NodeFlags = NodeFlagsYieldContext | NodeFlagsAwaitContext
// Represents all flags that are potentially set once and
// never cleared on SourceFiles which get re-used in between incremental parses.
// See the comment above on `PossiblyContainsDynamicImport` and `PossiblyContainsImportMeta`.
NodeFlagsPermanentlySetIncrementalFlags NodeFlags = NodeFlagsPossiblyContainsDynamicImport | NodeFlagsPossiblyContainsImportMeta
// The following flags repurpose other NodeFlags as different meanings for Identifier nodes
NodeFlagsIdentifierHasExtendedUnicodeEscape NodeFlags = NodeFlagsContainsThis // Indicates whether the identifier contains an extended unicode escape sequence
NodeFlagsIdentifierIsInJSDocNamespace NodeFlags = NodeFlagsHasAsyncFunctions // Indicates the identifier is the innermost name of a JSDoc namespace declaration
// The following flag repurposes other NodeFlags for ModuleDeclaration nodes
NodeFlagsNestedNamespace NodeFlags = NodeFlagsOptionalChain // If ModuleDeclaration is a nested namespace (e.g. inner part of A.B.C)
)

View File

@@ -0,0 +1,149 @@
package ast
import (
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/tspath"
)
type SourceFileParseOptions struct {
FileName string
Path tspath.Path
ExternalModuleIndicatorOptions ExternalModuleIndicatorOptions
}
type ExternalModuleIndicatorOptions struct {
JSX bool
Force bool
}
func GetExternalModuleIndicatorOptions(fileName string, options *core.CompilerOptions, metadata SourceFileMetaData) ExternalModuleIndicatorOptions {
if tspath.IsDeclarationFileName(fileName) {
return ExternalModuleIndicatorOptions{}
}
switch options.GetEmitModuleDetectionKind() {
case core.ModuleDetectionKindForce:
// All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule
return ExternalModuleIndicatorOptions{Force: true}
case core.ModuleDetectionKindLegacy:
// Files are modules if they have imports, exports, or import.meta
return ExternalModuleIndicatorOptions{}
case core.ModuleDetectionKindAuto:
// If module is nodenext or node16, all esm format files are modules
// If jsx is react-jsx or react-jsxdev then jsx tags force module-ness
// otherwise, the presence of import or export statments (or import.meta) implies module-ness
return ExternalModuleIndicatorOptions{
JSX: options.Jsx == core.JsxEmitReactJSX || options.Jsx == core.JsxEmitReactJSXDev,
Force: isFileForcedToBeModuleByFormat(fileName, options, metadata),
}
default:
return ExternalModuleIndicatorOptions{}
}
}
var isFileForcedToBeModuleByFormatExtensions = []string{tspath.ExtensionCjs, tspath.ExtensionCts, tspath.ExtensionMjs, tspath.ExtensionMts}
func isFileForcedToBeModuleByFormat(fileName string, options *core.CompilerOptions, metadata SourceFileMetaData) bool {
// Excludes declaration files - they still require an explicit `export {}` or the like
// for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files
// that aren't esm-mode (meaning not in a `type: module` scope).
if GetImpliedNodeFormatForEmitWorker(fileName, options.GetEmitModuleKind(), metadata) == core.ModuleKindESNext || tspath.FileExtensionIsOneOf(fileName, isFileForcedToBeModuleByFormatExtensions) {
return true
}
return false
}
func SetExternalModuleIndicator(file *SourceFile, opts ExternalModuleIndicatorOptions) {
file.ExternalModuleIndicator = getExternalModuleIndicator(file, opts)
}
func getExternalModuleIndicator(file *SourceFile, opts ExternalModuleIndicatorOptions) *Node {
if file.ScriptKind == core.ScriptKindJSON {
return nil
}
if node := isFileProbablyExternalModule(file); node != nil {
return node
}
if file.IsDeclarationFile {
return nil
}
if opts.JSX {
if node := isFileModuleFromUsingJSXTag(file); node != nil {
return node
}
}
if opts.Force {
return file.AsNode()
}
return nil
}
func isFileProbablyExternalModule(sourceFile *SourceFile) *Node {
for _, statement := range sourceFile.Statements.Nodes {
if isAnExternalModuleIndicatorNode(statement) {
return statement
}
}
return getImportMetaIfNecessary(sourceFile)
}
func isAnExternalModuleIndicatorNode(node *Node) bool {
return HasSyntacticModifier(node, ModifierFlagsExport) ||
IsImportEqualsDeclaration(node) && IsExternalModuleReference(node.AsImportEqualsDeclaration().ModuleReference) ||
IsImportDeclaration(node) || IsExportAssignment(node) || IsExportDeclaration(node)
}
func getImportMetaIfNecessary(sourceFile *SourceFile) *Node {
if sourceFile.AsNode().Flags&NodeFlagsPossiblyContainsImportMeta != 0 {
return findChildNode(sourceFile.AsNode(), IsImportMeta)
}
return nil
}
func findChildNode(root *Node, check func(*Node) bool) *Node {
var result *Node
var visit func(*Node) bool
visit = func(node *Node) bool {
if check(node) {
result = node
return true
}
return node.ForEachChild(visit)
}
visit(root)
return result
}
func isFileModuleFromUsingJSXTag(file *SourceFile) *Node {
return walkTreeForJSXTags(file.AsNode())
}
// This is a somewhat unavoidable full tree walk to locate a JSX tag - `import.meta` requires the same,
// but we avoid that walk (or parts of it) if at all possible using the `PossiblyContainsImportMeta` node flag.
// Unfortunately, there's no `NodeFlag` space to do the same for JSX.
func walkTreeForJSXTags(node *Node) *Node {
var found *Node
var visitor func(node *Node) bool
visitor = func(node *Node) bool {
if found != nil {
return true
}
if node.SubtreeFacts()&SubtreeContainsJsx == 0 {
return false
}
if IsJsxOpeningLikeElement(node) || IsJsxFragment(node) {
found = node
return true
}
return node.ForEachChild(visitor)
}
visitor(node)
return found
}

View File

@@ -0,0 +1,111 @@
package ast
import (
"unicode/utf8"
"github.com/microsoft/typescript-go/internal/stringutil"
)
// PositionMap provides bidirectional mapping between UTF-8 byte offsets (used by Go)
// and UTF-16 code unit offsets (used by JavaScript/TypeScript).
//
// For ASCII-only text, the two are identical. For text containing non-ASCII characters,
// the offsets diverge because multi-byte UTF-8 sequences map to different numbers of
// UTF-16 code units:
// - U+0000..U+007F: 1 byte in UTF-8, 1 code unit in UTF-16
// - U+0080..U+07FF: 2 bytes in UTF-8, 1 code unit in UTF-16
// - U+0800..U+FFFF: 3 bytes in UTF-8, 1 code unit in UTF-16
// - U+10000..U+10FFFF: 4 bytes in UTF-8, 2 code units in UTF-16 (surrogate pair)
type PositionMap struct {
// asciiOnly is true if the text contains only ASCII characters,
// meaning UTF-8 byte offsets and UTF-16 code unit offsets are identical.
asciiOnly bool
// For each multi-byte character, we store:
// - the UTF-8 byte offset of the character
// - the cumulative delta (utf8Offset - utf16Offset) at that character
// This allows O(log n) conversion in either direction.
//
// entries[i].utf8Pos is the byte offset of the i-th multi-byte character.
// entries[i].delta is the total (utf8 - utf16) difference accumulated
// through and including the i-th multi-byte character.
entries []positionMapEntry
}
type positionMapEntry struct {
utf8Pos int // UTF-8 byte offset AFTER this multi-byte character
delta int // cumulative (utf8 - utf16) offset difference after this character
}
// ComputePositionMap builds a PositionMap for the given text.
func ComputePositionMap(text string) *PositionMap {
pm := &PositionMap{}
delta := 0
for i := 0; i < len(text); {
b := text[i]
if b < utf8.RuneSelf {
i++
continue
}
r, size := stringutil.DecodeJSStringRune(text[i:])
utf16Size := 1
if r >= 0x10000 {
utf16Size = 2
}
delta += size - utf16Size
pm.entries = append(pm.entries, positionMapEntry{utf8Pos: i + size, delta: delta})
i += size
}
pm.asciiOnly = len(pm.entries) == 0
return pm
}
// IsAsciiOnly returns true if the text is ASCII-only,
// meaning UTF-8 and UTF-16 offsets are identical.
func (pm *PositionMap) IsAsciiOnly() bool {
return pm.asciiOnly
}
// UTF8ToUTF16 converts a UTF-8 byte offset to a UTF-16 code unit offset.
func (pm *PositionMap) UTF8ToUTF16(utf8Offset int) int {
if pm.asciiOnly {
return utf8Offset
}
// Binary search: find the last entry where utf8Pos <= utf8Offset
lo, hi := 0, len(pm.entries)
for lo < hi {
mid := lo + (hi-lo)/2
if pm.entries[mid].utf8Pos <= utf8Offset {
lo = mid + 1
} else {
hi = mid
}
}
if lo == 0 {
// Before any multi-byte character
return utf8Offset
}
return utf8Offset - pm.entries[lo-1].delta
}
// UTF16ToUTF8 converts a UTF-16 code unit offset to a UTF-8 byte offset.
func (pm *PositionMap) UTF16ToUTF8(utf16Offset int) int {
if pm.asciiOnly {
return utf16Offset
}
// We need the last entry where (utf8Pos - delta) <= utf16Offset.
// (utf8Pos - delta) is the UTF-16 offset of that entry's character.
lo, hi := 0, len(pm.entries)
for lo < hi {
mid := lo + (hi-lo)/2
utf16Pos := pm.entries[mid].utf8Pos - pm.entries[mid].delta
if utf16Pos <= utf16Offset {
lo = mid + 1
} else {
hi = mid
}
}
if lo == 0 {
return utf16Offset
}
return utf16Offset + pm.entries[lo-1].delta
}

View File

@@ -0,0 +1,225 @@
package ast_test
import (
"os"
"strings"
"testing"
"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/stringutil"
)
func TestPositionMapASCII(t *testing.T) {
t.Parallel()
text := "const x = 1;"
pm := ast.ComputePositionMap(text)
if !pm.IsAsciiOnly() {
t.Fatal("expected ASCII-only")
}
for i := 0; i <= len(text); i++ {
if got := pm.UTF8ToUTF16(i); got != i {
t.Errorf("UTF8ToUTF16(%d) = %d, want %d", i, got, i)
}
if got := pm.UTF16ToUTF8(i); got != i {
t.Errorf("UTF16ToUTF8(%d) = %d, want %d", i, got, i)
}
}
}
func TestPositionMapTwoByte(t *testing.T) {
t.Parallel()
// "café" — é (U+00E9) is 2 bytes UTF-8, 1 code unit UTF-16
text := "const café = 1;\nconst x = 2;"
pm := ast.ComputePositionMap(text)
if pm.IsAsciiOnly() {
t.Fatal("expected non-ASCII")
}
// Everything before é (byte offset 9) should be identity
for i := range 10 {
if got := pm.UTF8ToUTF16(i); got != i {
t.Errorf("before é: UTF8ToUTF16(%d) = %d, want %d", i, got, i)
}
}
// é starts at UTF-8 byte 9, UTF-16 offset 9: same
if got := pm.UTF8ToUTF16(9); got != 9 {
t.Errorf("at é: UTF8ToUTF16(9) = %d, want 9", got)
}
// After é (byte 11 in UTF-8 = code unit 10 in UTF-16), delta is 1
// ' ' after café: UTF-8 byte 11, UTF-16 offset 10
if got := pm.UTF8ToUTF16(11); got != 10 {
t.Errorf("after é: UTF8ToUTF16(11) = %d, want 10", got)
}
// 'x' on second line: UTF-8 byte 23, UTF-16 offset 22
xUTF8 := strings.LastIndex(text, "x")
if got := pm.UTF8ToUTF16(xUTF8); got != xUTF8-1 {
t.Errorf("at x: UTF8ToUTF16(%d) = %d, want %d", xUTF8, got, xUTF8-1)
}
// Reverse: UTF-16 offset 22 should map to UTF-8 byte 23
xUTF16 := xUTF8 - 1
if got := pm.UTF16ToUTF8(xUTF16); got != xUTF8 {
t.Errorf("reverse at x: UTF16ToUTF8(%d) = %d, want %d", xUTF16, got, xUTF8)
}
}
func TestPositionMapFourByte(t *testing.T) {
t.Parallel()
// 🎉 (U+1F389) is 4 bytes UTF-8, 2 code units UTF-16
text := `const a = "🎉";` + "\nconst b = 2;"
pm := ast.ComputePositionMap(text)
if pm.IsAsciiOnly() {
t.Fatal("expected non-ASCII")
}
// 🎉 starts at byte 11 (after `const a = "`)
// UTF-8: bytes 11-14 (4 bytes), UTF-16: units 11-12 (2 code units)
// After 🎉: UTF-8 byte 15, UTF-16 offset 13. Delta = 2.
// 'b' on second line
bUTF8 := strings.LastIndex(text, "b")
bUTF16 := bUTF8 - 2 // delta of 2 from emoji
if got := pm.UTF8ToUTF16(bUTF8); got != bUTF16 {
t.Errorf("at b: UTF8ToUTF16(%d) = %d, want %d", bUTF8, got, bUTF16)
}
if got := pm.UTF16ToUTF8(bUTF16); got != bUTF8 {
t.Errorf("reverse at b: UTF16ToUTF8(%d) = %d, want %d", bUTF16, got, bUTF8)
}
}
func TestPositionMapMultipleNonASCII(t *testing.T) {
t.Parallel()
// Mix of 2-byte and 4-byte characters
// "à" (U+00E0) = 2 bytes UTF-8, 1 code unit UTF-16 (delta +1)
// "🎉" (U+1F389) = 4 bytes UTF-8, 2 code units UTF-16 (delta +2)
text := "à🎉x"
pm := ast.ComputePositionMap(text)
// à: UTF-8 [0,2), UTF-16 [0,1)
// 🎉: UTF-8 [2,6), UTF-16 [1,3)
// x: UTF-8 [6,7), UTF-16 [3,4)
tests := []struct {
utf8 int
utf16 int
}{
{0, 0},
{2, 1}, // start of 🎉
{6, 3}, // x
{7, 4}, // end
}
for _, tt := range tests {
if got := pm.UTF8ToUTF16(tt.utf8); got != tt.utf16 {
t.Errorf("UTF8ToUTF16(%d) = %d, want %d", tt.utf8, got, tt.utf16)
}
if got := pm.UTF16ToUTF8(tt.utf16); got != tt.utf8 {
t.Errorf("UTF16ToUTF8(%d) = %d, want %d", tt.utf16, got, tt.utf8)
}
}
}
func TestPositionMapLoneSurrogateSentinel(t *testing.T) {
t.Parallel()
text := "a" + stringutil.EncodeJSStringRune(0xD800) + "b"
pm := ast.ComputePositionMap(text)
if pm.IsAsciiOnly() {
t.Fatal("expected non-ASCII")
}
if got := pm.UTF8ToUTF16(len(text)); got != 3 {
t.Errorf("UTF8ToUTF16(%d) = %d, want 3", len(text), got)
}
if got := pm.UTF16ToUTF8(2); got != len(text)-1 {
t.Errorf("UTF16ToUTF8(2) = %d, want %d", got, len(text)-1)
}
}
func TestPositionMapRoundtrip(t *testing.T) {
t.Parallel()
text := "let café = \"🎉\"; // naïve"
pm := ast.ComputePositionMap(text)
// Convert every valid UTF-16 position to UTF-8 and back
utf16Len := pm.UTF8ToUTF16(len(text))
for i := 0; i <= utf16Len; i++ {
utf8Pos := pm.UTF16ToUTF8(i)
back := pm.UTF8ToUTF16(utf8Pos)
if back != i {
t.Errorf("roundtrip UTF16->UTF8->UTF16: %d -> %d -> %d", i, utf8Pos, back)
}
}
}
func BenchmarkComputePositionMap_ASCII(b *testing.B) {
// ~10KB of ASCII TypeScript-like code
line := "const variable = someFunction(argument1, argument2);\n"
text := strings.Repeat(line, 200)
b.ResetTimer()
for range b.N {
ast.ComputePositionMap(text)
}
}
func BenchmarkComputePositionMap_NonASCII(b *testing.B) {
// Mix of ASCII and non-ASCII (comments with unicode)
line := "const café = \"héllo wörld 🎉\";\n"
text := strings.Repeat(line, 200)
b.ResetTimer()
for range b.N {
ast.ComputePositionMap(text)
}
}
func BenchmarkUTF8ToUTF16_ASCII(b *testing.B) {
line := "const variable = someFunction(argument1, argument2);\n"
text := strings.Repeat(line, 200)
pm := ast.ComputePositionMap(text)
positions := []int{0, 100, 500, 1000, 5000, len(text) - 1}
b.ResetTimer()
for range b.N {
for _, p := range positions {
pm.UTF8ToUTF16(p)
}
}
}
func BenchmarkUTF8ToUTF16_NonASCII(b *testing.B) {
line := "const café = \"héllo wörld 🎉\";\n"
text := strings.Repeat(line, 200)
pm := ast.ComputePositionMap(text)
positions := []int{0, 100, 500, 1000, 5000, len(text) - 1}
b.ResetTimer()
for range b.N {
for _, p := range positions {
pm.UTF8ToUTF16(p)
}
}
}
func BenchmarkUTF16ToUTF8_NonASCII(b *testing.B) {
line := "const café = \"héllo wörld 🎉\";\n"
text := strings.Repeat(line, 200)
pm := ast.ComputePositionMap(text)
utf16Len := pm.UTF8ToUTF16(len(text))
positions := []int{0, 100, 500, 1000, 3000, utf16Len - 1}
b.ResetTimer()
for range b.N {
for _, p := range positions {
pm.UTF16ToUTF8(p)
}
}
}
func BenchmarkComputePositionMap_CheckerTS(b *testing.B) {
data, err := os.ReadFile("../../_submodules/TypeScript/src/compiler/checker.ts")
if err != nil {
b.Skip("checker.ts not available:", err)
}
text := string(data)
b.ResetTimer()
for range b.N {
ast.ComputePositionMap(text)
}
}

View File

@@ -0,0 +1,717 @@
package ast
import (
"fmt"
)
type OperatorPrecedence int
const (
// Expression:
// AssignmentExpression
// Expression `,` AssignmentExpression
OperatorPrecedenceComma OperatorPrecedence = iota
// NOTE: `Spread` is higher than `Comma` due to how it is parsed in |ElementList|
// SpreadElement:
// `...` AssignmentExpression
OperatorPrecedenceSpread
// AssignmentExpression:
// ConditionalExpression
// YieldExpression
// ArrowFunction
// AsyncArrowFunction
// LeftHandSideExpression `=` AssignmentExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
//
// NOTE: AssignmentExpression is broken down into several precedences due to the requirements
// of the parenthesizer rules.
// AssignmentExpression: YieldExpression
// YieldExpression:
// `yield`
// `yield` AssignmentExpression
// `yield` `*` AssignmentExpression
OperatorPrecedenceYield
// AssignmentExpression: LeftHandSideExpression `=` AssignmentExpression
// AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression
// AssignmentOperator: one of
// `*=` `/=` `%=` `+=` `-=` `<<=` `>>=` `>>>=` `&=` `^=` `|=` `**=`
OperatorPrecedenceAssignment
// NOTE: `Conditional` is considered higher than `Assignment` here, but in reality they have
// the same precedence.
// AssignmentExpression: ConditionalExpression
// ConditionalExpression:
// ShortCircuitExpression
// ShortCircuitExpression `?` AssignmentExpression `:` AssignmentExpression
OperatorPrecedenceConditional
// LogicalORExpression:
// LogicalANDExpression
// LogicalORExpression `||` LogicalANDExpression
OperatorPrecedenceLogicalOR
// LogicalANDExpression:
// BitwiseORExpression
// LogicalANDExprerssion `&&` BitwiseORExpression
OperatorPrecedenceLogicalAND
// BitwiseORExpression:
// BitwiseXORExpression
// BitwiseORExpression `|` BitwiseXORExpression
OperatorPrecedenceBitwiseOR
// BitwiseXORExpression:
// BitwiseANDExpression
// BitwiseXORExpression `^` BitwiseANDExpression
OperatorPrecedenceBitwiseXOR
// BitwiseANDExpression:
// EqualityExpression
// BitwiseANDExpression `&` EqualityExpression
OperatorPrecedenceBitwiseAND
// EqualityExpression:
// RelationalExpression
// EqualityExpression `==` RelationalExpression
// EqualityExpression `!=` RelationalExpression
// EqualityExpression `===` RelationalExpression
// EqualityExpression `!==` RelationalExpression
OperatorPrecedenceEquality
// RelationalExpression:
// ShiftExpression
// RelationalExpression `<` ShiftExpression
// RelationalExpression `>` ShiftExpression
// RelationalExpression `<=` ShiftExpression
// RelationalExpression `>=` ShiftExpression
// RelationalExpression `instanceof` ShiftExpression
// RelationalExpression `in` ShiftExpression
// [+TypeScript] RelationalExpression `as` Type
OperatorPrecedenceRelational
// ShiftExpression:
// AdditiveExpression
// ShiftExpression `<<` AdditiveExpression
// ShiftExpression `>>` AdditiveExpression
// ShiftExpression `>>>` AdditiveExpression
OperatorPrecedenceShift
// AdditiveExpression:
// MultiplicativeExpression
// AdditiveExpression `+` MultiplicativeExpression
// AdditiveExpression `-` MultiplicativeExpression
OperatorPrecedenceAdditive
// MultiplicativeExpression:
// ExponentiationExpression
// MultiplicativeExpression MultiplicativeOperator ExponentiationExpression
// MultiplicativeOperator: one of `*`, `/`, `%`
OperatorPrecedenceMultiplicative
// ExponentiationExpression:
// UnaryExpression
// UpdateExpression `**` ExponentiationExpression
OperatorPrecedenceExponentiation
// UnaryExpression:
// UpdateExpression
// `delete` UnaryExpression
// `void` UnaryExpression
// `typeof` UnaryExpression
// `+` UnaryExpression
// `-` UnaryExpression
// `~` UnaryExpression
// `!` UnaryExpression
// AwaitExpression
// UpdateExpression: // TODO: Do we need to investigate the precedence here?
// `++` UnaryExpression
// `--` UnaryExpression
OperatorPrecedenceUnary
// UpdateExpression:
// LeftHandSideExpression
// LeftHandSideExpression `++`
// LeftHandSideExpression `--`
OperatorPrecedenceUpdate
// LeftHandSideExpression:
// NewExpression
// NewExpression:
// MemberExpression
// `new` NewExpression
OperatorPrecedenceLeftHandSide
// LeftHandSideExpression:
// OptionalExpression
// OptionalExpression:
// MemberExpression OptionalChain
// CallExpression OptionalChain
// OptionalExpression OptionalChain
OperatorPrecedenceOptionalChain
// LeftHandSideExpression:
// CallExpression
// CallExpression:
// CoverCallExpressionAndAsyncArrowHead
// SuperCall
// ImportCall
// CallExpression Arguments
// CallExpression `[` Expression `]`
// CallExpression `.` IdentifierName
// CallExpression TemplateLiteral
// MemberExpression:
// PrimaryExpression
// MemberExpression `[` Expression `]`
// MemberExpression `.` IdentifierName
// MemberExpression TemplateLiteral
// SuperProperty
// MetaProperty
// `new` MemberExpression Arguments
OperatorPrecedenceMember
// TODO: JSXElement?
// PrimaryExpression:
// `this`
// IdentifierReference
// Literal
// ArrayLiteral
// ObjectLiteral
// FunctionExpression
// ClassExpression
// GeneratorExpression
// AsyncFunctionExpression
// AsyncGeneratorExpression
// RegularExpressionLiteral
// TemplateLiteral
OperatorPrecedencePrimary
// PrimaryExpression:
// CoverParenthesizedExpressionAndArrowParameterList
OperatorPrecedenceParentheses
OperatorPrecedenceLowest = OperatorPrecedenceComma
OperatorPrecedenceHighest = OperatorPrecedenceParentheses
OperatorPrecedenceDisallowComma = OperatorPrecedenceYield
// ShortCircuitExpression:
// LogicalORExpression
// CoalesceExpression
// CoalesceExpression:
// CoalesceExpressionHead `??` BitwiseORExpression
// CoalesceExpressionHead:
// CoalesceExpression
// BitwiseORExpression
OperatorPrecedenceCoalesce = OperatorPrecedenceLogicalOR
// -1 is lower than all other precedences. Returning it will cause binary expression
// parsing to stop.
OperatorPrecedenceInvalid OperatorPrecedence = -1
)
func getOperator(expression *Expression) Kind {
switch expression.Kind {
case KindBinaryExpression:
return expression.AsBinaryExpression().OperatorToken.Kind
case KindPrefixUnaryExpression:
return expression.AsPrefixUnaryExpression().Operator
case KindPostfixUnaryExpression:
return expression.AsPostfixUnaryExpression().Operator
default:
return expression.Kind
}
}
// Gets the precedence of an expression
func GetExpressionPrecedence(expression *Expression) OperatorPrecedence {
operator := getOperator(expression)
var flags OperatorPrecedenceFlags
if expression.Kind == KindNewExpression && expression.ArgumentList() == nil {
flags = OperatorPrecedenceFlagsNewWithoutArguments
} else if IsOptionalChain(expression) {
flags = OperatorPrecedenceFlagsOptionalChain
}
return GetOperatorPrecedence(expression.Kind, operator, flags)
}
type OperatorPrecedenceFlags int
const (
OperatorPrecedenceFlagsNone OperatorPrecedenceFlags = 0
OperatorPrecedenceFlagsNewWithoutArguments OperatorPrecedenceFlags = 1 << 0
OperatorPrecedenceFlagsOptionalChain OperatorPrecedenceFlags = 1 << 1
)
// Gets the precedence of an operator
func GetOperatorPrecedence(nodeKind Kind, operatorKind Kind, flags OperatorPrecedenceFlags) OperatorPrecedence {
switch nodeKind {
case KindSpreadElement:
return OperatorPrecedenceSpread
case KindYieldExpression:
return OperatorPrecedenceYield
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
case KindArrowFunction:
return OperatorPrecedenceAssignment
case KindConditionalExpression:
return OperatorPrecedenceConditional
case KindBinaryExpression:
switch operatorKind {
case KindCommaToken:
return OperatorPrecedenceComma
case KindEqualsToken,
KindPlusEqualsToken,
KindMinusEqualsToken,
KindAsteriskAsteriskEqualsToken,
KindAsteriskEqualsToken,
KindSlashEqualsToken,
KindPercentEqualsToken,
KindLessThanLessThanEqualsToken,
KindGreaterThanGreaterThanEqualsToken,
KindGreaterThanGreaterThanGreaterThanEqualsToken,
KindAmpersandEqualsToken,
KindCaretEqualsToken,
KindBarEqualsToken,
KindBarBarEqualsToken,
KindAmpersandAmpersandEqualsToken,
KindQuestionQuestionEqualsToken:
return OperatorPrecedenceAssignment
default:
return GetBinaryOperatorPrecedence(operatorKind)
}
// TODO: Should prefix `++` and `--` be moved to the `Update` precedence?
case KindTypeAssertionExpression,
KindNonNullExpression,
KindPrefixUnaryExpression,
KindTypeOfExpression,
KindVoidExpression,
KindDeleteExpression,
KindAwaitExpression:
return OperatorPrecedenceUnary
case KindPostfixUnaryExpression:
return OperatorPrecedenceUpdate
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
case KindPropertyAccessExpression, KindElementAccessExpression:
if flags&OperatorPrecedenceFlagsOptionalChain != 0 {
return OperatorPrecedenceOptionalChain
}
return OperatorPrecedenceMember
case KindCallExpression:
if flags&OperatorPrecedenceFlagsOptionalChain != 0 {
return OperatorPrecedenceOptionalChain
}
return OperatorPrecedenceMember
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
case KindNewExpression:
if flags&OperatorPrecedenceFlagsNewWithoutArguments != 0 {
return OperatorPrecedenceLeftHandSide
}
return OperatorPrecedenceMember
// !!! By necessity, this differs from the old compiler to better align with ParenthesizerRules. consider backporting
case KindTaggedTemplateExpression, KindMetaProperty, KindExpressionWithTypeArguments:
return OperatorPrecedenceMember
case KindAsExpression,
KindSatisfiesExpression:
return OperatorPrecedenceRelational
case KindThisKeyword,
KindSuperKeyword,
KindImportKeyword,
KindIdentifier,
KindPrivateIdentifier,
KindNullKeyword,
KindTrueKeyword,
KindFalseKeyword,
KindNumericLiteral,
KindBigIntLiteral,
KindStringLiteral,
KindArrayLiteralExpression,
KindObjectLiteralExpression,
KindFunctionExpression,
KindClassExpression,
KindRegularExpressionLiteral,
KindNoSubstitutionTemplateLiteral,
KindTemplateExpression,
KindOmittedExpression,
KindJsxElement,
KindJsxSelfClosingElement,
KindJsxFragment,
KindMissingDeclaration:
return OperatorPrecedencePrimary
// !!! By necessity, this differs from the old compiler to support emit. consider backporting
case KindParenthesizedExpression:
return OperatorPrecedenceParentheses
default:
return OperatorPrecedenceInvalid
}
}
// Gets the precedence of a binary operator
func GetBinaryOperatorPrecedence(operatorKind Kind) OperatorPrecedence {
switch operatorKind {
case KindQuestionQuestionToken:
return OperatorPrecedenceCoalesce
case KindBarBarToken:
return OperatorPrecedenceLogicalOR
case KindAmpersandAmpersandToken:
return OperatorPrecedenceLogicalAND
case KindBarToken:
return OperatorPrecedenceBitwiseOR
case KindCaretToken:
return OperatorPrecedenceBitwiseXOR
case KindAmpersandToken:
return OperatorPrecedenceBitwiseAND
case KindEqualsEqualsToken, KindExclamationEqualsToken, KindEqualsEqualsEqualsToken, KindExclamationEqualsEqualsToken:
return OperatorPrecedenceEquality
case KindLessThanToken, KindGreaterThanToken, KindLessThanEqualsToken, KindGreaterThanEqualsToken,
KindInstanceOfKeyword, KindInKeyword, KindAsKeyword, KindSatisfiesKeyword:
return OperatorPrecedenceRelational
case KindLessThanLessThanToken, KindGreaterThanGreaterThanToken, KindGreaterThanGreaterThanGreaterThanToken:
return OperatorPrecedenceShift
case KindPlusToken, KindMinusToken:
return OperatorPrecedenceAdditive
case KindAsteriskToken, KindSlashToken, KindPercentToken:
return OperatorPrecedenceMultiplicative
case KindAsteriskAsteriskToken:
return OperatorPrecedenceExponentiation
}
// -1 is lower than all other precedences. Returning it will cause binary expression
// parsing to stop.
return OperatorPrecedenceInvalid
}
// Gets the leftmost expression of an expression, e.g. `a` in `a.b`, `a[b]`, `a++`, `a+b`, `a?b:c`, `a as B`, etc.
func GetLeftmostExpression(node *Expression, stopAtCallExpressions bool) *Expression {
for {
switch node.Kind {
case KindPostfixUnaryExpression:
node = node.AsPostfixUnaryExpression().Operand
continue
case KindBinaryExpression:
node = node.AsBinaryExpression().Left
continue
case KindConditionalExpression:
node = node.AsConditionalExpression().Condition
continue
case KindTaggedTemplateExpression:
node = node.AsTaggedTemplateExpression().Tag
continue
case KindCallExpression:
if stopAtCallExpressions {
return node
}
fallthrough
case KindAsExpression,
KindElementAccessExpression,
KindPropertyAccessExpression,
KindNonNullExpression,
KindPartiallyEmittedExpression,
KindSatisfiesExpression:
node = node.Expression()
continue
}
return node
}
}
type TypePrecedence int32
const (
// Conditional precedence (lowest)
//
// Type[Extends]:
// ConditionalTypeNode[?Extends]
//
// ConditionalTypeNode[Extends]:
// [~Extends] UnionTypeNode `extends` Type[+Extends] `?` Type[~Extends] `:` Type[~Extends]
//
TypePrecedenceConditional TypePrecedence = iota
// JSDoc precedence (optional and variadic types)
//
// JSDocType:
// `...`? Type `=`?
TypePrecedenceJSDoc
// Function precedence
//
// Type[Extends]:
// ConditionalTypeNode[?Extends]
// FunctionTypeNode[?Extends]
// ConstructorTypeNode[?Extends]
//
// ConditionalTypeNode[Extends]:
// UnionTypeNode
//
// FunctionTypeNode[Extends]:
// TypeParameters? ArrowParameters `=>` Type[?Extends]
//
// ConstructorTypeNode[Extends]:
// `abstract`? TypeParameters? ArrowParameters `=>` Type[?Extends]
//
TypePrecedenceFunction
// Union precedence
//
// UnionTypeNode:
// `|`? UnionTypeNoBar
//
// UnionTypeNoBar:
// IntersectionTypeNode
// UnionTypeNoBar `|` IntersectionTypeNode
//
TypePrecedenceUnion
// Intersection precedence
//
// IntersectionTypeNode:
// `&`? IntersectionTypeNoAmpersand
//
// IntersectionTypeNoAmpersand:
// TypeOperatorNode
// IntersectionTypeNoAmpersand `&` TypeOperatorNode
//
TypePrecedenceIntersection
// TypeOperatorNode precedence
//
// TypeOperatorNode:
// PostfixType
// InferTypeNode
// `keyof` TypeOperatorNode
// `unique` TypeOperatorNode
// `readonly` PostfixType
//
// InferTypeNode:
// `infer` BindingIdentifier
// `infer` BindingIdentifier `extends` Type[+Extends]
//
TypePrecedenceTypeOperator
// Postfix precedence
//
// PostfixType:
// NonArrayType
// OptionalTypeNode
// ArrayTypeNode
// IndexedAccessTypeNode
//
// OptionalTypeNode:
// PostfixType `?`
//
// ArrayTypeNode:
// PostfixType `[` `]`
//
// IndexedAccessTypeNode:
// PostfixType `[` Type[~Extends] `]`
//
TypePrecedencePostfix
// NonArray precedence (highest)
//
// NonArrayType:
// KeywordType
// LiteralTypeNode
// ThisTypeNode
// ImportType
// TypeQueryNode
// MappedTypeNode
// TypeLiteralNode
// TupleTypeNode
// ParenthesizedTypeNode
// TypePredicateNode
// TypeReferenceNode
// TemplateType
//
// KeywordType: one of
// `any` `unknown` `string` `number` `bigint`
// `symbol` `boolean` `undefined` `never` `object`
// `intrinsic` `void`
//
// LiteralTypeNode:
// StringLiteral
// NoSubstitutionTemplateLiteral
// NumericLiteral
// BigIntLiteral
// `-` NumericLiteral
// `-` BigIntLiteral
// `true`
// `false`
// `null`
//
// ThisTypeNode:
// `this`
//
// ImportType:
// `typeof`? `import` `(` Type[~Extends] `,`? `)` ImportTypeQualifier? TypeArguments?
// `typeof`? `import` `(` Type[~Extends] `,` ImportTypeAttributes `,`? `)` ImportTypeQualifier? TypeArguments?
//
// ImportTypeQualifier:
// `.` EntityName
//
// ImportTypeAttributes:
// `{` `with` `:` ImportAttributes `,`? `}`
//
// TypeQueryNode:
//
// MappedTypeNode:
// `{` MappedTypePrefix? MappedTypePropertyName MappedTypeSuffix? `:` Type[~Extends] `;` `}`
//
// MappedTypePrefix:
// `readonly`
// `+` `readonly`
// `-` `readonly`
//
// MappedTypePropertyName:
// `[` BindingIdentifier `in` Type[~Extends] `]`
// `[` BindingIdentifier `in` Type[~Extends] `as` Type[~Extends] `]`
//
// MappedTypeSuffix:
// `?`
// `+` `?`
// `-` `?`
//
// TypeLiteralNode:
// `{` TypeElementList `}`
//
// TypeElementList:
// [empty]
// TypeElementList TypeElement
//
// TypeElement:
// PropertySignatureDeclaration
// MethodSignatureDeclaration
// IndexSignatureDeclaration
// CallSignatureDeclaration
// ConstructSignatureDeclaration
//
// PropertySignatureDeclaration:
// PropertyName `?`? TypeAnnotation? `;`
//
// MethodSignatureDeclaration:
// PropertyName `?`? TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;`
// `get` PropertyName TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;` // GetAccessorDeclaration
// `set` PropertyName TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;` // SetAccessorDeclaration
//
// IndexSignatureDeclaration:
// `[` IdentifierName`]` TypeAnnotation `;`
//
// CallSignatureDeclaration:
// TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;`
//
// ConstructSignatureDeclaration:
// `new` TypeParameters? `(` FormalParameterList `)` TypeAnnotation? `;`
//
// TupleTypeNode:
// `[` `]`
// `[` NamedTupleElementTypes `,`? `]`
// `[` TupleElementTypes `,`? `]`
//
// NamedTupleElementTypes:
// NamedTupleMember
// NamedTupleElementTypes `,` NamedTupleMember
//
// NamedTupleMember:
// IdentifierName `?`? `:` Type[~Extends]
// `...` IdentifierName `:` Type[~Extends]
//
// TupleElementTypes:
// TupleElementType
// TupleElementTypes `,` TupleElementType
//
// TupleElementType:
// Type[~Extends]
// OptionalTypeNode
// RestTypeNode
//
// RestTypeNode:
// `...` Type[~Extends]
//
// ParenthesizedTypeNode:
// `(` Type[~Extends] `)`
//
// TypePredicateNode:
// `asserts`? TypePredicateParameterName
// `asserts`? TypePredicateParameterName `is` Type[~Extends]
//
// TypePredicateParameterName:
// `this`
// IdentifierReference
//
// TypeReferenceNode:
// EntityName TypeArguments?
//
// TemplateType:
// TemplateHead Type[~Extends] TemplateTypeSpans
//
// TemplateTypeSpans:
// TemplateTail
// TemplateTypeMiddleList TemplateTail
//
// TemplateTypeMiddleList:
// TemplateMiddle Type[~Extends]
// TemplateTypeMiddleList TemplateMiddle Type[~Extends]
//
// TypeArguments:
// `<` TypeArgumentList `,`? `>`
//
// TypeArgumentList:
// Type[~Extends]
// TypeArgumentList `,` Type[~Extends]
//
TypePrecedenceNonArray
TypePrecedenceLowest = TypePrecedenceConditional
TypePrecedenceHighest = TypePrecedenceNonArray
)
// Gets the precedence of a TypeNode
func GetTypeNodePrecedence(n *TypeNode) TypePrecedence {
switch n.Kind {
case KindConditionalType:
return TypePrecedenceConditional
case KindJSDocOptionalType, KindJSDocVariadicType:
return TypePrecedenceJSDoc
case KindFunctionType, KindConstructorType:
return TypePrecedenceFunction
case KindUnionType:
return TypePrecedenceUnion
case KindIntersectionType:
return TypePrecedenceIntersection
case KindTypeOperator:
return TypePrecedenceTypeOperator
case KindInferType:
if n.AsInferTypeNode().TypeParameter.AsTypeParameterDeclaration().Constraint != nil {
// `infer T extends U` must be treated as FunctionTypeNode precedence as the `extends` clause eagerly consumes
// TypeNode
return TypePrecedenceFunction
}
return TypePrecedenceTypeOperator
case KindIndexedAccessType, KindArrayType, KindOptionalType:
return TypePrecedencePostfix
case KindTypeQuery:
// TypeQueryNode is actually a NonArrayType, but we treat it as TypeOperatorNode
// precedence so that it is parenthesized when used in a PostfixType
// context (e.g., `(typeof C)[]` instead of `typeof C[]`)
return TypePrecedenceTypeOperator
case KindAnyKeyword,
KindUnknownKeyword,
KindStringKeyword,
KindNumberKeyword,
KindBigIntKeyword,
KindSymbolKeyword,
KindBooleanKeyword,
KindUndefinedKeyword,
KindNeverKeyword,
KindObjectKeyword,
KindIntrinsicKeyword,
KindVoidKeyword,
KindJSDocAllType,
KindJSDocNullableType,
KindJSDocNonNullableType,
KindLiteralType,
KindTypePredicate,
KindTypeReference,
KindTypeLiteral,
KindTupleType,
KindRestType,
KindParenthesizedType,
KindThisType,
KindMappedType,
KindNamedTupleMember,
KindTemplateLiteralType,
KindImportType,
// These occur in pseudo-types like `f<T>.C`, where `f` is a generic function and `C` is a local type
KindPropertyAccessExpression,
KindExpressionWithTypeArguments:
return TypePrecedenceNonArray
default:
panic(fmt.Sprintf("unhandled TypeNode: %v", n.Kind))
}
}

View File

@@ -0,0 +1,133 @@
package ast
import (
"github.com/microsoft/typescript-go/internal/core"
)
type SubtreeFacts uint32
const (
// Facts
// - Flags used to indicate that a node or subtree contains syntax relevant to a specific transform
SubtreeContainsTypeScript SubtreeFacts = 1 << iota
SubtreeContainsJsx
SubtreeContainsESDecorators
SubtreeContainsUsing
SubtreeContainsClassStaticBlocks
SubtreeContainsESClassFields
SubtreeContainsLogicalAssignments
SubtreeContainsNullishCoalescing
SubtreeContainsOptionalChaining
SubtreeContainsMissingCatchClauseVariable
SubtreeContainsESObjectRestOrSpread // subtree has a `...` somewhere inside it, never cleared
SubtreeContainsForAwaitOrAsyncGenerator
SubtreeContainsAnyAwait
SubtreeContainsExponentiationOperator
// Markers
// - Flags used to indicate that a node or subtree contains a particular kind of syntax.
SubtreeContainsLexicalThis
SubtreeContainsLexicalSuper
SubtreeContainsRestOrSpread // marker on any `...` - cleared on binding pattern exit
SubtreeContainsObjectRestOrSpread // marker on any `{...x}` - cleared on most scope exits
SubtreeContainsAwait
SubtreeContainsDynamicImport
SubtreeContainsClassFields
SubtreeContainsDecorators
SubtreeContainsIdentifier
SubtreeContainsPrivateIdentifierInExpression
SubtreeContainsInvalidTemplateEscape
SubtreeFactsComputed // NOTE: This should always be last
SubtreeFactsNone SubtreeFacts = 0
// Aliases (unused, for documentation purposes only - correspond to combinations in transformers/estransforms/definitions.go)
SubtreeContainsESNext = SubtreeContainsESDecorators | SubtreeContainsUsing
SubtreeContainsES2022 = SubtreeContainsClassStaticBlocks | SubtreeContainsESClassFields
SubtreeContainsES2021 = SubtreeContainsLogicalAssignments
SubtreeContainsES2020 = SubtreeContainsNullishCoalescing | SubtreeContainsOptionalChaining
SubtreeContainsES2019 = SubtreeContainsMissingCatchClauseVariable
SubtreeContainsES2018 = SubtreeContainsESObjectRestOrSpread | SubtreeContainsForAwaitOrAsyncGenerator | SubtreeContainsInvalidTemplateEscape
SubtreeContainsES2017 = SubtreeContainsAnyAwait
SubtreeContainsES2016 = SubtreeContainsExponentiationOperator
// Scope Exclusions
// - Bitmasks that exclude flags from propagating out of a specific context
// into the subtree flags of their container.
SubtreeExclusionsNode = SubtreeFactsComputed
SubtreeExclusionsEraseable = ^SubtreeContainsTypeScript
SubtreeExclusionsOuterExpression = SubtreeExclusionsNode
SubtreeExclusionsPropertyAccess = SubtreeExclusionsNode
SubtreeExclusionsElementAccess = SubtreeExclusionsNode
SubtreeExclusionsArrowFunction = SubtreeExclusionsNode | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsFunction = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsConstructor = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsMethod = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsAccessor = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsProperty = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper
SubtreeExclusionsClass = SubtreeExclusionsNode
SubtreeExclusionsModule = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper
SubtreeExclusionsObjectLiteral = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsArrayLiteral = SubtreeExclusionsNode
SubtreeExclusionsCall = SubtreeExclusionsNode
SubtreeExclusionsNew = SubtreeExclusionsNode
SubtreeExclusionsVariableDeclarationList = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsParameter = SubtreeExclusionsNode
SubtreeExclusionsCatchClause = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread
SubtreeExclusionsBindingPattern = SubtreeExclusionsNode | SubtreeContainsRestOrSpread
// Masks
// - Additional bitmasks
SubtreeContainsLexicalThisOrSuper = SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper
)
func propagateEraseableSyntaxListSubtreeFacts(children *TypeArgumentList) SubtreeFacts {
return core.IfElse(children != nil, SubtreeContainsTypeScript, SubtreeFactsNone)
}
func propagateEraseableSyntaxSubtreeFacts(child *TypeNode) SubtreeFacts {
return core.IfElse(child != nil, SubtreeContainsTypeScript, SubtreeFactsNone)
}
func propagateObjectBindingElementSubtreeFacts(child *BindingElementNode) SubtreeFacts {
facts := propagateSubtreeFacts(child)
if facts&SubtreeContainsRestOrSpread != 0 {
facts &^= SubtreeContainsRestOrSpread
facts |= SubtreeContainsObjectRestOrSpread | SubtreeContainsESObjectRestOrSpread
}
return facts
}
func propagateBindingElementSubtreeFacts(child *BindingElementNode) SubtreeFacts {
return propagateSubtreeFacts(child) & ^SubtreeContainsRestOrSpread
}
func propagateSubtreeFacts(child *Node) SubtreeFacts {
if child == nil {
return SubtreeFactsNone
}
return child.propagateSubtreeFacts()
}
func propagateNodeListSubtreeFacts(children *NodeList, propagate func(*Node) SubtreeFacts) SubtreeFacts {
if children == nil {
return SubtreeFactsNone
}
facts := SubtreeFactsNone
for _, child := range children.Nodes {
facts |= propagate(child)
}
return facts
}
func propagateModifierListSubtreeFacts(children *ModifierList) SubtreeFacts {
if children == nil {
return SubtreeFactsNone
}
return propagateNodeListSubtreeFacts(&children.NodeList, propagateSubtreeFacts)
}

View File

@@ -0,0 +1,103 @@
package ast
import (
"strings"
"sync/atomic"
)
// Symbol
type Symbol struct {
Flags SymbolFlags
CheckFlags CheckFlags // Non-zero only in transient symbols created by Checker
Name string
Declarations []*Node
ValueDeclaration *Node
Members SymbolTable
Exports SymbolTable
id atomic.Uint64
Parent *Symbol
ExportSymbol *Symbol
}
func (s *Symbol) IsExternalModule() bool {
return s.Flags&SymbolFlagsModule != 0 && len(s.Name) > 0 && s.Name[0] == '"'
}
func (s *Symbol) IsStatic() bool {
if s.ValueDeclaration == nil {
return false
}
modifierFlags := s.ValueDeclaration.ModifierFlags()
return modifierFlags&ModifierFlagsStatic != 0
}
// See comment on `declareModuleMember` in `binder.go`.
func (s *Symbol) CombinedLocalAndExportSymbolFlags() SymbolFlags {
if s.ExportSymbol != nil {
return s.Flags | s.ExportSymbol.Flags
}
return s.Flags
}
// SymbolTable
type SymbolTable map[string]*Symbol
const InternalSymbolNamePrefix = "\xFE" // Invalid UTF8 sequence, will never occur as IdentifierName
const (
InternalSymbolNameCall = InternalSymbolNamePrefix + "call" // Call signatures
InternalSymbolNameConstructor = InternalSymbolNamePrefix + "constructor" // Constructor implementations
InternalSymbolNameNew = InternalSymbolNamePrefix + "new" // Constructor signatures
InternalSymbolNameIndex = InternalSymbolNamePrefix + "index" // Index signatures
InternalSymbolNameExportStar = InternalSymbolNamePrefix + "export" // Module export * declarations
InternalSymbolNameGlobal = InternalSymbolNamePrefix + "global" // Global self-reference
InternalSymbolNameMissing = InternalSymbolNamePrefix + "missing" // Indicates missing symbol
InternalSymbolNameType = InternalSymbolNamePrefix + "type" // Anonymous type literal symbol
InternalSymbolNameObject = InternalSymbolNamePrefix + "object" // Anonymous object literal declaration
InternalSymbolNameJSXAttributes = InternalSymbolNamePrefix + "jsxAttributes" // Anonymous JSX attributes object literal declaration
InternalSymbolNameClass = InternalSymbolNamePrefix + "class" // Unnamed class expression
InternalSymbolNameFunction = InternalSymbolNamePrefix + "function" // Unnamed function expression
InternalSymbolNameComputed = InternalSymbolNamePrefix + "computed" // Computed property name declaration with dynamic name
InternalSymbolNameAssignmentDeclaration = InternalSymbolNamePrefix + "assignment" // Assignment declarations
InternalSymbolNameInstantiationExpression = InternalSymbolNamePrefix + "instantiationExpression" // Instantiation expressions
InternalSymbolNameImportAttributes = InternalSymbolNamePrefix + "importAttributes"
InternalSymbolNameExportEquals = "export=" // Export assignment symbol
InternalSymbolNameDefault = "default" // Default export symbol (technically not wholly internal, but included here for usability)
InternalSymbolNameThis = "this"
InternalSymbolNameModuleExports = "module.exports"
)
func SymbolName(symbol *Symbol) string {
if symbol.ValueDeclaration != nil && IsPrivateIdentifierClassElementDeclaration(symbol.ValueDeclaration) {
return symbol.ValueDeclaration.Name().Text()
}
return symbol.Name
}
// EscapeAllInternalSymbolNames replaces internal symbol name markers ("\xFE") with "__".
func EscapeAllInternalSymbolNames(name string) string {
return strings.ReplaceAll(name, InternalSymbolNamePrefix, "__")
}
func EscapeInternalSymbolName(name string) string {
if rest, ok := strings.CutPrefix(name, InternalSymbolNamePrefix); ok {
return "__" + rest
}
return name
}
// EscapeSymbolName converts a binder symbol name into its escaped "__String"
// form. Internal names (prefixed with the "\xFE" sentinel) become "__"-prefixed,
// and user names that already begin with "__" gain an extra leading underscore
// so they can be distinguished from internal names.
func EscapeSymbolName(name string) string {
if rest, ok := strings.CutPrefix(name, InternalSymbolNamePrefix); ok {
return "__" + rest
}
if len(name) >= 2 && name[0] == '_' && name[1] == '_' {
return "_" + name
}
return name
}

View File

@@ -0,0 +1,86 @@
package ast
// SymbolFlags
type SymbolFlags uint32
const (
SymbolFlagsNone SymbolFlags = 0
SymbolFlagsFunctionScopedVariable SymbolFlags = 1 << 0 // Variable (var) or parameter
SymbolFlagsBlockScopedVariable SymbolFlags = 1 << 1 // A block-scoped variable (let or const)
SymbolFlagsProperty SymbolFlags = 1 << 2 // Property or enum member
SymbolFlagsEnumMember SymbolFlags = 1 << 3 // Enum member
SymbolFlagsFunction SymbolFlags = 1 << 4 // Function
SymbolFlagsClass SymbolFlags = 1 << 5 // Class
SymbolFlagsInterface SymbolFlags = 1 << 6 // Interface
SymbolFlagsConstEnum SymbolFlags = 1 << 7 // Const enum
SymbolFlagsRegularEnum SymbolFlags = 1 << 8 // Enum
SymbolFlagsValueModule SymbolFlags = 1 << 9 // Instantiated module
SymbolFlagsNamespaceModule SymbolFlags = 1 << 10 // Uninstantiated module
SymbolFlagsTypeLiteral SymbolFlags = 1 << 11 // Type Literal or mapped type
SymbolFlagsObjectLiteral SymbolFlags = 1 << 12 // Object Literal
SymbolFlagsMethod SymbolFlags = 1 << 13 // Method
SymbolFlagsConstructor SymbolFlags = 1 << 14 // Constructor
SymbolFlagsGetAccessor SymbolFlags = 1 << 15 // Get accessor
SymbolFlagsSetAccessor SymbolFlags = 1 << 16 // Set accessor
SymbolFlagsSignature SymbolFlags = 1 << 17 // Call, construct, or index signature
SymbolFlagsTypeParameter SymbolFlags = 1 << 18 // Type parameter
SymbolFlagsTypeAlias SymbolFlags = 1 << 19 // Type alias
SymbolFlagsExportValue SymbolFlags = 1 << 20 // Exported value marker (see comment in declareModuleMember in binder)
SymbolFlagsAlias SymbolFlags = 1 << 21 // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
SymbolFlagsPrototype SymbolFlags = 1 << 22 // Prototype property (no source representation)
SymbolFlagsExportStar SymbolFlags = 1 << 23 // Export * declaration
SymbolFlagsOptional SymbolFlags = 1 << 24 // Optional property
SymbolFlagsTransient SymbolFlags = 1 << 25 // Transient symbol (created during type check)
SymbolFlagsAssignment SymbolFlags = 1 << 26 // Assignment to property on function acting as declaration (eg `func.prop = 1`)
SymbolFlagsModuleExports SymbolFlags = 1 << 27 // Symbol for CommonJS `module` of `module.exports`
SymbolFlagsConstEnumOnlyModule SymbolFlags = 1 << 28 // Module contains only const enums or other modules with only const enums
SymbolFlagsReplaceableByMethod SymbolFlags = 1 << 29
SymbolFlagsGlobalLookup SymbolFlags = 1 << 30 // Flag to signal this is a global lookup
SymbolFlagsAll SymbolFlags = 1<<30 - 1 // All flags except SymbolFlagsGlobalLookup
SymbolFlagsEnum = SymbolFlagsRegularEnum | SymbolFlagsConstEnum
SymbolFlagsVariable = SymbolFlagsFunctionScopedVariable | SymbolFlagsBlockScopedVariable
SymbolFlagsValue = SymbolFlagsVariable | SymbolFlagsProperty | SymbolFlagsEnumMember | SymbolFlagsObjectLiteral | SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsValueModule | SymbolFlagsMethod | SymbolFlagsGetAccessor | SymbolFlagsSetAccessor
SymbolFlagsType = SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsEnum | SymbolFlagsEnumMember | SymbolFlagsTypeLiteral | SymbolFlagsTypeParameter | SymbolFlagsTypeAlias
SymbolFlagsNamespace = SymbolFlagsValueModule | SymbolFlagsNamespaceModule | SymbolFlagsEnum
SymbolFlagsModule = SymbolFlagsValueModule | SymbolFlagsNamespaceModule
SymbolFlagsAccessor = SymbolFlagsGetAccessor | SymbolFlagsSetAccessor
// Variables can be redeclared, but can not redeclare a block-scoped declaration with the
// same name, or any other value that is not a variable, e.g. ValueModule or Class
SymbolFlagsFunctionScopedVariableExcludes = SymbolFlagsValue & ^SymbolFlagsFunctionScopedVariable
// Block-scoped declarations are not allowed to be re-declared
// they can not merge with anything in the value space
SymbolFlagsBlockScopedVariableExcludes = SymbolFlagsValue
SymbolFlagsParameterExcludes = SymbolFlagsValue
SymbolFlagsPropertyExcludes = SymbolFlagsValue & ^(SymbolFlagsProperty | SymbolFlagsAccessor)
SymbolFlagsEnumMemberExcludes = SymbolFlagsValue | SymbolFlagsType
SymbolFlagsFunctionExcludes = SymbolFlagsValue & ^(SymbolFlagsFunction | SymbolFlagsValueModule | SymbolFlagsClass)
SymbolFlagsClassExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^(SymbolFlagsValueModule | SymbolFlagsInterface | SymbolFlagsFunction) // class-interface mergability done in checker.ts
SymbolFlagsInterfaceExcludes = SymbolFlagsType & ^(SymbolFlagsInterface | SymbolFlagsClass)
SymbolFlagsRegularEnumExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^(SymbolFlagsRegularEnum | SymbolFlagsValueModule) // regular enums merge only with regular enums and modules
SymbolFlagsConstEnumExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^SymbolFlagsConstEnum // const enums merge only with const enums
SymbolFlagsValueModuleExcludes = SymbolFlagsValue & ^(SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsRegularEnum | SymbolFlagsValueModule)
SymbolFlagsNamespaceModuleExcludes = SymbolFlagsNone
SymbolFlagsMethodExcludes = SymbolFlagsValue & ^SymbolFlagsMethod
SymbolFlagsGetAccessorExcludes = SymbolFlagsValue & ^(SymbolFlagsSetAccessor | SymbolFlagsProperty)
SymbolFlagsSetAccessorExcludes = SymbolFlagsValue & ^(SymbolFlagsGetAccessor | SymbolFlagsProperty)
SymbolFlagsAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsProperty
SymbolFlagsTypeParameterExcludes = SymbolFlagsType & ^SymbolFlagsTypeParameter
SymbolFlagsTypeAliasExcludes = SymbolFlagsType
SymbolFlagsAliasExcludes = SymbolFlagsAlias
SymbolFlagsModuleMember = SymbolFlagsVariable | SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsEnum | SymbolFlagsModule | SymbolFlagsTypeAlias | SymbolFlagsAlias
SymbolFlagsExportHasLocal = SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsValueModule
SymbolFlagsBlockScoped = SymbolFlagsBlockScopedVariable | SymbolFlagsClass | SymbolFlagsEnum
SymbolFlagsPropertyOrAccessor = SymbolFlagsProperty | SymbolFlagsAccessor
SymbolFlagsClassMember = SymbolFlagsMethod | SymbolFlagsAccessor | SymbolFlagsProperty
SymbolFlagsExportSupportsDefaultModifier = SymbolFlagsClass | SymbolFlagsFunction | SymbolFlagsInterface
SymbolFlagsExportDoesNotSupportDefaultModifier = ^SymbolFlagsExportSupportsDefaultModifier
// The set of things we consider semantically classifiable. Used to speed up the LS during
// classification.
SymbolFlagsClassifiable = SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsTypeAlias | SymbolFlagsInterface | SymbolFlagsTypeParameter | SymbolFlagsModule | SymbolFlagsAlias
SymbolFlagsLateBindingContainer = SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsTypeLiteral | SymbolFlagsObjectLiteral | SymbolFlagsFunction
)

View File

@@ -0,0 +1,33 @@
package ast
type TokenFlags int32
const (
TokenFlagsNone TokenFlags = 0
TokenFlagsPrecedingLineBreak TokenFlags = 1 << 0
TokenFlagsPrecedingJSDocComment TokenFlags = 1 << 1
TokenFlagsUnterminated TokenFlags = 1 << 2
TokenFlagsExtendedUnicodeEscape TokenFlags = 1 << 3 // e.g. `\u{10ffff}`
TokenFlagsScientific TokenFlags = 1 << 4 // e.g. `10e2`
TokenFlagsOctal TokenFlags = 1 << 5 // e.g. `0777`
TokenFlagsHexSpecifier TokenFlags = 1 << 6 // e.g. `0x00000000`
TokenFlagsBinarySpecifier TokenFlags = 1 << 7 // e.g. `0b0110010000000000`
TokenFlagsOctalSpecifier TokenFlags = 1 << 8 // e.g. `0o777`
TokenFlagsContainsSeparator TokenFlags = 1 << 9 // e.g. `0b1100_0101`
TokenFlagsUnicodeEscape TokenFlags = 1 << 10 // e.g. `\u00a0`
TokenFlagsContainsInvalidEscape TokenFlags = 1 << 11 // e.g. `\uhello`
TokenFlagsHexEscape TokenFlags = 1 << 12 // e.g. `\xa0`
TokenFlagsContainsLeadingZero TokenFlags = 1 << 13 // e.g. `0888`
TokenFlagsContainsInvalidSeparator TokenFlags = 1 << 14 // e.g. `0_1`
TokenFlagsPrecedingJSDocLeadingAsterisks TokenFlags = 1 << 15
TokenFlagsSingleQuote TokenFlags = 1 << 16 // e.g. `'abc'`
TokenFlagsPrecedingJSDocWithDeprecated TokenFlags = 1 << 17 // Preceding JSDoc comment contains @deprecated
TokenFlagsPrecedingJSDocWithSeeOrLink TokenFlags = 1 << 18 // Preceding JSDoc comment contains @see or @link
TokenFlagsBinaryOrOctalSpecifier TokenFlags = TokenFlagsBinarySpecifier | TokenFlagsOctalSpecifier
TokenFlagsWithSpecifier TokenFlags = TokenFlagsHexSpecifier | TokenFlagsBinaryOrOctalSpecifier
TokenFlagsStringLiteralFlags TokenFlags = TokenFlagsUnterminated | TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape | TokenFlagsSingleQuote
TokenFlagsNumericLiteralFlags TokenFlags = TokenFlagsScientific | TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsWithSpecifier | TokenFlagsContainsSeparator | TokenFlagsContainsInvalidSeparator
TokenFlagsTemplateLiteralLikeFlags TokenFlags = TokenFlagsUnterminated | TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape
TokenFlagsRegularExpressionLiteralFlags TokenFlags = TokenFlagsUnterminated
TokenFlagsIsInvalid TokenFlags = TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsContainsInvalidSeparator | TokenFlagsContainsInvalidEscape
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
package ast
import (
"slices"
)
// NodeVisitor
type NodeVisitor struct {
Visit func(node *Node) *Node // Required. The callback used to visit a node
Factory *NodeFactory // Required. The NodeFactory used to produce new nodes when passed to VisitEachChild
Hooks NodeVisitorHooks // Hooks to be invoked when visiting a node
}
// These hooks are used to intercept the default behavior of the visitor
type NodeVisitorHooks struct {
VisitNode func(node *Node, v *NodeVisitor) *Node // Overrides visiting a Node. Only invoked by the VisitEachChild method on a given Node subtype.
VisitToken func(node *TokenNode, v *NodeVisitor) *Node // Overrides visiting a TokenNode. Only invoked by the VisitEachChild method on a given Node subtype.
VisitNodes func(nodes *NodeList, v *NodeVisitor) *NodeList // Overrides visiting a NodeList. Only invoked by the VisitEachChild method on a given Node subtype.
VisitModifiers func(nodes *ModifierList, v *NodeVisitor) *ModifierList // Overrides visiting a ModifierList. Only invoked by the VisitEachChild method on a given Node subtype.
VisitEmbeddedStatement func(node *Statement, v *NodeVisitor) *Statement // Overrides visiting a Node when it is the embedded statement body of an iteration statement, `if` statement, or `with` statement. Only invoked by the VisitEachChild method on a given Node subtype.
VisitIterationBody func(node *Statement, v *NodeVisitor) *Statement // Overrides visiting a Node when it is the embedded statement body of an iteration statement. Only invoked by the VisitEachChild method on a given Node subtype.
VisitParameters func(nodes *ParameterList, v *NodeVisitor) *ParameterList // Overrides visiting a ParameterList. Only invoked by the VisitEachChild method on a given Node subtype.
VisitFunctionBody func(node *BlockOrExpression, v *NodeVisitor) *BlockOrExpression // Overrides visiting a function body. Only invoked by the VisitEachChild method on a given Node subtype.
VisitTopLevelStatements func(nodes *StatementList, v *NodeVisitor) *StatementList // Overrides visiting a variable environment. Only invoked by the VisitEachChild method on a given Node subtype.
}
func NewNodeVisitor(visit func(node *Node) *Node, factory *NodeFactory, hooks NodeVisitorHooks) *NodeVisitor {
if factory == nil {
factory = &NodeFactory{}
}
return &NodeVisitor{Visit: visit, Factory: factory, Hooks: hooks}
}
func (v *NodeVisitor) VisitSourceFile(node *SourceFile) *SourceFile {
return v.VisitNode(node.AsNode()).AsSourceFile()
}
// Visits a Node, possibly returning a new Node in its place.
//
// - If the input node is nil, then the output is nil.
// - If v.Visit is nil, then the output is the input.
// - If v.Visit returns nil, then the output is nil.
// - If v.Visit returns a SyntaxList Node, then the output is the only child of the SyntaxList Node.
func (v *NodeVisitor) VisitNode(node *Node) *Node {
if node == nil || v.Visit == nil {
return node
}
if v.Visit != nil {
visited := v.Visit(node)
if visited != nil && visited.Kind == KindSyntaxList {
nodes := visited.AsSyntaxList().Children
if len(nodes) != 1 {
panic("Expected only a single node to be written to output")
}
visited = nodes[0]
if visited != nil && visited.Kind == KindSyntaxList {
panic("The result of visiting and lifting a Node may not be SyntaxList")
}
}
return visited
}
return node
}
// Visits an embedded Statement (i.e., the single statement body of a loop, `if..else` branch, etc.), possibly returning a new Statement in its place.
//
// - If the input node is nil, then the output is nil.
// - If v.Visit is nil, then the output is the input.
// - If v.Visit returns nil, then the output is nil.
// - If v.Visit returns a SyntaxList Node, then the output is either the only child of the SyntaxList Node, or a Block containing the nodes in the list.
func (v *NodeVisitor) VisitEmbeddedStatement(node *Statement) *Statement {
if node == nil || v.Visit == nil {
return node
}
visited := v.Visit(node)
if visited == nil {
return nil
}
return v.liftToBlock(visited)
}
// Visits a NodeList, possibly returning a new NodeList in its place.
//
// - If the input NodeList is nil, the output is nil.
// - If v.Visit is nil, then the output is the input.
// - If v.Visit returns nil, the visited Node will be absent in the output.
// - If v.Visit returns a different Node than the input, a new NodeList will be generated and returned.
// - If v.Visit returns a SyntaxList Node, then the children of that node will be merged into the output and a new NodeList will be returned.
// - If this method returns a new NodeList for any reason, it will have the same Loc as the input NodeList.
func (v *NodeVisitor) VisitNodes(nodes *NodeList) *NodeList {
if nodes == nil || v.Visit == nil {
return nodes
}
if result, changed := v.VisitSlice(nodes.Nodes); changed {
list := v.Factory.NewNodeList(result)
list.Loc = nodes.Loc
return list
}
return nodes
}
// Visits a ModifierList, possibly returning a new ModifierList in its place.
//
// - If the input ModifierList is nil, the output is nil.
// - If v.Visit is nil, then the output is the input.
// - If v.Visit returns nil, the visited Node will be absent in the output.
// - If v.Visit returns a different Node than the input, a new ModifierList will be generated and returned.
// - If v.Visit returns a SyntaxList Node, then the children of that node will be merged into the output and a new NodeList will be returned.
// - If this method returns a new NodeList for any reason, it will have the same Loc as the input NodeList.
func (v *NodeVisitor) VisitModifiers(nodes *ModifierList) *ModifierList {
if nodes == nil || v.Visit == nil {
return nodes
}
if result, changed := v.VisitSlice(nodes.Nodes); changed {
list := v.Factory.NewModifierList(result)
list.Loc = nodes.Loc
return list
}
return nodes
}
// Visits a slice of Nodes, returning the resulting slice and a value indicating whether the slice was changed.
//
// - If the input slice is nil, the output is nil.
// - If v.Visit is nil, then the output is the input.
// - If v.Visit returns nil, the visited Node will be absent in the output.
// - If v.Visit returns a different Node than the input, a new slice will be generated and returned.
// - If v.Visit returns a SyntaxList Node, then the children of that node will be merged into the output and a new slice will be returned.
func (v *NodeVisitor) VisitSlice(nodes []*Node) (result []*Node, changed bool) {
if nodes == nil || v.Visit == nil {
return nodes, false
}
for i := 0; i < len(nodes); i++ {
node := nodes[i]
if v.Visit == nil {
break
}
visited := v.Visit(node)
if visited == nil || visited != node {
updated := slices.Clone(nodes[:i])
for {
// finish prior loop
switch {
case visited == nil: // do nothing
case visited.Kind == KindSyntaxList:
updated = append(updated, visited.AsSyntaxList().Children...)
default:
updated = append(updated, visited)
}
i++
// loop over remaining elements
if i >= len(nodes) {
break
}
if v.Visit != nil {
node = nodes[i]
visited = v.Visit(node)
} else {
updated = append(updated, nodes[i:]...)
break
}
}
return updated, true
}
}
return nodes, false
}
// Visits each child of a Node, possibly returning a new Node of the same kind in its place.
func (v *NodeVisitor) VisitEachChild(node *Node) *Node {
if node == nil || v.Visit == nil {
return node
}
return node.VisitEachChild(v)
}
func (v *NodeVisitor) visitNode(node *Node) *Node {
if v.Hooks.VisitNode != nil {
return v.Hooks.VisitNode(node, v)
}
return v.VisitNode(node)
}
func (v *NodeVisitor) visitEmbeddedStatement(node *Node) *Node {
if v.Hooks.VisitEmbeddedStatement != nil {
return v.Hooks.VisitEmbeddedStatement(node, v)
}
if v.Hooks.VisitNode != nil {
return v.liftToBlock(v.Hooks.VisitNode(node, v))
}
return v.VisitEmbeddedStatement(node)
}
func (v *NodeVisitor) visitIterationBody(node *Statement) *Statement {
if v.Hooks.VisitIterationBody != nil {
return v.Hooks.VisitIterationBody(node, v)
}
return v.visitEmbeddedStatement(node)
}
func (v *NodeVisitor) visitFunctionBody(node *BlockOrExpression) *BlockOrExpression {
if v.Hooks.VisitFunctionBody != nil {
return v.Hooks.VisitFunctionBody(node, v)
}
return v.visitNode(node)
}
func (v *NodeVisitor) visitToken(node *Node) *Node {
if v.Hooks.VisitToken != nil {
return v.Hooks.VisitToken(node, v)
}
return v.VisitNode(node)
}
func (v *NodeVisitor) visitNodes(nodes *NodeList) *NodeList {
if v.Hooks.VisitNodes != nil {
return v.Hooks.VisitNodes(nodes, v)
}
return v.VisitNodes(nodes)
}
func (v *NodeVisitor) visitModifiers(nodes *ModifierList) *ModifierList {
if v.Hooks.VisitModifiers != nil {
return v.Hooks.VisitModifiers(nodes, v)
}
return v.VisitModifiers(nodes)
}
func (v *NodeVisitor) visitParameters(nodes *ParameterList) *ParameterList {
if v.Hooks.VisitParameters != nil {
return v.Hooks.VisitParameters(nodes, v)
}
return v.visitNodes(nodes)
}
func (v *NodeVisitor) visitTopLevelStatements(nodes *StatementList) *StatementList {
if v.Hooks.VisitTopLevelStatements != nil {
return v.Hooks.VisitTopLevelStatements(nodes, v)
}
return v.visitNodes(nodes)
}
func (v *NodeVisitor) liftToBlock(node *Statement) *Statement {
var nodes []*Node
if node != nil {
if node.Kind == KindSyntaxList {
nodes = node.AsSyntaxList().Children
} else {
nodes = []*Node{node}
}
}
if len(nodes) == 1 {
node = nodes[0]
} else {
node = v.Factory.NewBlock(v.Factory.NewNodeList(nodes), true /*multiLine*/)
}
if node.Kind == KindSyntaxList {
panic("The result of visiting and lifting a Node may not be SyntaxList")
}
return node
}