about summary refs log tree commit diff
path: root/vendor/modernc.org/gc/v3/etc.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/modernc.org/gc/v3/etc.go')
-rw-r--r--vendor/modernc.org/gc/v3/etc.go559
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 &parallel{
+		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
+}