Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions src/go/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,19 +279,49 @@ func (op Token) Precedence() int {
return LowestPrec
}

var keywords map[string]Token
var keywords [256]Token

func init() {
keywords = make(map[string]Token, keyword_end-(keyword_beg+1))
for i := keyword_beg + 1; i < keyword_end; i++ {
keywords[tokens[i]] = i
keywords[keywordsIndex(i.String())] = i
}
}

// keywordsIndex maps an identifier to an index in keywords array.
func keywordsIndex(maybeKeyword string) uint8 {
if len(maybeKeyword) <= 3 {
// If adding a 2 or 3 letter keyword that starts with `i`(if),`f`(for) or `g`(go)
// you'd need to add logic to this if statement to differentiate between them.
if len(maybeKeyword) == 0 {
return 0
}
return maybeKeyword[0]
}
// This hash was adjusted by hand. Finding the working combinations
// for this hash is quite straightforward, even when restricting all
// operations to power-of-two multiplications and addition/subtractions
// for performance reasons since multiplication of an integer by a power-of-two
// can be optimized to a bitshift which is faster on some architectures.
//
// Here is a list of hashes that also works for current keyword set:
// h = v0 + v1*2 + v2*4 + v3*8
// h = v0 + v1*4 + v2*8 + v3
// h = v0 + v1*2 + (v2+v3)*2
// h = v0*4 + v1*2 + v2*2 + v3*2
// h = v0*4 + v1*2 + v2*v3
v0 := maybeKeyword[0]
v1 := maybeKeyword[1]
v2 := maybeKeyword[2]
v3 := maybeKeyword[3]
h := v0 + v1*8 + v2 - v3
return h
}

// Lookup maps an identifier to its keyword token or [IDENT] (if not a keyword).
func Lookup(ident string) Token {
if tok, is_keyword := keywords[ident]; is_keyword {
return tok
maybeMatch := keywords[keywordsIndex(ident)]
if maybeMatch != 0 && maybeMatch.String() == ident {
return maybeMatch
}
return IDENT
}
Expand Down Expand Up @@ -319,10 +349,9 @@ func IsExported(name string) bool {
}

// IsKeyword reports whether name is a Go keyword, such as "func" or "return".
func IsKeyword(name string) bool {
// TODO: opt: use a perfect hash function instead of a global map.
_, ok := keywords[name]
return ok
func IsKeyword(ident string) bool {
tok := keywords[keywordsIndex(ident)]
return tok != 0 && tok.String() == ident
}

// IsIdentifier reports whether name is a Go identifier, that is, a non-empty
Expand Down