diff options
author | Emile <git@emile.space> | 2024-08-16 19:50:26 +0200 |
---|---|---|
committer | Emile <git@emile.space> | 2024-08-16 19:50:26 +0200 |
commit | 1a57267a17c2fc17fb6e104846fabc3e363c326c (patch) | |
tree | 1e574e3a80622086dc3c81ff9cba65ef7049b1a9 /vendor/modernc.org/gc/v3/etc.go |
initial commit
Diffstat (limited to 'vendor/modernc.org/gc/v3/etc.go')
-rw-r--r-- | vendor/modernc.org/gc/v3/etc.go | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/vendor/modernc.org/gc/v3/etc.go b/vendor/modernc.org/gc/v3/etc.go new file mode 100644 index 0000000..fe8d8fb --- /dev/null +++ b/vendor/modernc.org/gc/v3/etc.go @@ -0,0 +1,559 @@ +// Copyright 2022 The Gc Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gc // modernc.org/gc/v3 + +import ( + "fmt" + "go/token" + "math" + "os" + "path/filepath" + "runtime" + "sort" + "strconv" + "strings" + "sync" + + "github.com/dustin/go-humanize" +) + +// The list of tokens. +const ( + // Special tokens + ILLEGAL = token.ILLEGAL + EOF = token.EOF + COMMENT = token.COMMENT + + // Identifiers and basic type literals + // (these tokens stand for classes of literals) + IDENT = token.IDENT // main + INT = token.INT // 12345 + FLOAT = token.FLOAT // 123.45 + IMAG = token.IMAG // 123.45i + CHAR = token.CHAR // 'a' + STRING = token.STRING // "abc" + + // Operators and delimiters + ADD = token.ADD // + + SUB = token.SUB // - + MUL = token.MUL // * + QUO = token.QUO // / + REM = token.REM // % + + AND = token.AND // & + OR = token.OR // | + XOR = token.XOR // ^ + SHL = token.SHL // << + SHR = token.SHR // >> + AND_NOT = token.AND_NOT // &^ + + ADD_ASSIGN = token.ADD_ASSIGN // += + SUB_ASSIGN = token.SUB_ASSIGN // -= + MUL_ASSIGN = token.MUL_ASSIGN // *= + QUO_ASSIGN = token.QUO_ASSIGN // /= + REM_ASSIGN = token.REM_ASSIGN // %= + + AND_ASSIGN = token.AND_ASSIGN // &= + OR_ASSIGN = token.OR_ASSIGN // |= + XOR_ASSIGN = token.XOR_ASSIGN // ^= + SHL_ASSIGN = token.SHL_ASSIGN // <<= + SHR_ASSIGN = token.SHR_ASSIGN // >>= + AND_NOT_ASSIGN = token.AND_NOT_ASSIGN // &^= + + LAND = token.LAND // && + LOR = token.LOR // || + ARROW = token.ARROW // <- + INC = token.INC // ++ + DEC = token.DEC // -- + + EQL = token.EQL // == + LSS = token.LSS // < + GTR = token.GTR // > + ASSIGN = token.ASSIGN // = + NOT = token.NOT // ! + + NEQ = token.NEQ // != + LEQ = token.LEQ // <= + GEQ = token.GEQ // >= + DEFINE = token.DEFINE // := + ELLIPSIS = token.ELLIPSIS // ... + + LPAREN = token.LPAREN // ( + LBRACK = token.LBRACK // [ + LBRACE = token.LBRACE // { + COMMA = token.COMMA // , + PERIOD = token.PERIOD // . + + RPAREN = token.RPAREN // ) + RBRACK = token.RBRACK // ] + RBRACE = token.RBRACE // } + SEMICOLON = token.SEMICOLON // ; + COLON = token.COLON // : + + // Keywords + BREAK = token.BREAK + CASE = token.CASE + CHAN = token.CHAN + CONST = token.CONST + CONTINUE = token.CONTINUE + + DEFAULT = token.DEFAULT + DEFER = token.DEFER + ELSE = token.ELSE + FALLTHROUGH = token.FALLTHROUGH + FOR = token.FOR + + FUNC = token.FUNC + GO = token.GO + GOTO = token.GOTO + IF = token.IF + IMPORT = token.IMPORT + + INTERFACE = token.INTERFACE + MAP = token.MAP + PACKAGE = token.PACKAGE + RANGE = token.RANGE + RETURN = token.RETURN + + SELECT = token.SELECT + STRUCT = token.STRUCT + SWITCH = token.SWITCH + TYPE = token.TYPE + VAR = token.VAR + + // additional tokens, handled in an ad-hoc manner + TILDE = token.TILDE +) + +var ( + trcTODOs bool + extendedErrors bool +) + +// origin returns caller's short position, skipping skip frames. +func origin(skip int) string { + pc, fn, fl, _ := runtime.Caller(skip) + f := runtime.FuncForPC(pc) + var fns string + if f != nil { + fns = f.Name() + if x := strings.LastIndex(fns, "."); x > 0 { + fns = fns[x+1:] + } + if strings.HasPrefix(fns, "func") { + num := true + for _, c := range fns[len("func"):] { + if c < '0' || c > '9' { + num = false + break + } + } + if num { + return origin(skip + 2) + } + } + } + return fmt.Sprintf("%s:%d:%s", filepath.Base(fn), fl, fns) +} + +// todo prints and returns caller's position and an optional message tagged with TODO. Output goes to stderr. +// +//lint:ignore U1000 whatever +func todo(s string, args ...interface{}) string { + switch { + case s == "": + s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...) + default: + s = fmt.Sprintf(s, args...) + } + r := fmt.Sprintf("%s\n\tTODO (%s)", origin(2), s) + // fmt.Fprintf(os.Stderr, "%s\n", r) + // os.Stdout.Sync() + return r +} + +// trc prints and returns caller's position and an optional message tagged with TRC. Output goes to stderr. +// +//lint:ignore U1000 whatever +func trc(s string, args ...interface{}) string { + switch { + case s == "": + s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...) + default: + s = fmt.Sprintf(s, args...) + } + r := fmt.Sprintf("%s: TRC (%s)", origin(2), s) + fmt.Fprintf(os.Stderr, "%s\n", r) + os.Stderr.Sync() + return r +} + +func extractPos(s string) (p token.Position, ok bool) { + var prefix string + if len(s) > 1 && s[1] == ':' { // c:\foo + prefix = s[:2] + s = s[2:] + } + // "testdata/parser/bug/001.c:1193: ..." + a := strings.Split(s, ":") + // ["testdata/parser/bug/001.c" "1193" "..."] + if len(a) < 2 { + return p, false + } + + line, err := strconv.Atoi(a[1]) + if err != nil { + return p, false + } + + col, err := strconv.Atoi(a[2]) + if err != nil { + col = 1 + } + + return token.Position{Filename: prefix + a[0], Line: line, Column: col}, true +} + +// errorf constructs an error value. If extendedErrors is true, the error will +// contain its origin. +func errorf(s string, args ...interface{}) error { + switch { + case s == "": + s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...) + default: + s = fmt.Sprintf(s, args...) + } + if trcTODOs && strings.HasPrefix(s, "TODO") { + fmt.Fprintf(os.Stderr, "%s (%v)\n", s, origin(2)) + os.Stderr.Sync() + } + switch { + case extendedErrors: + return fmt.Errorf("%s (%v: %v: %v)", s, origin(4), origin(3), origin(2)) + default: + return fmt.Errorf("%s", s) + } +} + +func tokSource(t token.Token) string { + switch t { + case ILLEGAL: + return "ILLEGAL" + case EOF: + return "EOF" + case COMMENT: + return "COMMENT" + case IDENT: + return "IDENT" + case INT: + return "INT" + case FLOAT: + return "FLOAT" + case IMAG: + return "IMAG" + case CHAR: + return "CHAR" + case STRING: + return "STRING" + case ADD: + return "ADD" + case SUB: + return "SUB" + case MUL: + return "MUL" + case QUO: + return "QUO" + case REM: + return "REM" + case AND: + return "AND" + case OR: + return "OR" + case XOR: + return "XOR" + case SHL: + return "SHL" + case SHR: + return "SHR" + case AND_NOT: + return "AND_NOT" + case ADD_ASSIGN: + return "ADD_ASSIGN" + case SUB_ASSIGN: + return "SUB_ASSIGN" + case MUL_ASSIGN: + return "MUL_ASSIGN" + case QUO_ASSIGN: + return "QUO_ASSIGN" + case REM_ASSIGN: + return "REM_ASSIGN" + case AND_ASSIGN: + return "AND_ASSIGN" + case OR_ASSIGN: + return "OR_ASSIGN" + case XOR_ASSIGN: + return "XOR_ASSIGN" + case SHL_ASSIGN: + return "SHL_ASSIGN" + case SHR_ASSIGN: + return "SHR_ASSIGN" + case AND_NOT_ASSIGN: + return "AND_NOT_ASSIGN" + case LAND: + return "LAND" + case LOR: + return "LOR" + case ARROW: + return "ARROW" + case INC: + return "INC" + case DEC: + return "DEC" + case EQL: + return "EQL" + case LSS: + return "LSS" + case GTR: + return "GTR" + case ASSIGN: + return "ASSIGN" + case NOT: + return "NOT" + case NEQ: + return "NEQ" + case LEQ: + return "LEQ" + case GEQ: + return "GEQ" + case DEFINE: + return "DEFINE" + case ELLIPSIS: + return "ELLIPSIS" + case LPAREN: + return "LPAREN" + case LBRACK: + return "LBRACK" + case LBRACE: + return "LBRACE" + case COMMA: + return "COMMA" + case PERIOD: + return "PERIOD" + case RPAREN: + return "RPAREN" + case RBRACK: + return "RBRACK" + case RBRACE: + return "RBRACE" + case SEMICOLON: + return "SEMICOLON" + case COLON: + return "COLON" + case BREAK: + return "BREAK" + case CASE: + return "CASE" + case CHAN: + return "CHAN" + case CONST: + return "CONST" + case CONTINUE: + return "CONTINUE" + case DEFAULT: + return "DEFAULT" + case DEFER: + return "DEFER" + case ELSE: + return "ELSE" + case FALLTHROUGH: + return "FALLTHROUGH" + case FOR: + return "FOR" + case FUNC: + return "FUNC" + case GO: + return "GO" + case GOTO: + return "GOTO" + case IF: + return "IF" + case IMPORT: + return "IMPORT" + case INTERFACE: + return "INTERFACE" + case MAP: + return "MAP" + case PACKAGE: + return "PACKAGE" + case RANGE: + return "RANGE" + case RETURN: + return "RETURN" + case SELECT: + return "SELECT" + case STRUCT: + return "STRUCT" + case SWITCH: + return "SWITCH" + case TYPE: + return "TYPE" + case VAR: + return "VAR" + case TILDE: + return "TILDE" + default: + panic(todo("", int(t), t)) + } +} + +type data struct { + line int + cases int + cnt int +} + +type analyzer struct { + sync.Mutex + m map[int]*data // line: data +} + +func newAnalyzer() *analyzer { + return &analyzer{m: map[int]*data{}} +} + +func (a *analyzer) record(line, cnt int) { + d := a.m[line] + if d == nil { + d = &data{line: line} + a.m[line] = d + } + d.cases++ + d.cnt += cnt +} + +func (a *analyzer) merge(b *analyzer) { + a.Lock() + defer a.Unlock() + + for k, v := range b.m { + d := a.m[k] + if d == nil { + d = &data{line: k} + a.m[k] = d + } + d.cases += v.cases + d.cnt += v.cnt + } +} + +func (a *analyzer) report() string { + var rows []*data + for _, v := range a.m { + rows = append(rows, v) + } + sort.Slice(rows, func(i, j int) bool { + a := rows[i] + b := rows[j] + if a.cases < b.cases { + return true + } + + if a.cases > b.cases { + return false + } + + // a.cases == b.cases + if a.cnt < b.cnt { + return true + } + + if a.cnt > b.cnt { + return false + } + + // a.cnt == b.cnt + return a.line < b.line + }) + var b strings.Builder + var cases, cnt int + for _, row := range rows { + cases += row.cases + cnt += row.cnt + avg := float64(row.cnt) / float64(row.cases) + fmt.Fprintf(&b, "parser.go:%d:\t%16s %16s %8.1f\n", row.line, h(row.cases), h(row.cnt), avg) + } + avg := float64(cnt) / float64(cases) + fmt.Fprintf(&b, "<total>\t\t%16s %16s %8.1f\n", h(cases), h(cnt), avg) + return b.String() +} + +func h(v interface{}) string { + switch x := v.(type) { + case int: + return humanize.Comma(int64(x)) + case int32: + return humanize.Comma(int64(x)) + case int64: + return humanize.Comma(x) + case uint32: + return humanize.Comma(int64(x)) + case uint64: + if x <= math.MaxInt64 { + return humanize.Comma(int64(x)) + } + + return "-" + humanize.Comma(-int64(x)) + } + return fmt.Sprint(v) +} + +type parallel struct { + limiter chan struct{} +} + +func newParallel() *parallel { + return ¶llel{ + limiter: make(chan struct{}, runtime.GOMAXPROCS(0)), + } +} + +func (p *parallel) throttle(f func()) { + p.limiter <- struct{}{} + + defer func() { + <-p.limiter + }() + + f() +} + +func extraTags(verMajor, verMinor int, goos, goarch string) (r []string) { + // https://github.com/golang/go/commit/eeb7899137cda1c2cd60dab65ff41f627436db5b + // + // In Go 1.17 we added register ABI on AMD64 on Linux/macOS/Windows + // as a GOEXPERIMENT, on by default. In Go 1.18, we commit to always + // enabling register ABI on AMD64. + // + // Now "go build" for AMD64 always have goexperiment.regabi* tags + // set. However, at bootstrapping cmd/dist does not set the tags + // when building go_bootstrap. For this to work, unfortunately, we + // need to hard-code AMD64 to use register ABI in runtime code. + if verMajor == 1 { + switch { + case verMinor == 17: + switch goos { + case "linux", "darwin", "windows": + if goarch == "amd64" { + r = append(r, "goexperiment.regabiargs", "goexperiment.regabiwrappers") + } + } + case verMinor >= 18: + if goarch == "amd64" { + r = append(r, "goexperiment.regabiargs", "goexperiment.regabiwrappers") + } + } + } + return r +} |