From 4db57c1641f0035069caeb5269fe7234daa1a5fb Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Wed, 9 Feb 2022 23:04:20 -0500 Subject: [PATCH] remove use of go's "unsafe" package in the parser --- internal/js_lexer/js_lexer.go | 81 ++++++--- internal/js_lexer/js_lexer_test.go | 6 +- internal/js_parser/global_name_parser.go | 4 +- internal/js_parser/js_parser.go | 202 +++++++++++------------ internal/js_parser/ts_parser.go | 18 +- 5 files changed, 171 insertions(+), 140 deletions(-) diff --git a/internal/js_lexer/js_lexer.go b/internal/js_lexer/js_lexer.go index 559eab0dd06..93d97ac30eb 100644 --- a/internal/js_lexer/js_lexer.go +++ b/internal/js_lexer/js_lexer.go @@ -20,6 +20,7 @@ import ( "unicode" "unicode/utf8" + "github.com/evanw/esbuild/internal/ast" "github.com/evanw/esbuild/internal/config" "github.com/evanw/esbuild/internal/helpers" "github.com/evanw/esbuild/internal/js_ast" @@ -216,10 +217,37 @@ type json struct { allowComments bool } +// This represents a string that is maybe a substring of the current file's +// "source.Contents" string. The point of doing this is that if it is a +// substring (the common case), then we can represent it more efficiently. +// +// For compactness and performance, the JS AST represents identifiers as a +// symbol reference instead of as a string. However, we need to track the +// string between the first pass and the second pass because the string is only +// resolved to a symbol in the second pass. To avoid allocating extra memory +// to store the string, we instead use an index+length slice of the original JS +// source code. That index is what "Start" represents here. The length is just +// "len(String)". +// +// Set "Start" to invalid (the zero value) if "String" is not a substring of +// "source.Contents". This is the case for escaped identifiers. For example, +// the identifier "fo\u006f" would be "MaybeSubstring{String: "foo"}". It's +// critical that any code changing the "String" also set "Start" to the zero +// value, which is best done by just overwriting the whole "MaybeSubstring". +// +// The substring range used to be recovered automatically from the string but +// that relied on the Go "unsafe" package which can hypothetically break under +// certain Go compiler optimization passes, so it has been removed and replaced +// with this more error-prone approach that doesn't use "unsafe". +type MaybeSubstring struct { + String string + Start ast.Index32 +} + type Lexer struct { CommentsToPreserveBefore []js_ast.Comment AllOriginalComments []js_ast.Comment - Identifier string + Identifier MaybeSubstring log logger.Log source logger.Source JSXFactoryPragmaComment logger.Span @@ -323,6 +351,10 @@ func (lexer *Lexer) Raw() string { return lexer.source.Contents[lexer.start:lexer.end] } +func (lexer *Lexer) rawIdentifier() MaybeSubstring { + return MaybeSubstring{lexer.Raw(), ast.MakeIndex32(uint32(lexer.start))} +} + func (lexer *Lexer) StringLiteral() []uint16 { if lexer.decodedStringLiteralOrNil == nil { // Lazily decode escape sequences if needed @@ -1143,7 +1175,7 @@ func (lexer *Lexer) NextInsideJSXElement() { lexer.step() } - lexer.Identifier = lexer.Raw() + lexer.Identifier = lexer.rawIdentifier() lexer.Token = TIdentifier break } @@ -1185,7 +1217,7 @@ func (lexer *Lexer) Next() { break hashbang } } - lexer.Identifier = lexer.Raw() + lexer.Identifier = lexer.rawIdentifier() } else { // "#foo" lexer.step() @@ -1202,7 +1234,7 @@ func (lexer *Lexer) Next() { if lexer.codePoint == '\\' { lexer.Identifier, _ = lexer.scanIdentifierWithEscapes(privateIdentifier) } else { - lexer.Identifier = lexer.Raw() + lexer.Identifier = lexer.rawIdentifier() } } lexer.Token = TPrivateIdentifier @@ -1717,9 +1749,8 @@ func (lexer *Lexer) Next() { if lexer.codePoint == '\\' { lexer.Identifier, lexer.Token = lexer.scanIdentifierWithEscapes(normalIdentifier) } else { - contents := lexer.Raw() - lexer.Identifier = contents - lexer.Token = Keywords[contents] + lexer.Identifier = lexer.rawIdentifier() + lexer.Token = Keywords[lexer.Raw()] if lexer.Token == 0 { lexer.Token = TIdentifier } @@ -1747,7 +1778,7 @@ func (lexer *Lexer) Next() { lexer.Identifier, lexer.Token = lexer.scanIdentifierWithEscapes(normalIdentifier) } else { lexer.Token = TIdentifier - lexer.Identifier = lexer.Raw() + lexer.Identifier = lexer.rawIdentifier() } break } @@ -1769,7 +1800,7 @@ const ( // This is an edge case that doesn't really exist in the wild, so it doesn't // need to be as fast as possible. -func (lexer *Lexer) scanIdentifierWithEscapes(kind identifierKind) (string, T) { +func (lexer *Lexer) scanIdentifierWithEscapes(kind identifierKind) (MaybeSubstring, T) { // First pass: scan over the identifier to see how long it is for { // Scan a unicode escape sequence. There is at least one because that's @@ -1848,9 +1879,9 @@ func (lexer *Lexer) scanIdentifierWithEscapes(kind identifierKind) (string, T) { // foo.\u0076\u0061\u0072; // if Keywords[text] != 0 { - return text, TEscapedKeyword + return MaybeSubstring{String: text}, TEscapedKeyword } else { - return text, TIdentifier + return MaybeSubstring{String: text}, TIdentifier } } @@ -1978,7 +2009,7 @@ func (lexer *Lexer) parseNumericLiteralOrDot() { // Slow path: do we need to re-scan the input as text? if isBigIntegerLiteral || isInvalidLegacyOctalLiteral { - text := lexer.Raw() + text := lexer.rawIdentifier() // Can't use a leading zero for bigint literals if isBigIntegerLiteral && lexer.IsLegacyOctalLiteral { @@ -1987,14 +2018,14 @@ func (lexer *Lexer) parseNumericLiteralOrDot() { // Filter out underscores if underscoreCount > 0 { - bytes := make([]byte, 0, len(text)-underscoreCount) - for i := 0; i < len(text); i++ { - c := text[i] + bytes := make([]byte, 0, len(text.String)-underscoreCount) + for i := 0; i < len(text.String); i++ { + c := text.String[i] if c != '_' { bytes = append(bytes, c) } } - text = string(bytes) + text = MaybeSubstring{String: string(bytes)} } // Store bigints as text to avoid precision loss @@ -2002,7 +2033,7 @@ func (lexer *Lexer) parseNumericLiteralOrDot() { lexer.Identifier = text } else if isInvalidLegacyOctalLiteral { // Legacy octal literals may turn out to be a base 10 literal after all - value, _ := strconv.ParseFloat(text, 64) + value, _ := strconv.ParseFloat(text.String, 64) lexer.Number = value } } @@ -2099,23 +2130,23 @@ func (lexer *Lexer) parseNumericLiteralOrDot() { } // Take a slice of the text to parse - text := lexer.Raw() + text := lexer.rawIdentifier() // Filter out underscores if underscoreCount > 0 { - bytes := make([]byte, 0, len(text)-underscoreCount) - for i := 0; i < len(text); i++ { - c := text[i] + bytes := make([]byte, 0, len(text.String)-underscoreCount) + for i := 0; i < len(text.String); i++ { + c := text.String[i] if c != '_' { bytes = append(bytes, c) } } - text = string(bytes) + text = MaybeSubstring{String: string(bytes)} } if lexer.codePoint == 'n' && !hasDotOrExponent { // The only bigint literal that can start with 0 is "0n" - if len(text) > 1 && first == '0' { + if len(text.String) > 1 && first == '0' { lexer.SyntaxError() } @@ -2124,13 +2155,13 @@ func (lexer *Lexer) parseNumericLiteralOrDot() { } else if !hasDotOrExponent && lexer.end-lexer.start < 10 { // Parse a 32-bit integer (very fast path) var number uint32 = 0 - for _, c := range text { + for _, c := range text.String { number = number*10 + uint32(c-'0') } lexer.Number = float64(number) } else { // Parse a double-precision floating-point number - value, _ := strconv.ParseFloat(text, 64) + value, _ := strconv.ParseFloat(text.String, 64) lexer.Number = value } } diff --git a/internal/js_lexer/js_lexer_test.go b/internal/js_lexer/js_lexer_test.go index 1b67363fa85..96d9b164c82 100644 --- a/internal/js_lexer/js_lexer_test.go +++ b/internal/js_lexer/js_lexer_test.go @@ -85,7 +85,7 @@ func expectHashbang(t *testing.T, contents string, expected string) { msgs := log.Done() test.AssertEqual(t, len(msgs), 0) test.AssertEqual(t, lexer.Token, THashbang) - test.AssertEqual(t, lexer.Identifier, expected) + test.AssertEqual(t, lexer.Identifier.String, expected) }) } @@ -113,7 +113,7 @@ func expectIdentifier(t *testing.T, contents string, expected string) { msgs := log.Done() test.AssertEqual(t, len(msgs), 0) test.AssertEqual(t, lexer.Token, TIdentifier) - test.AssertEqual(t, lexer.Identifier, expected) + test.AssertEqual(t, lexer.Identifier.String, expected) }) } @@ -359,7 +359,7 @@ func expectBigInteger(t *testing.T, contents string, expected string) { msgs := log.Done() test.AssertEqual(t, len(msgs), 0) test.AssertEqual(t, lexer.Token, TBigIntegerLiteral) - test.AssertEqual(t, lexer.Identifier, expected) + test.AssertEqual(t, lexer.Identifier.String, expected) }) } diff --git a/internal/js_parser/global_name_parser.go b/internal/js_parser/global_name_parser.go index 168abb6d3e8..0064990b75a 100644 --- a/internal/js_parser/global_name_parser.go +++ b/internal/js_parser/global_name_parser.go @@ -20,7 +20,7 @@ func ParseGlobalName(log logger.Log, source logger.Source) (result []string, ok lexer := js_lexer.NewLexerGlobalName(log, source) // Start off with an identifier - result = append(result, lexer.Identifier) + result = append(result, lexer.Identifier.String) lexer.Expect(js_lexer.TIdentifier) // Follow with dot or index expressions @@ -31,7 +31,7 @@ func ParseGlobalName(log logger.Log, source logger.Source) (result []string, ok if !lexer.IsIdentifierOrKeyword() { lexer.Expect(js_lexer.TIdentifier) } - result = append(result, lexer.Identifier) + result = append(result, lexer.Identifier.String) lexer.Next() case js_lexer.TOpenBracket: diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index 255e6f8737e..8cb42de7a21 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -3,12 +3,10 @@ package js_parser import ( "fmt" "math" - "reflect" "regexp" "sort" "strings" "unicode/utf8" - "unsafe" "github.com/evanw/esbuild/internal/ast" "github.com/evanw/esbuild/internal/compat" @@ -1750,26 +1748,23 @@ func (p *parser) makePromiseRef() js_ast.Ref { // can just store the slice and not need to allocate any extra memory. In the // rare case, the name is an externally-allocated string. In that case we store // an index to the string and use that index during the scope traversal pass. -func (p *parser) storeNameInRef(name string) js_ast.Ref { - c := (*reflect.StringHeader)(unsafe.Pointer(&p.source.Contents)) - n := (*reflect.StringHeader)(unsafe.Pointer(&name)) - +func (p *parser) storeNameInRef(name js_lexer.MaybeSubstring) js_ast.Ref { // Is the data in "name" a subset of the data in "p.source.Contents"? - if n.Data >= c.Data && n.Data+uintptr(n.Len) < c.Data+uintptr(c.Len) { + if name.Start.IsValid() { // The name is a slice of the file contents, so we can just reference it by // length and don't have to allocate anything. This is the common case. // // It's stored as a negative value so we'll crash if we try to use it. That // way we'll catch cases where we've forgotten to call loadNameFromRef(). // The length is the negative part because we know it's non-zero. - return js_ast.Ref{SourceIndex: -uint32(n.Len), InnerIndex: uint32(n.Data - c.Data)} + return js_ast.Ref{SourceIndex: -uint32(len(name.String)), InnerIndex: uint32(name.Start.GetIndex())} } else { // The name is some memory allocated elsewhere. This is either an inline // string constant in the parser or an identifier with escape sequences // in the source code, which is very unusual. Stash it away for later. // This uses allocations but it should hopefully be very uncommon. ref := js_ast.Ref{SourceIndex: 0x80000000, InnerIndex: uint32(len(p.allocatedNames))} - p.allocatedNames = append(p.allocatedNames, name) + p.allocatedNames = append(p.allocatedNames, name.String) return ref } } @@ -1933,7 +1928,7 @@ func (p *parser) parseProperty(kind js_ast.PropertyKind, opts propertyOpts, erro preferQuotedKey = !p.options.minifySyntax case js_lexer.TBigIntegerLiteral: - key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EBigInt{Value: p.lexer.Identifier}} + key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EBigInt{Value: p.lexer.Identifier.String}} p.markSyntaxFeature(compat.BigInt, p.lexer.Range()) p.lexer.Next() @@ -2008,21 +2003,21 @@ func (p *parser) parseProperty(kind js_ast.PropertyKind, opts propertyOpts, erro // If so, check for a modifier keyword if couldBeModifierKeyword { - switch name { + switch name.String { case "get": - if !opts.isAsync && raw == name { + if !opts.isAsync && raw == name.String { p.markSyntaxFeature(compat.ObjectAccessors, nameRange) return p.parseProperty(js_ast.PropertyGet, opts, nil) } case "set": - if !opts.isAsync && raw == name { + if !opts.isAsync && raw == name.String { p.markSyntaxFeature(compat.ObjectAccessors, nameRange) return p.parseProperty(js_ast.PropertySet, opts, nil) } case "async": - if !opts.isAsync && raw == name && !p.lexer.HasNewlineBefore { + if !opts.isAsync && raw == name.String && !p.lexer.HasNewlineBefore { opts.isAsync = true opts.asyncRange = nameRange p.markLoweredSyntaxFeature(compat.AsyncAwait, nameRange, compat.Generator) @@ -2030,13 +2025,13 @@ func (p *parser) parseProperty(kind js_ast.PropertyKind, opts propertyOpts, erro } case "static": - if !opts.isStatic && !opts.isAsync && opts.isClass && raw == name { + if !opts.isStatic && !opts.isAsync && opts.isClass && raw == name.String { opts.isStatic = true return p.parseProperty(kind, opts, nil) } case "declare": - if opts.isClass && p.options.ts.Parse && opts.tsDeclareRange.Len == 0 && raw == name { + if opts.isClass && p.options.ts.Parse && opts.tsDeclareRange.Len == 0 && raw == name.String { opts.tsDeclareRange = nameRange scopeIndex := len(p.scopesInOrder) @@ -2060,7 +2055,7 @@ func (p *parser) parseProperty(kind js_ast.PropertyKind, opts propertyOpts, erro } case "abstract": - if opts.isClass && p.options.ts.Parse && !opts.isTSAbstract && raw == name { + if opts.isClass && p.options.ts.Parse && !opts.isTSAbstract && raw == name.String { opts.isTSAbstract = true scopeIndex := len(p.scopesInOrder) p.parseProperty(kind, opts, nil) @@ -2070,11 +2065,11 @@ func (p *parser) parseProperty(kind js_ast.PropertyKind, opts propertyOpts, erro case "private", "protected", "public", "readonly", "override": // Skip over TypeScript keywords - if opts.isClass && p.options.ts.Parse && raw == name { + if opts.isClass && p.options.ts.Parse && raw == name.String { return p.parseProperty(kind, opts, nil) } } - } else if p.lexer.Token == js_lexer.TOpenBrace && name == "static" { + } else if p.lexer.Token == js_lexer.TOpenBrace && name.String == "static" { loc := p.lexer.Loc() p.lexer.Next() @@ -2102,18 +2097,18 @@ func (p *parser) parseProperty(kind js_ast.PropertyKind, opts propertyOpts, erro } } - if p.isMangledProp(name) { + if p.isMangledProp(name.String) { key = js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.EMangledProp{Ref: p.storeNameInRef(name)}} } else { - key = js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name)}} + key = js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name.String)}} } // Parse a shorthand property if !opts.isClass && kind == js_ast.PropertyNormal && p.lexer.Token != js_lexer.TColon && p.lexer.Token != js_lexer.TOpenParen && p.lexer.Token != js_lexer.TLessThan && - !opts.isGenerator && !opts.isAsync && js_lexer.Keywords[name] == js_lexer.T(0) { - if (p.fnOrArrowDataParse.await != allowIdent && name == "await") || (p.fnOrArrowDataParse.yield != allowIdent && name == "yield") { - p.log.Add(logger.Error, &p.tracker, nameRange, fmt.Sprintf("Cannot use %q as an identifier here:", name)) + !opts.isGenerator && !opts.isAsync && js_lexer.Keywords[name.String] == js_lexer.T(0) { + if (p.fnOrArrowDataParse.await != allowIdent && name.String == "await") || (p.fnOrArrowDataParse.yield != allowIdent && name.String == "yield") { + p.log.Add(logger.Error, &p.tracker, nameRange, fmt.Sprintf("Cannot use %q as an identifier here:", name.String)) } ref := p.storeNameInRef(name) value := js_ast.Expr{Loc: key.Loc, Data: &js_ast.EIdentifier{Ref: ref}} @@ -2397,7 +2392,7 @@ func (p *parser) parsePropertyBinding() js_ast.PropertyBinding { preferQuotedKey = !p.options.minifySyntax case js_lexer.TBigIntegerLiteral: - key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EBigInt{Value: p.lexer.Identifier}} + key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EBigInt{Value: p.lexer.Identifier.String}} p.markSyntaxFeature(compat.BigInt, p.lexer.Range()) p.lexer.Next() @@ -2414,10 +2409,10 @@ func (p *parser) parsePropertyBinding() js_ast.PropertyBinding { p.lexer.Expect(js_lexer.TIdentifier) } p.lexer.Next() - if p.isMangledProp(name) { + if p.isMangledProp(name.String) { key = js_ast.Expr{Loc: loc, Data: &js_ast.EMangledProp{Ref: p.storeNameInRef(name)}} } else { - key = js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name)}} + key = js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name.String)}} } if p.lexer.Token != js_lexer.TColon && p.lexer.Token != js_lexer.TOpenParen { @@ -2503,8 +2498,8 @@ func (p *parser) symbolForMangledProp(name string) js_ast.Ref { return ref } -func (p *parser) dotOrMangledPropParse(target js_ast.Expr, name string, nameLoc logger.Loc, optionalChain js_ast.OptionalChain) js_ast.E { - if p.isMangledProp(name) { +func (p *parser) dotOrMangledPropParse(target js_ast.Expr, name js_lexer.MaybeSubstring, nameLoc logger.Loc, optionalChain js_ast.OptionalChain) js_ast.E { + if p.isMangledProp(name.String) { return &js_ast.EIndex{ Target: target, Index: js_ast.Expr{Loc: nameLoc, Data: &js_ast.EMangledProp{Ref: p.storeNameInRef(name)}}, @@ -2514,7 +2509,7 @@ func (p *parser) dotOrMangledPropParse(target js_ast.Expr, name string, nameLoc return &js_ast.EDot{ Target: target, - Name: name, + Name: name.String, NameLoc: nameLoc, OptionalChain: optionalChain, } @@ -2612,7 +2607,8 @@ func (p *parser) parseAsyncPrefixExpr(asyncRange logger.Range, level js_ast.L, f // "async => {}" case js_lexer.TEqualsGreaterThan: if level <= js_ast.LAssign { - arg := js_ast.Arg{Binding: js_ast.Binding{Loc: asyncRange.Loc, Data: &js_ast.BIdentifier{Ref: p.storeNameInRef("async")}}} + arg := js_ast.Arg{Binding: js_ast.Binding{Loc: asyncRange.Loc, Data: &js_ast.BIdentifier{ + Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "async"})}}} p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, asyncRange.Loc) defer p.popScope() @@ -2627,7 +2623,7 @@ func (p *parser) parseAsyncPrefixExpr(asyncRange logger.Range, level js_ast.L, f if level <= js_ast.LAssign { // See https://github.com/tc39/ecma262/issues/2034 for details isArrowFn := true - if (flags&exprFlagForLoopInit) != 0 && p.lexer.Identifier == "of" { + if (flags&exprFlagForLoopInit) != 0 && p.lexer.Identifier.String == "of" { // "for (async of" is only an arrow function if the next token is "=>" isArrowFn = p.checkForArrowAfterTheCurrentToken() @@ -2661,21 +2657,22 @@ func (p *parser) parseAsyncPrefixExpr(asyncRange logger.Range, level js_ast.L, f // "async () => {}" case js_lexer.TOpenParen: p.lexer.Next() - return p.parseParenExpr(asyncRange.Loc, level, parenExprOpts{isAsync: true, asyncRange: asyncRange}) + return p.parseParenExpr(asyncRange.Loc, level, parenExprOpts{asyncRange: asyncRange}) // "async()" // "async () => {}" case js_lexer.TLessThan: if p.options.ts.Parse && p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking() { p.lexer.Next() - return p.parseParenExpr(asyncRange.Loc, level, parenExprOpts{isAsync: true, asyncRange: asyncRange}) + return p.parseParenExpr(asyncRange.Loc, level, parenExprOpts{asyncRange: asyncRange}) } } } // "async" // "async + 1" - return js_ast.Expr{Loc: asyncRange.Loc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef("async")}} + return js_ast.Expr{Loc: asyncRange.Loc, Data: &js_ast.EIdentifier{ + Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "async"})}} } func (p *parser) parseFnExpr(loc logger.Loc, isAsync bool, asyncRange logger.Range) js_ast.Expr { @@ -2696,7 +2693,7 @@ func (p *parser) parseFnExpr(loc logger.Loc, isAsync bool, asyncRange logger.Ran if p.lexer.Token == js_lexer.TIdentifier { // Don't declare the name "arguments" since it's shadowed and inaccessible name = &js_ast.LocRef{Loc: p.lexer.Loc()} - if text := p.lexer.Identifier; text != "arguments" { + if text := p.lexer.Identifier.String; text != "arguments" { name.Ref = p.declareSymbol(js_ast.SymbolHoistedFunction, name.Loc, text) } else { name.Ref = p.newSymbol(js_ast.SymbolHoistedFunction, text) @@ -2730,7 +2727,6 @@ func (p *parser) parseFnExpr(loc logger.Loc, isAsync bool, asyncRange logger.Ran type parenExprOpts struct { asyncRange logger.Range - isAsync bool forceArrowFn bool } @@ -2742,6 +2738,7 @@ func (p *parser) parseParenExpr(loc logger.Loc, level js_ast.L, opts parenExprOp spreadRange := logger.Range{} typeColonRange := logger.Range{} commaAfterSpread := logger.Loc{} + isAsync := opts.asyncRange.Len > 0 // Push a scope assuming this is an arrow function. It may not be, in which // case we'll need to roll this change back. This has to be done ahead of @@ -2828,7 +2825,7 @@ func (p *parser) parseParenExpr(loc logger.Loc, level js_ast.L, opts parenExprOp var invalidLog invalidLog args := []js_ast.Arg{} - if opts.isAsync { + if isAsync { p.markLoweredSyntaxFeature(compat.AsyncAwait, opts.asyncRange, compat.Generator) } @@ -2871,7 +2868,7 @@ func (p *parser) parseParenExpr(loc logger.Loc, level js_ast.L, opts parenExprOp } await := allowIdent - if opts.isAsync { + if isAsync { await = allowExpr } @@ -2879,7 +2876,7 @@ func (p *parser) parseParenExpr(loc logger.Loc, level js_ast.L, opts parenExprOp needsAsyncLoc: loc, await: await, }) - arrow.IsAsync = opts.isAsync + arrow.IsAsync = isAsync arrow.HasRestArg = spreadRange.Len > 0 p.popScope() return js_ast.Expr{Loc: loc, Data: arrow} @@ -2898,9 +2895,10 @@ func (p *parser) parseParenExpr(loc logger.Loc, level js_ast.L, opts parenExprOp } // Are these arguments for a call to a function named "async"? - if opts.isAsync { + if isAsync { p.logExprErrors(&errors) - async := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef("async")}} + async := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{ + Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "async"})}} return js_ast.Expr{Loc: loc, Data: &js_ast.ECall{ Target: async, Args: items, @@ -3123,7 +3121,7 @@ func (p *parser) parsePrefix(level js_ast.L, errors *deferredErrors, flags exprF if p.classPrivateBrandChecksToLower == nil { p.classPrivateBrandChecksToLower = make(map[string]bool) } - p.classPrivateBrandChecksToLower[name] = true + p.classPrivateBrandChecksToLower[name.String] = true } return js_ast.Expr{Loc: loc, Data: &js_ast.EPrivateIdentifier{Ref: p.storeNameInRef(name)}} @@ -3135,7 +3133,7 @@ func (p *parser) parsePrefix(level js_ast.L, errors *deferredErrors, flags exprF p.lexer.Next() // Handle async and await expressions - switch name { + switch name.String { case "async": if raw == "async" { return p.parseAsyncPrefixExpr(nameRange, level, flags) @@ -3248,7 +3246,7 @@ func (p *parser) parsePrefix(level js_ast.L, errors *deferredErrors, flags exprF value := p.lexer.Identifier p.markSyntaxFeature(compat.BigInt, p.lexer.Range()) p.lexer.Next() - return js_ast.Expr{Loc: loc, Data: &js_ast.EBigInt{Value: value}} + return js_ast.Expr{Loc: loc, Data: &js_ast.EBigInt{Value: value.String}} case js_lexer.TSlash, js_lexer.TSlashEquals: p.lexer.ScanRegExp() @@ -3340,7 +3338,7 @@ func (p *parser) parsePrefix(level js_ast.L, errors *deferredErrors, flags exprF // Parse an optional class name if p.lexer.Token == js_lexer.TIdentifier { - if nameText := p.lexer.Identifier; !p.options.ts.Parse || nameText != "implements" { + if nameText := p.lexer.Identifier.String; !p.options.ts.Parse || nameText != "implements" { if p.fnOrArrowDataParse.await != allowIdent && nameText == "await" { p.log.Add(logger.Error, &p.tracker, p.lexer.Range(), "Cannot use \"await\" as an identifier here:") } @@ -4436,9 +4434,8 @@ func (p *parser) parseSuffix(left js_ast.Expr, level js_ast.L, errors *deferredE func (p *parser) parseExprOrLetStmt(opts parseStmtOpts) (js_ast.Expr, js_ast.Stmt, []js_ast.Decl) { letRange := p.lexer.Range() - raw := p.lexer.Raw() - if p.lexer.Token != js_lexer.TIdentifier || raw != "let" { + if p.lexer.Token != js_lexer.TIdentifier || p.lexer.Raw() != "let" { var flags exprFlag if opts.isForLoopInit { flags |= exprFlagForLoopInit @@ -4449,6 +4446,7 @@ func (p *parser) parseExprOrLetStmt(opts parseStmtOpts) (js_ast.Expr, js_ast.Stm return p.parseExprCommon(js_ast.LLowest, nil, flags), js_ast.Stmt{}, nil } + name := p.lexer.Identifier p.lexer.Next() switch p.lexer.Token { @@ -4467,7 +4465,7 @@ func (p *parser) parseExprOrLetStmt(opts parseStmtOpts) (js_ast.Expr, js_ast.Stm } } - ref := p.storeNameInRef(raw) + ref := p.storeNameInRef(name) expr := js_ast.Expr{Loc: letRange.Loc, Data: &js_ast.EIdentifier{Ref: ref}} return p.parseSuffix(expr, js_ast.LLowest, nil, 0), js_ast.Stmt{}, nil } @@ -4503,7 +4501,7 @@ func (p *parser) parseCallArgs() []js_ast.Expr { return args } -func (p *parser) parseJSXNamespacedName() (logger.Range, string) { +func (p *parser) parseJSXNamespacedName() (logger.Range, js_lexer.MaybeSubstring) { nameRange := p.lexer.Range() name := p.lexer.Identifier p.lexer.ExpectInsideJSXElement(js_lexer.TIdentifier) @@ -4515,19 +4513,20 @@ func (p *parser) parseJSXNamespacedName() (logger.Range, string) { if p.lexer.Token == js_lexer.TColon { // Parse the colon nameRange.Len = p.lexer.Range().End() - nameRange.Loc.Start - name += ":" + ns := name.String + ":" p.lexer.NextInsideJSXElement() // Parse the second identifier if p.lexer.Token == js_lexer.TIdentifier { nameRange.Len = p.lexer.Range().End() - nameRange.Loc.Start - name += p.lexer.Identifier + ns += p.lexer.Identifier.String p.lexer.NextInsideJSXElement() } else { p.log.Add(logger.Error, &p.tracker, logger.Range{Loc: logger.Loc{Start: nameRange.End()}}, - fmt.Sprintf("Expected identifier after %q in namespaced JSX name", name)) + fmt.Sprintf("Expected identifier after %q in namespaced JSX name", ns)) panic(js_lexer.LexerPanic{}) } + return nameRange, js_lexer.MaybeSubstring{String: ns} } return nameRange, name @@ -4545,14 +4544,15 @@ func (p *parser) parseJSXTag() (logger.Range, string, js_ast.Expr) { tagRange, tagName := p.parseJSXNamespacedName() // Certain identifiers are strings - if strings.ContainsAny(tagName, "-:") || (p.lexer.Token != js_lexer.TDot && tagName[0] >= 'a' && tagName[0] <= 'z') { - return tagRange, tagName, js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(tagName)}} + if strings.ContainsAny(tagName.String, "-:") || (p.lexer.Token != js_lexer.TDot && tagName.String[0] >= 'a' && tagName.String[0] <= 'z') { + return tagRange, tagName.String, js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(tagName.String)}} } // Otherwise, this is an identifier tag := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef(tagName)}} // Parse a member expression chain + chain := tagName.String for p.lexer.Token == js_lexer.TDot { p.lexer.NextInsideJSXElement() memberRange := p.lexer.Range() @@ -4560,19 +4560,19 @@ func (p *parser) parseJSXTag() (logger.Range, string, js_ast.Expr) { p.lexer.ExpectInsideJSXElement(js_lexer.TIdentifier) // Dashes are not allowed in member expression chains - index := strings.IndexByte(member, '-') + index := strings.IndexByte(member.String, '-') if index >= 0 { p.log.Add(logger.Error, &p.tracker, logger.Range{Loc: logger.Loc{Start: memberRange.Loc.Start + int32(index)}}, "Unexpected \"-\"") panic(js_lexer.LexerPanic{}) } - tagName += "." + member + chain += "." + member.String tag = js_ast.Expr{Loc: loc, Data: p.dotOrMangledPropParse(tag, member, memberRange.Loc, js_ast.OptionalChainNone)} tagRange.Len = memberRange.Loc.Start + memberRange.Len - tagRange.Loc.Start } - return tagRange, tagName, tag + return tagRange, chain, tag } func (p *parser) parseJSXElement(loc logger.Loc) js_ast.Expr { @@ -4599,10 +4599,10 @@ func (p *parser) parseJSXElement(loc logger.Loc) js_ast.Expr { // Parse the key keyRange, keyName := p.parseJSXNamespacedName() var key js_ast.Expr - if p.isMangledProp(keyName) && !strings.ContainsRune(keyName, ':') { + if p.isMangledProp(keyName.String) && !strings.ContainsRune(keyName.String, ':') { key = js_ast.Expr{Loc: keyRange.Loc, Data: &js_ast.EMangledProp{Ref: p.storeNameInRef(keyName)}} } else { - key = js_ast.Expr{Loc: keyRange.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(keyName)}} + key = js_ast.Expr{Loc: keyRange.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(keyName.String)}} } // Parse the value @@ -4897,7 +4897,7 @@ func (p *parser) forbidInitializers(decls []js_ast.Decl, loopType string, isVar } } -func (p *parser) parseClauseAlias(kind string) string { +func (p *parser) parseClauseAlias(kind string) js_lexer.MaybeSubstring { loc := p.lexer.Loc() // The alias may now be a string (see https://github.com/tc39/ecma262/pull/2154) @@ -4910,7 +4910,7 @@ func (p *parser) parseClauseAlias(kind string) string { } else { p.markSyntaxFeature(compat.ArbitraryModuleNamespaceNames, r) } - return alias + return js_lexer.MaybeSubstring{String: alias} } // The alias may be a keyword @@ -4919,7 +4919,7 @@ func (p *parser) parseClauseAlias(kind string) string { } alias := p.lexer.Identifier - p.checkForUnrepresentableIdentifier(loc, alias) + p.checkForUnrepresentableIdentifier(loc, alias.String) return alias } @@ -4942,7 +4942,7 @@ func (p *parser) parseImportClause() ([]js_ast.ClauseItem, bool) { // "import { type as } from 'mod'" // "import { type as as } from 'mod'" // "import { type as as as } from 'mod'" - if p.options.ts.Parse && alias == "type" && p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace { + if p.options.ts.Parse && alias.String == "type" && p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace { if p.lexer.IsContextualKeyword("as") { p.lexer.Next() if p.lexer.IsContextualKeyword("as") { @@ -4957,10 +4957,10 @@ func (p *parser) parseImportClause() ([]js_ast.ClauseItem, bool) { } else { // "import { type as as } from 'mod'" items = append(items, js_ast.ClauseItem{ - Alias: alias, + Alias: alias.String, AliasLoc: aliasLoc, Name: name, - OriginalName: originalName, + OriginalName: originalName.String, }) } } else if p.lexer.Token == js_lexer.TIdentifier { @@ -4970,16 +4970,16 @@ func (p *parser) parseImportClause() ([]js_ast.ClauseItem, bool) { p.lexer.Expect(js_lexer.TIdentifier) // Reject forbidden names - if isEvalOrArguments(originalName) { + if isEvalOrArguments(originalName.String) { r := js_lexer.RangeOfIdentifier(p.source, name.Loc) - p.log.Add(logger.Error, &p.tracker, r, fmt.Sprintf("Cannot use %q as an identifier here:", originalName)) + p.log.Add(logger.Error, &p.tracker, r, fmt.Sprintf("Cannot use %q as an identifier here:", originalName.String)) } items = append(items, js_ast.ClauseItem{ - Alias: alias, + Alias: alias.String, AliasLoc: aliasLoc, Name: name, - OriginalName: originalName, + OriginalName: originalName.String, }) } } else { @@ -5012,16 +5012,16 @@ func (p *parser) parseImportClause() ([]js_ast.ClauseItem, bool) { } // Reject forbidden names - if isEvalOrArguments(originalName) { + if isEvalOrArguments(originalName.String) { r := js_lexer.RangeOfIdentifier(p.source, name.Loc) - p.log.Add(logger.Error, &p.tracker, r, fmt.Sprintf("Cannot use %q as an identifier here:", originalName)) + p.log.Add(logger.Error, &p.tracker, r, fmt.Sprintf("Cannot use %q as an identifier here:", originalName.String)) } items = append(items, js_ast.ClauseItem{ - Alias: alias, + Alias: alias.String, AliasLoc: aliasLoc, Name: name, - OriginalName: originalName, + OriginalName: originalName.String, }) } @@ -5071,7 +5071,7 @@ func (p *parser) parseExportClause() ([]js_ast.ClauseItem, bool) { } p.lexer.Next() - if p.options.ts.Parse && alias == "type" && p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace { + if p.options.ts.Parse && alias.String == "type" && p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace { if p.lexer.IsContextualKeyword("as") { p.lexer.Next() if p.lexer.IsContextualKeyword("as") { @@ -5088,10 +5088,10 @@ func (p *parser) parseExportClause() ([]js_ast.ClauseItem, bool) { } else { // "export { type as as }" items = append(items, js_ast.ClauseItem{ - Alias: alias, + Alias: alias.String, AliasLoc: aliasLoc, Name: name, - OriginalName: originalName, + OriginalName: originalName.String, }) } } else if p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace { @@ -5102,10 +5102,10 @@ func (p *parser) parseExportClause() ([]js_ast.ClauseItem, bool) { p.lexer.Next() items = append(items, js_ast.ClauseItem{ - Alias: alias, + Alias: alias.String, AliasLoc: aliasLoc, Name: name, - OriginalName: originalName, + OriginalName: originalName.String, }) } } else { @@ -5148,10 +5148,10 @@ func (p *parser) parseExportClause() ([]js_ast.ClauseItem, bool) { } items = append(items, js_ast.ClauseItem{ - Alias: alias, + Alias: alias.String, AliasLoc: aliasLoc, Name: name, - OriginalName: originalName, + OriginalName: originalName.String, }) } @@ -5189,9 +5189,9 @@ func (p *parser) parseBinding() js_ast.Binding { switch p.lexer.Token { case js_lexer.TIdentifier: name := p.lexer.Identifier - if (p.fnOrArrowDataParse.await != allowIdent && name == "await") || - (p.fnOrArrowDataParse.yield != allowIdent && name == "yield") { - p.log.Add(logger.Error, &p.tracker, p.lexer.Range(), fmt.Sprintf("Cannot use %q as an identifier here:", name)) + if (p.fnOrArrowDataParse.await != allowIdent && name.String == "await") || + (p.fnOrArrowDataParse.yield != allowIdent && name.String == "yield") { + p.log.Add(logger.Error, &p.tracker, p.lexer.Range(), fmt.Sprintf("Cannot use %q as an identifier here:", name.String)) } ref := p.storeNameInRef(name) p.lexer.Next() @@ -5370,7 +5370,7 @@ func (p *parser) parseFn(name *js_ast.LocRef, data fnOrArrowDataParse) (fn js_as isTypeScriptCtorField := false isIdentifier := p.lexer.Token == js_lexer.TIdentifier - text := p.lexer.Identifier + text := p.lexer.Identifier.String arg := p.parseBinding() if p.options.ts.Parse { @@ -5388,7 +5388,7 @@ func (p *parser) parseFn(name *js_ast.LocRef, data fnOrArrowDataParse) (fn js_as if p.lexer.Token != js_lexer.TIdentifier { p.lexer.Expect(js_lexer.TIdentifier) } - text = p.lexer.Identifier + text = p.lexer.Identifier.String // Re-parse the binding (the current binding is the TypeScript keyword) arg = p.parseBinding() @@ -5508,9 +5508,9 @@ func (p *parser) parseClassStmt(loc logger.Loc, opts parseStmtOpts) js_ast.Stmt p.lexer.Expected(js_lexer.TClass) } - if !opts.isNameOptional || (p.lexer.Token == js_lexer.TIdentifier && (!p.options.ts.Parse || p.lexer.Identifier != "implements")) { + if !opts.isNameOptional || (p.lexer.Token == js_lexer.TIdentifier && (!p.options.ts.Parse || p.lexer.Identifier.String != "implements")) { nameLoc := p.lexer.Loc() - nameText := p.lexer.Identifier + nameText := p.lexer.Identifier.String p.lexer.Expect(js_lexer.TIdentifier) if p.fnOrArrowDataParse.await != allowIdent && nameText == "await" { p.log.Add(logger.Error, &p.tracker, js_lexer.RangeOfIdentifier(p.source, nameLoc), "Cannot use \"await\" as an identifier here:") @@ -5699,7 +5699,7 @@ func (p *parser) parsePath() (logger.Loc, string, *[]ast.AssertEntry) { var key []uint16 var keyText string if p.lexer.IsIdentifierOrKeyword() { - keyText = p.lexer.Identifier + keyText = p.lexer.Identifier.String key = helpers.StringToUTF16(keyText) } else if p.lexer.Token == js_lexer.TStringLiteral { key = p.lexer.StringLiteral() @@ -5769,7 +5769,7 @@ func (p *parser) parseFnStmt(loc logger.Loc, opts parseStmtOpts, isAsync bool, a // The name is optional for "export default function() {}" pseudo-statements if !opts.isNameOptional || p.lexer.Token == js_lexer.TIdentifier { nameLoc := p.lexer.Loc() - nameText = p.lexer.Identifier + nameText = p.lexer.Identifier.String if !isAsync && p.fnOrArrowDataParse.await != allowIdent && nameText == "await" { p.log.Add(logger.Error, &p.tracker, js_lexer.RangeOfIdentifier(p.source, nameLoc), "Cannot use \"await\" as an identifier here:") } @@ -5964,7 +5964,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { } if p.options.ts.Parse { - switch p.lexer.Identifier { + switch p.lexer.Identifier.String { case "type": // "export type foo = ..." typeRange := p.lexer.Range() @@ -6084,7 +6084,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { } isIdentifier := p.lexer.Token == js_lexer.TIdentifier - name := p.lexer.Identifier + name := p.lexer.Identifier.String expr := p.parseExpr(js_ast.LComma) // Handle the default export of an abstract class in TypeScript @@ -6129,7 +6129,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { p.lexer.Next() name := p.parseClauseAlias("export") namespaceRef = p.storeNameInRef(name) - alias = &js_ast.ExportStarAlias{Loc: p.lexer.Loc(), OriginalName: name} + alias = &js_ast.ExportStarAlias{Loc: p.lexer.Loc(), OriginalName: name.String} p.lexer.Next() p.lexer.ExpectContextualKeyword("from") pathLoc, pathText, assertions = p.parsePath() @@ -6138,7 +6138,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { p.lexer.ExpectContextualKeyword("from") pathLoc, pathText, assertions = p.parsePath() name := js_ast.GenerateNonUniqueNameFromPath(pathText) + "_star" - namespaceRef = p.storeNameInRef(name) + namespaceRef = p.storeNameInRef(js_lexer.MaybeSubstring{String: name}) } importRecordIndex := p.addImportRecord(ast.ImportStmt, pathLoc, pathText, assertions) @@ -6165,7 +6165,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { pathLoc, pathText, assertions := p.parsePath() importRecordIndex := p.addImportRecord(ast.ImportStmt, pathLoc, pathText, assertions) name := "import_" + js_ast.GenerateNonUniqueNameFromPath(pathText) - namespaceRef := p.storeNameInRef(name) + namespaceRef := p.storeNameInRef(js_lexer.MaybeSubstring{String: name}) // Export clause statements anywhere in the file disable top-level const // local prefix because import cycles can be used to trigger TDZ @@ -6672,10 +6672,10 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { if p.options.ts.Parse { // Skip over type-only imports - if defaultName == "type" { + if defaultName.String == "type" { switch p.lexer.Token { case js_lexer.TIdentifier: - if p.lexer.Identifier != "from" { + if p.lexer.Identifier.String != "from" { defaultName = p.lexer.Identifier stmt.DefaultName.Loc = p.lexer.Loc() p.lexer.Next() @@ -6683,7 +6683,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { // "import type foo = require('bar');" // "import type foo = bar.baz;" opts.isTypeScriptDeclare = true - return p.parseTypeScriptImportEqualsStmt(loc, opts, stmt.DefaultName.Loc, defaultName) + return p.parseTypeScriptImportEqualsStmt(loc, opts, stmt.DefaultName.Loc, defaultName.String) } else { // "import type foo from 'bar';" p.lexer.ExpectContextualKeyword("from") @@ -6716,7 +6716,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { // Parse TypeScript import assignment statements if p.lexer.Token == js_lexer.TEquals || opts.isExport || (opts.isNamespaceScope && !opts.isTypeScriptDeclare) { p.esmImportStatementKeyword = previousImportStatementKeyword // This wasn't an ESM import statement after all - return p.parseTypeScriptImportEqualsStmt(loc, opts, stmt.DefaultName.Loc, defaultName) + return p.parseTypeScriptImportEqualsStmt(loc, opts, stmt.DefaultName.Loc, defaultName.String) } } @@ -6851,7 +6851,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { default: isIdentifier := p.lexer.Token == js_lexer.TIdentifier - name := p.lexer.Identifier + name := p.lexer.Identifier.String // Parse either an async function, an async expression, or a normal expression var expr js_ast.Expr @@ -14875,7 +14875,7 @@ func Parse(log logger.Log, source logger.Source, options Options) (result js_ast // Consume a leading hashbang comment hashbang := "" if p.lexer.Token == js_lexer.THashbang { - hashbang = p.lexer.Identifier + hashbang = p.lexer.Identifier.String p.lexer.Next() } diff --git a/internal/js_parser/ts_parser.go b/internal/js_parser/ts_parser.go index 942d191415b..425d2710c4d 100644 --- a/internal/js_parser/ts_parser.go +++ b/internal/js_parser/ts_parser.go @@ -278,7 +278,7 @@ func (p *parser) skipTypeScriptTypeWithOpts(level js_ast.L, opts skipTypeOpts) { p.skipTypeScriptParenOrFnType() case js_lexer.TIdentifier: - kind := tsTypeIdentifierMap[p.lexer.Identifier] + kind := tsTypeIdentifierMap[p.lexer.Identifier.String] if kind == tsTypeIdentifierPrefix { p.lexer.Next() @@ -823,7 +823,7 @@ func (p *parser) canFollowTypeArgumentsInExpression() bool { } func (p *parser) skipTypeScriptInterfaceStmt(opts parseStmtOpts) { - name := p.lexer.Identifier + name := p.lexer.Identifier.String p.lexer.Expect(js_lexer.TIdentifier) if opts.isModuleScope { @@ -870,7 +870,7 @@ func (p *parser) skipTypeScriptTypeStmt(opts parseStmtOpts) { return } - name := p.lexer.Identifier + name := p.lexer.Identifier.String p.lexer.Expect(js_lexer.TIdentifier) if opts.isModuleScope { @@ -906,7 +906,7 @@ func (p *parser) parseTypeScriptDecorators() []js_ast.Expr { func (p *parser) parseTypeScriptEnumStmt(loc logger.Loc, opts parseStmtOpts) js_ast.Stmt { p.lexer.Expect(js_lexer.TEnum) nameLoc := p.lexer.Loc() - nameText := p.lexer.Identifier + nameText := p.lexer.Identifier.String p.lexer.Expect(js_lexer.TIdentifier) name := js_ast.LocRef{Loc: nameLoc, Ref: js_ast.InvalidRef} @@ -952,7 +952,7 @@ func (p *parser) parseTypeScriptEnumStmt(loc logger.Loc, opts parseStmtOpts) js_ value.Name = p.lexer.StringLiteral() nameText = helpers.UTF16ToString(value.Name) } else if p.lexer.IsIdentifierOrKeyword() { - nameText = p.lexer.Identifier + nameText = p.lexer.Identifier.String value.Name = helpers.StringToUTF16(nameText) } else { p.lexer.Expect(js_lexer.TIdentifier) @@ -992,7 +992,7 @@ func (p *parser) parseTypeScriptEnumStmt(loc logger.Loc, opts parseStmtOpts) js_ if p.lexer.Token == js_lexer.TStringLiteral { nextName = helpers.UTF16ToString(p.lexer.StringLiteral()) } else { - nextName = p.lexer.Identifier + nextName = p.lexer.Identifier.String } errorLoc = p.lexer.Loc() errorText = fmt.Sprintf("Expected \",\" before %q in enum", nextName) @@ -1081,7 +1081,7 @@ func (p *parser) parseTypeScriptImportEqualsStmt(loc logger.Loc, opts parseStmtO value := js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EIdentifier{Ref: p.storeNameInRef(name)}} p.lexer.Expect(js_lexer.TIdentifier) - if name == "require" && p.lexer.Token == js_lexer.TOpenParen { + if name.String == "require" && p.lexer.Token == js_lexer.TOpenParen { // "import ns = require('x')" p.lexer.Next() path := js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EString{Value: p.lexer.StringLiteral()}} @@ -1098,7 +1098,7 @@ func (p *parser) parseTypeScriptImportEqualsStmt(loc logger.Loc, opts parseStmtO p.lexer.Next() value.Data = &js_ast.EDot{ Target: value, - Name: p.lexer.Identifier, + Name: p.lexer.Identifier.String, NameLoc: p.lexer.Loc(), } p.lexer.Expect(js_lexer.TIdentifier) @@ -1158,7 +1158,7 @@ func (p *parser) getOrCreateExportedNamespaceMembers(name string, isExport bool) func (p *parser) parseTypeScriptNamespaceStmt(loc logger.Loc, opts parseStmtOpts) js_ast.Stmt { // "namespace Foo {}" nameLoc := p.lexer.Loc() - nameText := p.lexer.Identifier + nameText := p.lexer.Identifier.String p.lexer.Next() // Generate the namespace object