Compare commits

..

17 Commits

Author SHA1 Message Date
Marc Vertes
0a5b16cad6 feat: support go1.22
* feat: support go1.22

* Temporary fix for consistency tests due to language change in for loops

* review: clean old files

---------

Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
2024-03-05 17:56:04 +01:00
Ludovic Fernandez
1990b96ccd update to go1.21 (#1598)
* feat: generate go1.21 files

* chore: update CI

* feat: add support for generic symbols in standard library packages

This is necessary to fully support go1.21 and beyond, which now
provide some generic packages such as `cmp`, `maps` or `slices`
in the standard library.

The principle is to embed the generic symbols in source form (as
strings) so they can be instantiated as required during interpretation.

Extract() has been modified to skip the generic types, functions and
constraint interfaces which can't be represented as reflect.Values.

A new stdlib/generic package has been added to provide the corresponding
source files as embedded strings.

The `Use()` function has been changed to pre-parse generic symbols as
doing lazy parsing was causing cyclic dependencies issues at compiling.
This is something we may improve in the future.

A unit test using `cmp` has been added.

For now, there are still some issues with generic stdlib packages
inter-dependencies, for example `slices` importing `cmp`, or when
generic types or function signatures depends on pre-compiled types
in the same package, which we will support shortly.

* fixup

* fixup

* fixup

* fixup

* fixup

* fixup

* fixes for go1.20

* fix previous

* update unsafe2 for go1.21, skip faky tests

In go1.21, the reflect rtype definition has been move to internal/abi.
We follow this change for maintainability, even if there is no layout
change (the go1.20 unsafe2 is compatible with go1.21).

We have isolated a few problematic tests which are failing sometimes
in go1.21, but work in go1.20, and also in go1.22. Those tests are
skipped if in go1.21. A preliminary investigation can not confirm that
something is wrong in yaegi, and the problem disappears with go1.22.

* add new wrapper for go1.21 package testing/slogtest

* add missing wrapper for go/doc/comment

* add support for slices generic package

---------

Co-authored-by: Marc Vertes <mvertes@free.fr>
2024-03-04 12:00:25 +01:00
Denys Smirnov
da27c4fbc2 interp: Add wasip1 to known OS list
Adds `wasip1` to known OS list, introduced in golang/go#58141.

Without this change, `yaegi extract` may fail on Go 1.21 with the following message:
```
type-checking package "time" failed (<GOROOT>/src/time/zoneinfo_wasip1.go:8:5: platformZoneSources redeclared in this block)
```
2023-09-27 00:22:05 +02:00
Denys Smirnov
f5b5481794 interp: Record function names in panic
Currently, yaegi only records source positions when writing panic trace to stderr.

This change adds function names to the panic output.

Unfortunately, yaegi walks the trace in reverse order, comparing to Go runtime. This can be improved in the future.
2023-09-23 12:24:05 +02:00
Marc Vertes
79b7420ee1 interp: fix issue where a var is reused instead of redefined
Avoid a spurious optimisation which forces a variable to be reused instead of redefined for assignment operation. This ensures that a variable defined in a loop is re-allocated, preserving the previous instance when used by a closure for example.

Fix #1594
2023-09-21 23:00:06 +02:00
Ludovic Fernandez
8a6061cc86 chore: update linter
update golangci-lint to v1.53.3
2023-07-02 10:28:05 +02:00
bysir
c10e468d01 interp: fix fieldName method parsing embedded + generic fields
Fix https://github.com/traefik/yaegi/issues/1571
2023-07-01 12:58:05 +02:00
Hiro
75e5f99bc5 doc: fix go install cmd 2023-06-20 02:38:06 +02:00
Hiro
79e32b5a92 doc: install using go install
- Update markdown to document `go install` as the preferred way for the installation of yaegi REPL
2023-06-20 01:46:05 +02:00
Fernandez Ludovic
63b8cc42b9 doc: update readme 2023-06-19 14:07:06 +02:00
Marc Vertes
f4a9cd3cbe stdlib: remove embed wrapper
Embedding files using `//go:embed` and `embed` packages can not be supported in yaegi, so it is better to not generate the wrapper to embed and have a graceful error in case of usage of `embed.FS` in the interpreter.
Also update README about unsuported directives.

Fixes #1557.
2023-06-14 19:04:05 +02:00
laushunyu
6447a677f3 fix(src): use errors.Is(err, fs.ErrNotExist)
I implemented fs.FS. When the file does not exist, `xerrors.Wrap(fs.ErrNotExist, "")` will be returned. However, `os.IsNotExist` cannot handle this situation. I found the following comment:
```
// IsNotExist returns a boolean indicating whether the error is known to
// report that a file or directory does not exist. It is satisfied by
// ErrNotExist as well as some syscall errors.
//
// This function predates errors.Is. It only supports errors returned by
// the os package. New code should use errors.Is(err, fs.ErrNotExist).
```

Therefore, we should use `errors.Is(err, fs.ErrNotExist)` instead.
2023-06-14 17:00:12 +02:00
Marc Vertes
68a430f969 interp: fix support of type assert expressions in the global scope
Add the support of type assert expressions in type parsing
which allows to process type assertions in the global scope.

Fixes #1543.
2023-04-26 10:52:05 +02:00
Marc Vertes
dc7c64ba88 interp: improve support of unsafe
Unsafe functions such as `unsafe.Alignof`, `unsafe.Offsetof` and `unsafe.Sizeof` can be used for type declarations early on during compile, and as such, must be treated as builtins returning constants at compile time. It is still necessary to explicitely enable unsafe support in yaegi.

The support of `unsafe.Add` has also been added.

Fixes #1544.
2023-04-26 10:16:05 +02:00
Marc Vertes
d6ad13acea interp: improve handling of embedded fields with binary methods
Only structures with one embedded field can be marked anonymous, due to golang/go#15924. Also check only that the method is defined, do not verify its complete signature, as the receiver may or not be defined in the arguments of the method.

Fixes #1537.
2023-04-13 18:16:05 +02:00
Marc Vertes
d124954a7d interp: fix computation of array size from constant expression
The result of the expression giving the size of an array may be an `int` instead of `constant.Value` in case of an out of order declaration. Handle both cases.

Fixes #1536.
2023-04-11 17:54:05 +02:00
Senan Kelly
8de3add6fa extract: escape ~ in package names
consider packages from git.sr.ht, the user namespace is prefixed with `~`

so running something like `yaegi extract git.sr.ht/~emersion/scfg`

was producing syntax errors with `~` in identifiers. and also `~` in filenames which worked but probably best not to have it there either

thanks!
2023-03-27 19:08:05 +02:00
595 changed files with 11336 additions and 4929 deletions

View File

@@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
go-version: [ 1.19, '1.20' ]
go-version: [ '1.21', '1.22' ]
os: [ubuntu-latest, macos-latest, windows-latest]
include:

View File

@@ -7,8 +7,8 @@ on:
pull_request:
env:
GO_VERSION: 1.19
GOLANGCI_LINT_VERSION: v1.47.1
GO_VERSION: '1.22'
GOLANGCI_LINT_VERSION: v1.55.2
jobs:
@@ -45,7 +45,7 @@ jobs:
needs: linting
strategy:
matrix:
go-version: [ 1.19, '1.20' ]
go-version: [ '1.21', '1.22' ]
steps:
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v2
@@ -76,7 +76,7 @@ jobs:
working-directory: ${{ github.workspace }}/go/src/github.com/traefik/yaegi
strategy:
matrix:
go-version: [ 1.19, '1.20' ]
go-version: [ '1.21', '1.22' ]
steps:
- name: Set up Go ${{ matrix.go-version }}

View File

@@ -6,7 +6,7 @@ on:
- v[0-9]+.[0-9]+*
env:
GO_VERSION: '1.20'
GO_VERSION: '1.21'
jobs:

View File

@@ -1,92 +0,0 @@
[run]
deadline = "5m"
skip-files = []
[linters-settings]
[linters-settings.govet]
check-shadowing = false
[linters-settings.gocyclo]
min-complexity = 12.0
[linters-settings.maligned]
suggest-new = true
[linters-settings.goconst]
min-len = 3.0
min-occurrences = 3.0
[linters-settings.misspell]
locale = "US"
[linters]
enable-all = true
disable = [
"golint", # deprecated
"scopelint", # deprecated
"interfacer", # deprecated
"maligned", # deprecated
"exhaustivestruct", # deprecated
"lll",
"gas",
"dupl",
"prealloc",
"gocyclo",
"cyclop",
"gochecknoinits",
"gochecknoglobals",
"wsl",
"nlreturn",
"godox",
"funlen",
"gocognit",
"stylecheck",
"gomnd",
"testpackage",
"paralleltest",
"tparallel",
"goerr113",
"wrapcheck",
"nestif",
"exhaustive",
"exhaustruct",
"forbidigo",
"ifshort",
"forcetypeassert",
"varnamelen",
"nosnakecase",
"nonamedreturns",
"nilnil",
"maintidx",
"errorlint", # TODO: must be reactivate before fixes
]
[issues]
exclude-use-default = false
max-per-linter = 0
max-same-issues = 0
exclude = []
[[issues.exclude-rules]]
path = ".+_test\\.go"
linters = ["goconst"]
[[issues.exclude-rules]]
path = ".+_test\\.go"
text = "var-declaration:"
[[issues.exclude-rules]]
path = "interp/interp.go"
text = "`in` can be `io.Reader`"
[[issues.exclude-rules]]
path = "interp/interp.go"
text = "`out` can be `io.Writer`"
[[issues.exclude-rules]]
path = "interp/interp.go"
text = "`Panic` should conform to the `XxxError` format"
[[issues.exclude-rules]]
path = "interp/interp_eval_test.go"
linters = ["thelper"]
[[issues.exclude-rules]]
path = "interp/debugger.go"
linters = ["containedctx"]

165
.golangci.yml Normal file
View File

@@ -0,0 +1,165 @@
run:
timeout: 10m
skip-files: []
linters-settings:
govet:
check-shadowing: false
gocyclo:
min-complexity: 12
maligned:
suggest-new: true
goconst:
min-len: 3
min-occurrences: 3
funlen:
lines: -1
statements: 50
misspell:
locale: US
depguard:
rules:
main:
files:
- $all
allow:
- $gostd
- github.com/traefik/yaegi
tagalign:
align: false
order:
- xml
- json
- yaml
- yml
- toml
- mapstructure
- url
godox:
keywords:
- FIXME
gocritic:
enabled-tags:
- diagnostic
- style
- performance
disabled-checks:
- paramTypeCombine # already handle by gofumpt.extra-rules
- whyNoLint # already handle by nonolint
- unnamedResult
- hugeParam
- sloppyReassign
- rangeValCopy
- octalLiteral
- ptrToRefParam
- appendAssign
- ruleguard
- httpNoBody
- exposedSyncMutex
- importShadow # TODO should be fixed
- commentedOutCode # TODO should be fixed
revive:
rules:
- name: struct-tag
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
- name: error-strings
- name: error-naming
- name: exported
disabled: true
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
disabled: true
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unused-parameter
disabled: true
- name: unreachable-code
- name: redefines-builtin-id
linters:
enable-all: true
disable:
- deadcode # deprecated
- exhaustivestruct # deprecated
- golint # deprecated
- ifshort # deprecated
- interfacer # deprecated
- maligned # deprecated
- nosnakecase # deprecated
- scopelint # deprecated
- structcheck # deprecated
- varcheck # deprecated
- cyclop # duplicate of gocyclo
- sqlclosecheck # not relevant (SQL)
- rowserrcheck # not relevant (SQL)
- execinquery # not relevant (SQL)
- lll
- gas
- dupl
- prealloc
- gocyclo
- cyclop
- gochecknoinits
- gochecknoglobals
- wsl
- nlreturn
- godox
- funlen
- gocognit
- stylecheck
- gomnd
- testpackage
- paralleltest
- tparallel
- goerr113
- wrapcheck
- nestif
- exhaustive
- exhaustruct
- forbidigo
- ifshort
- forcetypeassert
- varnamelen
- nosnakecase
- nonamedreturns
- nilnil
- maintidx
- dupword # false positives
- errorlint # TODO: must be reactivate after fixes
issues:
exclude-use-default: false
max-per-linter: 0
max-same-issues: 0
exclude: []
exclude-rules:
- path: .+_test\.go
linters:
- goconst
- path: .+_test\.go
text: 'var-declaration:'
- path: interp/interp.go
text: '`in` can be `io.Reader`'
- path: interp/interp.go
text: '`out` can be `io.Writer`'
- path: interp/interp.go
text: '`Panic` should conform to the `XxxError` format'
- path: interp/interp_eval_test.go
linters:
- thelper
- path: interp/debugger.go
linters:
- containedctx

View File

@@ -27,4 +27,15 @@ tests:
install.sh: .goreleaser.yml
godownloader --repo=traefik/yaegi -o install.sh .goreleaser.yml
.PHONY: check gen_all_syscall gen_tests generate_downloader internal/cmd/extract/extract install
generic_list = cmp/cmp.go slices/slices.go slices/sort.go slices/zsortanyfunc.go maps/maps.go \
sync/oncefunc.go sync/atomic/type.go
# get_generic_src imports stdlib files containing generic symbols definitions
get_generic_src:
eval "`go env`"; echo $$GOROOT; gov=$${GOVERSION#*.}; gov=$${gov%.*}; \
for f in ${generic_list}; do \
nf=stdlib/generic/go1_$${gov}_`echo $$f | tr / _`.txt; echo "nf: $$nf"; \
cat "$$GOROOT/src/$$f" > "$$nf"; \
done
.PHONY: check gen_all_syscall internal/cmd/extract/extract get_generic_src install

View File

@@ -5,7 +5,6 @@
[![release](https://img.shields.io/github/tag-date/traefik/yaegi.svg?label=alpha)](https://github.com/traefik/yaegi/releases)
[![Build Status](https://github.com/traefik/yaegi/actions/workflows/main.yml/badge.svg)](https://github.com/traefik/yaegi/actions/workflows/main.yml)
[![GoDoc](https://godoc.org/github.com/traefik/yaegi?status.svg)](https://pkg.go.dev/mod/github.com/traefik/yaegi)
[![Discourse status](https://img.shields.io/discourse/https/community.traefik.io/status?label=Community&style=social)](https://community.traefik.io/c/yaegi)
Yaegi is Another Elegant Go Interpreter.
It powers executable Go scripts and plugins, in embedded interpreters or interactive shells, on top of the Go runtime.
@@ -18,7 +17,7 @@ It powers executable Go scripts and plugins, in embedded interpreters or interac
* Works everywhere Go works
* All Go & runtime resources accessible from script (with control)
* Security: `unsafe` and `syscall` packages neither used nor exported by default
* Support Go 1.18 and Go 1.19 (the latest 2 major releases)
* Support the latest 2 major releases of Go (Go 1.21 and Go 1.22)
## Install
@@ -31,7 +30,7 @@ import "github.com/traefik/yaegi/interp"
### Command-line executable
```bash
go get -u github.com/traefik/yaegi/cmd/yaegi
go install github.com/traefik/yaegi/cmd/yaegi@latest
```
Note that you can use [rlwrap](https://github.com/hanslub42/rlwrap) (install with your favorite package manager),
@@ -173,6 +172,7 @@ Beside the known [bugs] which are supposed to be fixed in the short term, there
- Assembly files (`.s`) are not supported.
- Calling C code is not supported (no virtual "C" package).
- Directives about the compiler, the linker, or embedding files are not supported.
- Interfaces to be used from the pre-compiled code can not be added dynamically, as it is required to pre-compile interface wrappers.
- Representation of types by `reflect` and printing values using %T may give different results between compiled mode and interpreted mode.
- Interpreting computation intensive code is likely to remain significantly slower than in compiled mode.

View File

@@ -15,11 +15,10 @@ func main() {
r := extendedRequest{}
req := &r.Request
fmt.Println(r)
fmt.Println(req)
fmt.Printf("%T\n", r.Request)
fmt.Printf("%T\n", req)
}
// Output:
// {{ <nil> 0 0 map[] <nil> <nil> 0 [] false map[] map[] <nil> map[] <nil> <nil> <nil> <nil>} }
// &{ <nil> 0 0 map[] <nil> <nil> 0 [] false map[] map[] <nil> map[] <nil> <nil> <nil> <nil>}
// http.Request
// *http.Request

11
_test/assert4.go Normal file
View File

@@ -0,0 +1,11 @@
package main
var cc interface{} = 2
var dd = cc.(int)
func main() {
println(dd)
}
// Output:
// 2

15
_test/issue-1536.go Normal file
View File

@@ -0,0 +1,15 @@
package main
var a [len(prefix+path) + 2]int
const (
prefix = "/usr/"
path = prefix + "local/bin"
)
func main() {
println(len(a))
}
// Output:
// 21

20
_test/issue-1571.go Normal file
View File

@@ -0,0 +1,20 @@
package main
type A struct {
*B[string]
}
type B[T any] struct {
data T
}
func main() {
_ = &A{
B: &B[string]{},
}
println("PASS")
}
// Output:
// PASS

17
_test/issue-1594.go Normal file
View File

@@ -0,0 +1,17 @@
package main
func main() {
var fns []func()
for _, v := range []int{1, 2, 3} {
x := v*100 + v
fns = append(fns, func() { println(x) })
}
for _, fn := range fns {
fn()
}
}
// Output:
// 101
// 202
// 303

32
_test/method40.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"bytes"
"io"
)
type TMemoryBuffer struct {
*bytes.Buffer
size int
}
func newTMemoryBuffer() *TMemoryBuffer {
return &TMemoryBuffer{}
}
var globalMemoryBuffer = newTMemoryBuffer()
type TTransport interface {
io.ReadWriter
}
func check(t TTransport) {
println("ok")
}
func main() {
check(globalMemoryBuffer)
}
// Output:
// ok

20
_test/panic0.go Normal file
View File

@@ -0,0 +1,20 @@
package main
func main() {
foo()
}
func foo() {
bar()
}
func bar() {
baz()
}
func baz() {
panic("stop!")
}
// Error:
// stop!

17
_test/unsafe10.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "unsafe"
type T struct {
X uint64
Y uint64
}
func f(off uintptr) { println(off) }
func main() {
f(unsafe.Offsetof(T{}.Y))
}
// Output:
// 8

View File

@@ -21,3 +21,6 @@ func main() {
fmt.Println(i)
}
// Output:
// 5

18
_test/unsafe8.go Normal file
View File

@@ -0,0 +1,18 @@
package main
import "unsafe"
type T struct {
i uint64
}
var d T
var b [unsafe.Sizeof(d)]byte
func main() {
println(len(b))
}
// Output:
// 8

View File

@@ -69,7 +69,7 @@ func extractCmd(arg []string) error {
ext.Include = strings.Split(include, ",")
}
r := strings.NewReplacer("/", "-", ".", "_")
r := strings.NewReplacer("/", "-", ".", "_", "~", "_")
for _, pkgIdent := range args {
var buf bytes.Buffer

View File

@@ -128,7 +128,7 @@ func TestPackages(t *testing.T) {
if test.topImport != "" {
topImport = test.topImport
}
if _, err = i.Eval(fmt.Sprintf(`import "%s"`, topImport)); err != nil {
if _, err = i.Eval(fmt.Sprintf(`import %q`, topImport)); err != nil {
t.Fatal(err)
}
value, err := i.Eval(`pkg.NewSample()`)

View File

@@ -39,7 +39,9 @@ import (
"{{$key}}"
{{- end}}
{{- end}}
{{- if or .Val .Typ }}
"{{.ImportPath}}"
{{- end}}
"reflect"
)
@@ -130,9 +132,18 @@ func matchList(name string, list []string) (match bool, err error) {
return
}
// Extractor creates a package with all the symbols from a dependency package.
type Extractor struct {
Dest string // The name of the created package.
License string // License text to be included in the created package, optional.
Exclude []string // Comma separated list of regexp matching symbols to exclude.
Include []string // Comma separated list of regexp matching symbols to include.
Tag []string // Comma separated of build tags to be added to the created package.
}
func (e *Extractor) genContent(importPath string, p *types.Package) ([]byte, error) {
prefix := "_" + importPath + "_"
prefix = strings.NewReplacer("/", "_", "-", "_", ".", "_").Replace(prefix)
prefix = strings.NewReplacer("/", "_", "-", "_", ".", "_", "~", "_").Replace(prefix)
typ := map[string]string{}
val := map[string]Val{}
@@ -190,6 +201,10 @@ func (e *Extractor) genContent(importPath string, p *types.Package) ([]byte, err
val[name] = Val{pname, false}
}
case *types.Func:
// Skip generic functions and methods.
if s := o.Type().(*types.Signature); s.TypeParams().Len() > 0 || s.RecvTypeParams().Len() > 0 {
continue
}
val[name] = Val{pname, false}
case *types.Var:
val[name] = Val{pname, true}
@@ -198,9 +213,13 @@ func (e *Extractor) genContent(importPath string, p *types.Package) ([]byte, err
if t, ok := o.Type().(*types.Named); ok && t.TypeParams().Len() > 0 {
continue
}
typ[name] = pname
if t, ok := o.Type().Underlying().(*types.Interface); ok {
if t.NumMethods() == 0 && t.NumEmbeddeds() != 0 {
// Skip interfaces used to implement constraints for generics.
delete(typ, name)
continue
}
var methods []Method
for i := 0; i < t.NumMethods(); i++ {
f := t.Method(i)
@@ -283,11 +302,11 @@ func (e *Extractor) genContent(importPath string, p *types.Package) ([]byte, err
}
for _, t := range e.Tag {
if len(t) != 0 {
if t != "" {
buildTags += "," + t
}
}
if len(buildTags) != 0 && buildTags[0] == ',' {
if buildTags != "" && buildTags[0] == ',' {
buildTags = buildTags[1:]
}
@@ -340,7 +359,7 @@ func fixConst(name string, val constant.Value, imports map[string]bool) string {
str = f.Text('g', int(f.Prec()))
case constant.Complex:
// TODO: not sure how to parse this case
fallthrough
fallthrough //nolint:gocritic // Empty Fallthrough is expected.
default:
return name
}
@@ -351,15 +370,6 @@ func fixConst(name string, val constant.Value, imports map[string]bool) string {
return fmt.Sprintf("constant.MakeFromLiteral(%q, token.%s, 0)", str, tok)
}
// Extractor creates a package with all the symbols from a dependency package.
type Extractor struct {
Dest string // The name of the created package.
License string // License text to be included in the created package, optional.
Exclude []string // Comma separated list of regexp matching symbols to exclude.
Include []string // Comma separated list of regexp matching symbols to include.
Tag []string // Comma separated of build tags to be added to the created package.
}
// importPath checks whether pkgIdent is an existing directory relative to
// e.WorkingDir. If yes, it returns the actual import path of the Go package
// located in the directory. If it is definitely a relative path, but it does not
@@ -468,7 +478,7 @@ func GetMinor(part string) string {
return minor
}
const defaultMinorVersion = 20
const defaultMinorVersion = 22
func genBuildTags() (string, error) {
version := runtime.Version()

2
go.mod
View File

@@ -1,3 +1,3 @@
module github.com/traefik/yaegi
go 1.18
go 1.21

View File

@@ -1,3 +1,6 @@
//go:build !go1.21
// +build !go1.21
// Package unsafe2 provides helpers to generate recursive struct types.
package unsafe2

View File

@@ -0,0 +1,72 @@
//go:build go1.21
// +build go1.21
// Package unsafe2 provides helpers to generate recursive struct types.
package unsafe2
import (
"reflect"
"unsafe"
)
type dummy struct{}
// DummyType represents a stand-in for a recursive type.
var DummyType = reflect.TypeOf(dummy{})
// The following type sizes must match their original definition in Go src/internal/abi/type.go.
type abiType struct {
_ uintptr
_ uintptr
_ uint32
_ uint8
_ uint8
_ uint8
_ uint8
_ uintptr
_ uintptr
_ int32
_ int32
}
type abiName struct {
Bytes *byte
}
type abiStructField struct {
Name abiName
Typ *abiType
Offset uintptr
}
type abiStructType struct {
abiType
PkgPath abiName
Fields []abiStructField
}
type emptyInterface struct {
typ *abiType
_ unsafe.Pointer
}
// SetFieldType sets the type of the struct field at the given index, to the given type.
//
// The struct type must have been created at runtime. This is very unsafe.
func SetFieldType(s reflect.Type, idx int, t reflect.Type) {
if s.Kind() != reflect.Struct || idx >= s.NumField() {
return
}
rtyp := unpackType(s)
styp := (*abiStructType)(unsafe.Pointer(rtyp))
f := styp.Fields[idx]
f.Typ = unpackType(t)
styp.Fields[idx] = f
}
func unpackType(t reflect.Type) *abiType {
v := reflect.New(t).Elem().Interface()
eface := *(*emptyInterface)(unsafe.Pointer(&v))
return eface.typ
}

View File

@@ -182,6 +182,7 @@ var knownOs = map[string]bool{
"openbsd": true,
"plan9": true,
"solaris": true,
"wasip1": true,
"windows": true,
}

View File

@@ -45,6 +45,13 @@ var constBltn = map[string]func(*node){
const nilIdent = "nil"
func init() {
// Use init() to avoid initialization cycles for the following constant builtins.
constBltn[bltnAlignof] = alignof
constBltn[bltnOffsetof] = offsetof
constBltn[bltnSizeof] = sizeof
}
// cfg generates a control flow graph (CFG) from AST (wiring successors in AST)
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
// variables. A list of nodes of init functions is returned.
@@ -422,7 +429,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
case funcDecl:
// Do not allow function declarations without body.
if len(n.child) < 4 {
err = n.cfgErrorf("function declaration without body is unsupported (linkname or assembly can not be interpreted).")
err = n.cfgErrorf("missing function body")
return false
}
n.val = n
@@ -748,7 +755,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
n.gen = nop
src.findex = dest.findex
src.level = level
case len(n.child) < 4 && isArithmeticAction(src) && !isInterface(dest.typ):
case len(n.child) < 4 && n.kind != defineStmt && isArithmeticAction(src) && !isInterface(dest.typ):
// Optimize single assignments from some arithmetic operations.
src.typ = dest.typ
src.findex = dest.findex
@@ -1154,6 +1161,10 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
case n.typ.cat == builtinT:
n.findex = notInFrame
n.val = nil
switch bname {
case "unsafe.alignOf", "unsafe.Offsetof", "unsafe.Sizeof":
n.gen = nop
}
case n.anc.kind == returnStmt:
// Store result directly to frame output location, to avoid a frame copy.
n.findex = 0
@@ -1186,8 +1197,8 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
default:
n.findex = sc.add(n.typ)
}
if op, ok := constBltn[bname]; ok && n.anc.action != aAssign {
op(n) // pre-compute non-assigned constant :
if op, ok := constBltn[bname]; ok {
op(n)
}
case c0.isType(sc):
@@ -1268,21 +1279,6 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
}
}
case isOffsetof(c0):
if len(n.child) != 2 || n.child[1].kind != selectorExpr || !isStruct(n.child[1].child[0].typ) {
err = n.cfgErrorf("Offsetof argument: invalid expression")
break
}
c1 := n.child[1]
field, ok := c1.child[0].typ.rtype.FieldByName(c1.child[1].ident)
if !ok {
err = n.cfgErrorf("struct does not contain field: %s", c1.child[1].ident)
break
}
n.typ = valueTOf(reflect.TypeOf(field.Offset))
n.rval = reflect.ValueOf(field.Offset)
n.gen = nop
default:
// The call may be on a generic function. In that case, replace the
// generic function AST by an instantiated one before going further.
@@ -1816,6 +1812,10 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
} else {
n.typ = valueTOf(fixPossibleConstType(s.Type()), withUntyped(isValueUntyped(s)))
n.rval = s
if pkg == "unsafe" && (name == "AlignOf" || name == "Offsetof" || name == "Sizeof") {
n.sym = &symbol{kind: bltnSym, node: n, rval: s}
n.ident = pkg + "." + name
}
}
n.action = aGetSym
n.gen = nop
@@ -2794,10 +2794,6 @@ func isBinCall(n *node, sc *scope) bool {
return c0.typ.cat == valueT && c0.typ.rtype.Kind() == reflect.Func
}
func isOffsetof(n *node) bool {
return n.typ != nil && n.typ.cat == valueT && n.rval.String() == "Offsetof"
}
func mustReturnValue(n *node) bool {
if len(n.child) < 3 {
return false
@@ -3136,3 +3132,24 @@ func isBlank(n *node) bool {
}
return n.ident == "_"
}
func alignof(n *node) {
n.gen = nop
n.typ = n.scope.getType("uintptr")
n.rval = reflect.ValueOf(uintptr(n.child[1].typ.TypeOf().Align()))
}
func offsetof(n *node) {
n.gen = nop
n.typ = n.scope.getType("uintptr")
c1 := n.child[1]
if field, ok := c1.child[0].typ.rtype.FieldByName(c1.child[1].ident); ok {
n.rval = reflect.ValueOf(field.Offset)
}
}
func sizeof(n *node) {
n.gen = nop
n.typ = n.scope.getType("uintptr")
n.rval = reflect.ValueOf(n.child[1].typ.TypeOf().Size())
}

View File

@@ -306,12 +306,12 @@ func checkConstraint(it, ct *itype) error {
return nil
}
for _, c := range ct.constraint {
if it.equals(c) {
if it.equals(c) || it.matchDefault(c) {
return nil
}
}
for _, c := range ct.ulconstraint {
if it.underlying().equals(c) {
if it.underlying().equals(c) || it.matchDefault(c) {
return nil
}
}

View File

@@ -184,14 +184,14 @@ type opt struct {
noRun bool // compile, but do not run
fastChan bool // disable cancellable chan operations
specialStdio bool // allows os.Stdin, os.Stdout, os.Stderr to not be file descriptors
unrestricted bool // allow use of non sandboxed symbols
unrestricted bool // allow use of non-sandboxed symbols
}
// Interpreter contains global resources and state.
type Interpreter struct {
// id is an atomic counter counter used for run cancellation,
// id is an atomic counter used for run cancellation,
// only accessed via runid/stop
// Located at start of struct to ensure proper alignment on 32 bit
// Located at start of struct to ensure proper alignment on 32-bit
// architectures.
id uint64
@@ -405,6 +405,7 @@ func New(options Options) *Interpreter {
}
const (
bltnAlignof = "unsafe.Alignof"
bltnAppend = "append"
bltnCap = "cap"
bltnClose = "close"
@@ -415,11 +416,13 @@ const (
bltnLen = "len"
bltnMake = "make"
bltnNew = "new"
bltnOffsetof = "unsafe.Offsetof"
bltnPanic = "panic"
bltnPrint = "print"
bltnPrintln = "println"
bltnReal = "real"
bltnRecover = "recover"
bltnSizeof = "unsafe.Sizeof"
)
func initUniverse() *scope {

View File

@@ -1,11 +1,13 @@
package interp_test
import (
"bytes"
"go/build"
"io"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
@@ -14,6 +16,13 @@ import (
"github.com/traefik/yaegi/stdlib/unsafe"
)
// The following tests depend on an incompatible language change in go1.22, where `for` variables are now
// defined in body (thus reallocated at each loop). We skip them until both supported versions behave the same.
// We will remove this in Go1.23.
var testsToSkipGo122 = map[string]bool{"closure9.go": true, "closure10.go": true, "closure11.go": true, "closure12.go": true}
var go122 = strings.HasPrefix(runtime.Version(), "go1.22")
func TestInterpConsistencyBuild(t *testing.T) {
if testing.Short() {
t.Skip("short mode")
@@ -89,6 +98,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
file.Name() == "redeclaration-global5.go" || // expect error
file.Name() == "redeclaration-global6.go" || // expect error
file.Name() == "redeclaration-global7.go" || // expect error
file.Name() == "panic0.go" || // expect error
file.Name() == "pkgname0.go" || // has deps
file.Name() == "pkgname1.go" || // expect error
file.Name() == "pkgname2.go" || // has deps
@@ -119,6 +129,13 @@ func TestInterpConsistencyBuild(t *testing.T) {
file.Name() == "type33.go" { // expect error
continue
}
// Skip some tests which are problematic in go1.21 only.
if go121 && testsToSkipGo121[file.Name()] {
continue
}
if go122 && testsToSkipGo122[file.Name()] {
continue
}
file := file
t.Run(file.Name(), func(t *testing.T) {
@@ -176,7 +193,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
t.Fatal(err)
}
if string(outInterp) != string(outRun) {
if !bytes.Equal(outInterp, outRun) {
t.Errorf("\nGot: %q,\n want: %q", string(outInterp), string(outRun))
}
})
@@ -187,6 +204,7 @@ func TestInterpErrorConsistency(t *testing.T) {
testCases := []struct {
fileName string
expectedInterp string
expectedStderr string
expectedExec string
}{
{
@@ -284,17 +302,28 @@ func TestInterpErrorConsistency(t *testing.T) {
expectedInterp: "37:2: duplicate case Bir in type switch",
expectedExec: "37:7: duplicate case Bir in type switch",
},
{
fileName: "panic0.go",
expectedInterp: "stop!",
expectedStderr: `
../_test/panic0.go:16:2: panic: main.baz(...)
../_test/panic0.go:12:2: panic: main.bar(...)
../_test/panic0.go:8:2: panic: main.foo(...)
../_test/panic0.go:4:2: panic: main.main(...)
`,
},
}
for _, test := range testCases {
t.Run(test.fileName, func(t *testing.T) {
if len(test.expectedInterp) == 0 && len(test.expectedExec) == 0 {
t.Fatal("at least expectedInterp must be define")
if test.expectedInterp == "" && test.expectedExec == "" {
t.Fatal("at least expectedInterp must be defined")
}
filePath := filepath.Join("..", "_test", test.fileName)
i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
var stderr bytes.Buffer
i := interp.New(interp.Options{GoPath: build.Default.GOPATH, Stderr: &stderr})
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
@@ -307,6 +336,12 @@ func TestInterpErrorConsistency(t *testing.T) {
if !strings.Contains(errEval.Error(), test.expectedInterp) {
t.Errorf("got %q, want: %q", errEval.Error(), test.expectedInterp)
}
if test.expectedStderr != "" {
exp, got := strings.TrimSpace(test.expectedStderr), strings.TrimSpace(stderr.String())
if exp != got {
t.Errorf("got %q, want: %q", got, exp)
}
}
cmd := exec.Command("go", "run", filePath)
outRun, errExec := cmd.CombinedOutput()
@@ -315,7 +350,7 @@ func TestInterpErrorConsistency(t *testing.T) {
t.Fatal("An error is expected but got none.")
}
if len(test.expectedExec) == 0 && !strings.Contains(string(outRun), test.expectedInterp) {
if test.expectedExec == "" && !strings.Contains(string(outRun), test.expectedInterp) {
t.Errorf("got %q, want: %q", string(outRun), test.expectedInterp)
} else if !strings.Contains(string(outRun), test.expectedExec) {
t.Errorf("got %q, want: %q", string(outRun), test.expectedExec)

View File

@@ -708,7 +708,7 @@ func TestEvalCall(t *testing.T) {
{src: ` test := func(a, b int) int { return a }
blah := func() (int, float64) { return 1, 1.1 }
a := test(blah())`, err: "3:15: cannot use func() (int,float64) as type (int,int)"},
{src: "func f()", err: "function declaration without body is unsupported"},
{src: "func f()", err: "missing function body"},
})
}
@@ -1095,6 +1095,10 @@ func main() {
}
func TestImportPathIsKey(t *testing.T) {
// FIXME(marc): support of stdlib generic packages like "cmp", "maps", "slices" has changed
// the scope layout by introducing new source packages when stdlib is used.
// The logic of the following test doesn't apply anymore.
t.Skip("This test needs to be reworked.")
// No need to check the results of Eval, as TestFile already does it.
i := interp.New(interp.Options{GoPath: filepath.FromSlash("../_test/testdata/redeclaration-global7")})
if err := i.Use(stdlib.Symbols); err != nil {
@@ -1252,11 +1256,10 @@ func TestConcurrentEvals2(t *testing.T) {
if hello1 {
if l == "hello world2" {
break
} else {
}
done <- fmt.Errorf("unexpected output: %v", l)
return
}
}
if l == "hello world1" {
hello1 = true
} else {
@@ -1335,7 +1338,7 @@ func TestConcurrentEvals3(t *testing.T) {
}()
for _, v := range input {
in := strings.NewReader(fmt.Sprintf("println(\"%s\")\n", v))
in := strings.NewReader(fmt.Sprintf("println(%q)\n", v))
if _, err := io.Copy(poutin, in); err != nil {
t.Fatal(err)
}
@@ -1880,25 +1883,25 @@ func TestIssue1383(t *testing.T) {
}
`
interp := interp.New(interp.Options{})
err := interp.Use(stdlib.Symbols)
i := interp.New(interp.Options{})
err := i.Use(stdlib.Symbols)
if err != nil {
t.Fatal(err)
}
_, err = interp.Eval(`import "fmt"`)
_, err = i.Eval(`import "fmt"`)
if err != nil {
t.Fatal(err)
}
ast, err := parser.ParseFile(interp.FileSet(), "_.go", src, parser.DeclarationErrors)
ast, err := parser.ParseFile(i.FileSet(), "_.go", src, parser.DeclarationErrors)
if err != nil {
t.Fatal(err)
}
prog, err := interp.CompileAST(ast)
prog, err := i.CompileAST(ast)
if err != nil {
t.Fatal(err)
}
_, err = interp.Execute(prog)
_, err = i.Execute(prog)
if err != nil {
t.Fatal(err)
}

View File

@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"testing"
@@ -16,6 +17,12 @@ import (
"github.com/traefik/yaegi/stdlib/unsafe"
)
// The following tests sometimes (not always) crash with go1.21 but not with go1.20 or go1.22.
// The reason of failure is not obvious, maybe due to the runtime itself, and will be investigated separately.
var testsToSkipGo121 = map[string]bool{"cli6.go": true, "cli7.go": true, "issue-1276.go": true, "issue-1330.go": true, "struct11.go": true}
var go121 = strings.HasPrefix(runtime.Version(), "go1.21")
func TestFile(t *testing.T) {
filePath := "../_test/str.go"
runCheck(t, filePath)
@@ -27,10 +34,15 @@ func TestFile(t *testing.T) {
if err != nil {
t.Fatal(err)
}
for _, file := range files {
if filepath.Ext(file.Name()) != ".go" {
continue
}
// Skip some tests which are problematic in go1.21 only.
if go121 && testsToSkipGo121[file.Name()] {
continue
}
file := file
t.Run(file.Name(), func(t *testing.T) {
runCheck(t, filepath.Join(baseDir, file.Name()))
@@ -98,7 +110,7 @@ func wantedFromComment(p string) (res string, goPath string, err bool) {
if err != nil {
panic(err)
}
goPath = filepath.Join(wd, "../_test", strings.TrimPrefix(parts[0], "GOPATH:"))
goPath = filepath.Join(wd, "..", "_test", strings.TrimPrefix(parts[0], "GOPATH:"))
}
if strings.HasPrefix(text, "Output:\n") {
return strings.TrimPrefix(text, "Output:\n"), goPath, false

View File

@@ -180,6 +180,27 @@ var errAbortHandler = errors.New("net/http: abort Handler")
// Functions set to run during execution of CFG.
func panicFunc(s *scope) string {
if s == nil {
return ""
}
def := s.def
if def == nil {
return s.pkgID
}
switch def.kind {
case funcDecl:
if c := def.child[1]; c.kind == identExpr {
return s.pkgID + "." + c.ident
}
case funcLit:
if def.anc != nil {
return panicFunc(def.anc.scope) + ".func"
}
}
return s.pkgID
}
// runCfg executes a node AST by walking its CFG and running node builtin at each step.
func runCfg(n *node, f *frame, funcNode, callNode *node) {
var exec bltn
@@ -199,7 +220,7 @@ func runCfg(n *node, f *frame, funcNode, callNode *node) {
// suppress the logging here accordingly, to get a similar and consistent
// behavior.
if !ok || errorer.Error() != errAbortHandler.Error() {
fmt.Fprintln(n.interp.stderr, oNode.cfgErrorf("panic"))
fmt.Fprintln(n.interp.stderr, oNode.cfgErrorf("panic: %s(...)", panicFunc(oNode.scope)))
}
f.mutex.Unlock()
panic(f.recovered)
@@ -1958,7 +1979,7 @@ func getMethodByName(n *node) {
}
if val, ok = val0.Field(i).Interface().(valueInterface); ok {
break
// TODO: should we keep track of all the the vals that are indeed valueInterface,
// TODO: should we keep track of all the vals that are indeed valueInterface,
// so that later on we can call MethodByName on all of them until one matches?
}
}

View File

@@ -1,6 +1,7 @@
package interp
import (
"errors"
"fmt"
"io/fs"
"os"
@@ -208,7 +209,7 @@ func (interp *Interpreter) pkgDir(goPath string, root, importPath string) (strin
return dir, root, nil // found!
}
if len(root) == 0 {
if root == "" {
if interp.context.GOPATH == "" {
return "", "", fmt.Errorf("unable to find source related to: %q. Either the GOPATH environment variable, or the Interpreter.Options.GoPath needs to be set", importPath)
}
@@ -245,7 +246,7 @@ func previousRoot(filesystem fs.FS, rootPath, root string) (string, error) {
vendored = strings.TrimPrefix(strings.TrimPrefix(parent, prefix), string(filepath.Separator))
break
}
if !os.IsNotExist(err) {
if !errors.Is(err, fs.ErrNotExist) {
return "", err
}
// stop when we reach GOPATH/src

View File

@@ -484,6 +484,7 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
length = int(vInt(sym.rval))
default:
// Size is defined by a numeric constant expression.
var ok bool
if _, err := interp.cfg(c0, sc, sc.pkgID, sc.pkgName); err != nil {
if strings.Contains(err.Error(), " undefined: ") {
incomplete = true
@@ -491,6 +492,10 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
}
return nil, err
}
if !c0.rval.IsValid() {
return nil, c0.cfgErrorf("undefined array size")
}
if length, ok = c0.rval.Interface().(int); !ok {
v, ok := c0.rval.Interface().(constant.Value)
if !ok {
incomplete = true
@@ -498,6 +503,7 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
}
length = constToInt(v)
}
}
val, err := nodeType2(interp, sc, n.child[1], seen)
if err != nil {
return nil, err
@@ -983,16 +989,18 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
rtype = rtype.Elem()
}
t = valueTOf(rtype, withNode(n), withScope(sc))
} else {
err = n.cfgErrorf("undefined selector %s.%s", lt.path, name)
break
}
// Continue search in source package, as it may exist if package contains generics.
fallthrough
case srcPkgT:
pkg := interp.srcPkg[lt.path]
if pkg, ok := interp.srcPkg[lt.path]; ok {
if s, ok := pkg[name]; ok {
t = s.typ
} else {
err = n.cfgErrorf("undefined selector %s.%s", lt.path, name)
break
}
}
err = n.cfgErrorf("undefined selector %s.%s", lt.path, name)
default:
if m, _ := lt.lookupMethod(name); m != nil {
t, err = nodeType2(interp, sc, m.child[2], seen)
@@ -1087,6 +1095,9 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
sc.sym[sname].typ = t
}
case typeAssertExpr:
t, err = nodeType2(interp, sc, n.child[1], seen)
default:
err = n.cfgErrorf("type definition not implemented: %s", n.kind)
}
@@ -1221,6 +1232,8 @@ func fieldName(n *node) string {
return fieldName(n.child[1])
case starExpr:
return fieldName(n.child[0])
case indexExpr:
return fieldName(n.child[0])
case identExpr:
return n.ident
default:
@@ -1336,7 +1349,7 @@ func (t *itype) numOut() int {
}
case builtinT:
switch t.name {
case "append", "cap", "complex", "copy", "imag", "len", "make", "new", "real", "recover":
case "append", "cap", "complex", "copy", "imag", "len", "make", "new", "real", "recover", "unsafe.Alignof", "unsafe.Offsetof", "unsafe.Sizeof":
return 1
}
}
@@ -1522,7 +1535,7 @@ func (t *itype) ordered() bool {
return isInt(typ) || isFloat(typ) || isString(typ)
}
// Equals returns true if the given type is identical to the receiver one.
// equals returns true if the given type is identical to the receiver one.
func (t *itype) equals(o *itype) bool {
switch ti, oi := isInterface(t), isInterface(o); {
case ti && oi:
@@ -1536,13 +1549,21 @@ func (t *itype) equals(o *itype) bool {
}
}
// matchDefault returns true if the receiver default type is the same as the given one.
func (t *itype) matchDefault(o *itype) bool {
return t.untyped && t.id() == "untyped "+o.id()
}
// MethodSet defines the set of methods signatures as strings, indexed per method name.
type methodSet map[string]string
// Contains returns true if the method set m contains the method set n.
func (m methodSet) contains(n methodSet) bool {
for k, v := range n {
if m[k] != v {
for k := range n {
// Only check the presence of method, not its complete signature,
// as the receiver may be part of the arguments, which makes a
// robust check complex.
if _, ok := m[k]; !ok {
return false
}
}
@@ -2129,8 +2150,14 @@ func (t *itype) refType(ctx *refTypeContext) reflect.Type {
var fields []reflect.StructField
for _, f := range t.field {
field := reflect.StructField{
Name: exportName(f.name), Type: f.typ.refType(ctx),
Tag: reflect.StructTag(f.tag), Anonymous: f.embed,
Name: exportName(f.name),
Type: f.typ.refType(ctx),
Tag: reflect.StructTag(f.tag),
}
if len(t.field) == 1 && f.embed {
// Mark the field as embedded (anonymous) only if it is the
// only one, to avoid a panic due to golang/go#15924 issue.
field.Anonymous = true
}
fields = append(fields, field)
// Find any nil type refs that indicates a rebuild is needed on this field.

View File

@@ -723,6 +723,7 @@ var builtinFuncs = map[string]struct {
args int
variadic bool
}{
bltnAlignof: {args: 1, variadic: false},
bltnAppend: {args: 1, variadic: true},
bltnCap: {args: 1, variadic: false},
bltnClose: {args: 1, variadic: false},
@@ -733,11 +734,13 @@ var builtinFuncs = map[string]struct {
bltnLen: {args: 1, variadic: false},
bltnMake: {args: 1, variadic: true},
bltnNew: {args: 1, variadic: false},
bltnOffsetof: {args: 1, variadic: false},
bltnPanic: {args: 1, variadic: false},
bltnPrint: {args: 0, variadic: true},
bltnPrintln: {args: 0, variadic: true},
bltnReal: {args: 1, variadic: false},
bltnRecover: {args: 0, variadic: false},
bltnSizeof: {args: 1, variadic: false},
}
func (check typecheck) builtin(name string, n *node, child []*node, ellipsis bool) error {
@@ -927,7 +930,7 @@ func (check typecheck) builtin(name string, n *node, child []*node, ellipsis boo
return err
}
}
case bltnRecover, bltnNew:
case bltnRecover, bltnNew, bltnAlignof, bltnOffsetof, bltnSizeof:
// Nothing to do.
default:
return n.cfgErrorf("unsupported builtin %s", name)
@@ -1093,6 +1096,9 @@ func (check typecheck) convertUntyped(n *node, typ *itype) error {
return convErr
}
return nil
case n.typ.isNil() && typ.id() == "unsafe.Pointer":
n.typ = typ
return nil
default:
return convErr
}

View File

@@ -9,6 +9,8 @@ import (
"os"
"path"
"reflect"
gen "github.com/traefik/yaegi/stdlib/generic"
)
// Symbols returns a map of interpreter exported symbol values for the given
@@ -139,6 +141,13 @@ func (interp *Interpreter) Use(values Exports) error {
// well known stdlib package path.
if _, ok := values["fmt/fmt"]; ok {
fixStdlib(interp)
// Load stdlib generic source.
for _, s := range gen.Sources {
if _, err := interp.Compile(s); err != nil {
return err
}
}
}
return nil
}

View File

@@ -0,0 +1,59 @@
// Copyright 2023 The Go 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 cmp provides types and functions related to comparing
// ordered values.
package cmp
// Ordered is a constraint that permits any ordered type: any type
// that supports the operators < <= >= >.
// If future releases of Go add new ordered types,
// this constraint will be modified to include them.
//
// Note that floating-point types may contain NaN ("not-a-number") values.
// An operator such as == or < will always report false when
// comparing a NaN value with any other value, NaN or not.
// See the [Compare] function for a consistent way to compare NaN values.
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string
}
// Less reports whether x is less than y.
// For floating-point types, a NaN is considered less than any non-NaN,
// and -0.0 is not less than (is equal to) 0.0.
func Less[T Ordered](x, y T) bool {
return (isNaN(x) && !isNaN(y)) || x < y
}
// Compare returns
//
// -1 if x is less than y,
// 0 if x equals y,
// +1 if x is greater than y.
//
// For floating-point types, a NaN is considered less than any non-NaN,
// a NaN is considered equal to a NaN, and -0.0 is equal to 0.0.
func Compare[T Ordered](x, y T) int {
xNaN := isNaN(x)
yNaN := isNaN(y)
if xNaN && yNaN {
return 0
}
if xNaN || x < y {
return -1
}
if yNaN || x > y {
return +1
}
return 0
}
// isNaN reports whether x is a NaN without requiring the math package.
// This will always return false if T is not floating-point.
func isNaN[T Ordered](x T) bool {
return x != x
}

View File

@@ -0,0 +1,33 @@
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package generic
import _ "embed"
//go:embed go1_21_cmp.go.txt
var cmpSource string
//go:embed go1_21_maps.go.txt
var mapsSource string
//go:embed go1_21_slices.go.txt
var slicesSource string
/*
//go:embed go1_21_sync.go.txt
var syncSource string
//go:embed go1_21_sync_atomic.go.txt
var syncAtomicSource string
*/
// Sources contains the list of generic packages source strings.
var Sources = [...]string{
cmpSource,
mapsSource,
slicesSource,
// FIXME(marc): support the following.
// syncAtomicSource,
// syncSource,
}

View File

@@ -0,0 +1,66 @@
// Copyright 2021 The Go 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 maps defines various functions useful with maps of any type.
package maps
// Equal reports whether two maps contain the same key/value pairs.
// Values are compared using ==.
func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool {
if len(m1) != len(m2) {
return false
}
for k, v1 := range m1 {
if v2, ok := m2[k]; !ok || v1 != v2 {
return false
}
}
return true
}
// EqualFunc is like Equal, but compares values using eq.
// Keys are still compared with ==.
func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool {
if len(m1) != len(m2) {
return false
}
for k, v1 := range m1 {
if v2, ok := m2[k]; !ok || !eq(v1, v2) {
return false
}
}
return true
}
// clone is implemented in the runtime package.
func clone(m any) any { return m }
// Clone returns a copy of m. This is a shallow clone:
// the new keys and values are set using ordinary assignment.
func Clone[M ~map[K]V, K comparable, V any](m M) M {
// Preserve nil in case it matters.
if m == nil {
return nil
}
return clone(m).(M)
}
// Copy copies all key/value pairs in src adding them to dst.
// When a key in src is already present in dst,
// the value in dst will be overwritten by the value associated
// with the key in src.
func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) {
for k, v := range src {
dst[k] = v
}
}
// DeleteFunc deletes any key/value pairs from m for which del returns true.
func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) {
for k, v := range m {
if del(k, v) {
delete(m, k)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
// Copyright 2022 The Go 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 sync
import (
"sync/atomic"
)
// OnceFunc returns a function that invokes f only once. The returned function
// may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceFunc(f func()) func() {
var (
once Once
valid bool
p any
)
// Construct the inner closure just once to reduce costs on the fast path.
g := func() {
defer func() {
p = recover()
if !valid {
// Re-panic immediately so on the first call the user gets a
// complete stack trace into f.
panic(p)
}
}()
f()
valid = true // Set only if f does not panic
}
return func() {
once.Do(g)
if !valid {
panic(p)
}
}
}
// OnceValue returns a function that invokes f only once and returns the value
// returned by f. The returned function may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceValue[T any](f func() T) func() T {
var (
once Once
valid bool
p any
result T
)
g := func() {
defer func() {
p = recover()
if !valid {
panic(p)
}
}()
result = f()
valid = true
}
return func() T {
once.Do(g)
if !valid {
panic(p)
}
return result
}
}
// OnceValues returns a function that invokes f only once and returns the values
// returned by f. The returned function may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
var (
once Once
valid bool
p any
r1 T1
r2 T2
)
g := func() {
defer func() {
p = recover()
if !valid {
panic(p)
}
}()
r1, r2 = f()
valid = true
}
return func() (T1, T2) {
once.Do(g)
if !valid {
panic(p)
}
return r1, r2
}
}
// Copyright 2009 The Go 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 sync
// import (
// "sync/atomic"
// )
// Once is an object that will perform exactly one action.
//
// A Once must not be copied after first use.
//
// In the terminology of the Go memory model,
// the return from f “synchronizes before”
// the return from any call of once.Do(f).
type Once struct {
// done indicates whether the action has been performed.
// It is first in the struct because it is used in the hot path.
// The hot path is inlined at every call site.
// Placing done first allows more compact instructions on some architectures (amd64/386),
// and fewer instructions (to calculate offset) on other architectures.
done uint32
m Mutex
}
// Do calls the function f if and only if Do is being called for the
// first time for this instance of Once. In other words, given
//
// var once Once
//
// if once.Do(f) is called multiple times, only the first call will invoke f,
// even if f has a different value in each invocation. A new instance of
// Once is required for each function to execute.
//
// Do is intended for initialization that must be run exactly once. Since f
// is niladic, it may be necessary to use a function literal to capture the
// arguments to a function to be invoked by Do:
//
// config.once.Do(func() { config.init(filename) })
//
// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.
//
// If f panics, Do considers it to have returned; future calls of Do return
// without calling f.
func (o *Once) Do(f func()) {
// Note: Here is an incorrect implementation of Do:
//
// if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
// f()
// }
//
// Do guarantees that when it returns, f has finished.
// This implementation would not implement that guarantee:
// given two simultaneous calls, the winner of the cas would
// call f, and the second would return immediately, without
// waiting for the first's call to f to complete.
// This is why the slow path falls back to a mutex, and why
// the atomic.StoreUint32 must be delayed until after f returns.
if atomic.LoadUint32(&o.done) == 0 {
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)
}
}
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1)
f()
}
}

View File

@@ -0,0 +1,200 @@
// Copyright 2022 The Go 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 atomic
import "unsafe"
// A Bool is an atomic boolean value.
// The zero value is false.
type Bool struct {
_ noCopy
v uint32
}
// Load atomically loads and returns the value stored in x.
func (x *Bool) Load() bool { return LoadUint32(&x.v) != 0 }
// Store atomically stores val into x.
func (x *Bool) Store(val bool) { StoreUint32(&x.v, b32(val)) }
// Swap atomically stores new into x and returns the previous value.
func (x *Bool) Swap(new bool) (old bool) { return SwapUint32(&x.v, b32(new)) != 0 }
// CompareAndSwap executes the compare-and-swap operation for the boolean value x.
func (x *Bool) CompareAndSwap(old, new bool) (swapped bool) {
return CompareAndSwapUint32(&x.v, b32(old), b32(new))
}
// b32 returns a uint32 0 or 1 representing b.
func b32(b bool) uint32 {
if b {
return 1
}
return 0
}
// For testing *Pointer[T]'s methods can be inlined.
// Keep in sync with cmd/compile/internal/test/inl_test.go:TestIntendedInlining.
var _ = &Pointer[int]{}
// A Pointer is an atomic pointer of type *T. The zero value is a nil *T.
type Pointer[T any] struct {
// Mention *T in a field to disallow conversion between Pointer types.
// See go.dev/issue/56603 for more details.
// Use *T, not T, to avoid spurious recursive type definition errors.
_ [0]*T
_ noCopy
v unsafe.Pointer
}
// Load atomically loads and returns the value stored in x.
func (x *Pointer[T]) Load() *T { return (*T)(LoadPointer(&x.v)) }
// Store atomically stores val into x.
func (x *Pointer[T]) Store(val *T) { StorePointer(&x.v, unsafe.Pointer(val)) }
// Swap atomically stores new into x and returns the previous value.
func (x *Pointer[T]) Swap(new *T) (old *T) { return (*T)(SwapPointer(&x.v, unsafe.Pointer(new))) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool) {
return CompareAndSwapPointer(&x.v, unsafe.Pointer(old), unsafe.Pointer(new))
}
// An Int32 is an atomic int32. The zero value is zero.
type Int32 struct {
_ noCopy
v int32
}
// Load atomically loads and returns the value stored in x.
func (x *Int32) Load() int32 { return LoadInt32(&x.v) }
// Store atomically stores val into x.
func (x *Int32) Store(val int32) { StoreInt32(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Int32) Swap(new int32) (old int32) { return SwapInt32(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) {
return CompareAndSwapInt32(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) }
// An Int64 is an atomic int64. The zero value is zero.
type Int64 struct {
_ noCopy
_ align64
v int64
}
// Load atomically loads and returns the value stored in x.
func (x *Int64) Load() int64 { return LoadInt64(&x.v) }
// Store atomically stores val into x.
func (x *Int64) Store(val int64) { StoreInt64(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Int64) Swap(new int64) (old int64) { return SwapInt64(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) {
return CompareAndSwapInt64(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) }
// A Uint32 is an atomic uint32. The zero value is zero.
type Uint32 struct {
_ noCopy
v uint32
}
// Load atomically loads and returns the value stored in x.
func (x *Uint32) Load() uint32 { return LoadUint32(&x.v) }
// Store atomically stores val into x.
func (x *Uint32) Store(val uint32) { StoreUint32(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Uint32) Swap(new uint32) (old uint32) { return SwapUint32(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) {
return CompareAndSwapUint32(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) }
// A Uint64 is an atomic uint64. The zero value is zero.
type Uint64 struct {
_ noCopy
_ align64
v uint64
}
// Load atomically loads and returns the value stored in x.
func (x *Uint64) Load() uint64 { return LoadUint64(&x.v) }
// Store atomically stores val into x.
func (x *Uint64) Store(val uint64) { StoreUint64(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Uint64) Swap(new uint64) (old uint64) { return SwapUint64(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) {
return CompareAndSwapUint64(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) }
// A Uintptr is an atomic uintptr. The zero value is zero.
type Uintptr struct {
_ noCopy
v uintptr
}
// Load atomically loads and returns the value stored in x.
func (x *Uintptr) Load() uintptr { return LoadUintptr(&x.v) }
// Store atomically stores val into x.
func (x *Uintptr) Store(val uintptr) { StoreUintptr(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Uintptr) Swap(new uintptr) (old uintptr) { return SwapUintptr(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) {
return CompareAndSwapUintptr(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) }
// noCopy may be added to structs which must not be copied
// after the first use.
//
// See https://golang.org/issues/8005#issuecomment-190753527
// for details.
//
// Note that it must not be embedded, due to the Lock and Unlock methods.
type noCopy struct{}
// Lock is a no-op used by -copylocks checker from `go vet`.
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}
// align64 may be added to structs that must be 64-bit aligned.
// This struct is recognized by a special case in the compiler
// and will not work if copied to any other package.
type align64 struct{}

View File

@@ -0,0 +1,71 @@
// Copyright 2023 The Go 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 cmp provides types and functions related to comparing
// ordered values.
package cmp
// Ordered is a constraint that permits any ordered type: any type
// that supports the operators < <= >= >.
// If future releases of Go add new ordered types,
// this constraint will be modified to include them.
//
// Note that floating-point types may contain NaN ("not-a-number") values.
// An operator such as == or < will always report false when
// comparing a NaN value with any other value, NaN or not.
// See the [Compare] function for a consistent way to compare NaN values.
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string
}
// Less reports whether x is less than y.
// For floating-point types, a NaN is considered less than any non-NaN,
// and -0.0 is not less than (is equal to) 0.0.
func Less[T Ordered](x, y T) bool {
return (isNaN(x) && !isNaN(y)) || x < y
}
// Compare returns
//
// -1 if x is less than y,
// 0 if x equals y,
// +1 if x is greater than y.
//
// For floating-point types, a NaN is considered less than any non-NaN,
// a NaN is considered equal to a NaN, and -0.0 is equal to 0.0.
func Compare[T Ordered](x, y T) int {
xNaN := isNaN(x)
yNaN := isNaN(y)
if xNaN && yNaN {
return 0
}
if xNaN || x < y {
return -1
}
if yNaN || x > y {
return +1
}
return 0
}
// isNaN reports whether x is a NaN without requiring the math package.
// This will always return false if T is not floating-point.
func isNaN[T Ordered](x T) bool {
return x != x
}
// Or returns the first of its arguments that is not equal to the zero value.
// If no argument is non-zero, it returns the zero value.
func Or[T comparable](vals ...T) T {
var zero T
for _, val := range vals {
if val != zero {
return val
}
}
return zero
}

View File

@@ -0,0 +1,41 @@
//go:build go1.22
// +build go1.22
package generic
import _ "embed"
//go:embed go1_22_cmp_cmp.go.txt
var cmpSource string
//go:embed go1_22_maps_maps.go.txt
var mapsSource string
//go:embed go1_22_slices_slices.go.txt
var slicesSource string
/*
//go:embed go1_22_slices_sort.go.txt
var slicesSource1 string
//go:embed go1_22_slices_zsortanyfunc.go.txt
var slicesSource2 string
//go:embed go1_22_sync_oncefunc.go.txt
var syncSource string
//go:embed go1_22_sync_atomic_type.go.txt
var syncAtomicSource string
*/
// Sources contains the list of generic packages source strings.
var Sources = [...]string{
cmpSource,
mapsSource,
slicesSource,
// FIXME(marc): support the following.
// slicesSource1,
// slicesSource2,
// syncAtomicSource,
// syncSource,
}

View File

@@ -0,0 +1,68 @@
// Copyright 2021 The Go 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 maps defines various functions useful with maps of any type.
package maps
// Equal reports whether two maps contain the same key/value pairs.
// Values are compared using ==.
func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool {
if len(m1) != len(m2) {
return false
}
for k, v1 := range m1 {
if v2, ok := m2[k]; !ok || v1 != v2 {
return false
}
}
return true
}
// EqualFunc is like Equal, but compares values using eq.
// Keys are still compared with ==.
func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool {
if len(m1) != len(m2) {
return false
}
for k, v1 := range m1 {
if v2, ok := m2[k]; !ok || !eq(v1, v2) {
return false
}
}
return true
}
// clone is implemented in the runtime package.
func clone(m any) any {
return m
}
// Clone returns a copy of m. This is a shallow clone:
// the new keys and values are set using ordinary assignment.
func Clone[M ~map[K]V, K comparable, V any](m M) M {
// Preserve nil in case it matters.
if m == nil {
return nil
}
return clone(m).(M)
}
// Copy copies all key/value pairs in src adding them to dst.
// When a key in src is already present in dst,
// the value in dst will be overwritten by the value associated
// with the key in src.
func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) {
for k, v := range src {
dst[k] = v
}
}
// DeleteFunc deletes any key/value pairs from m for which del returns true.
func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) {
for k, v := range m {
if del(k, v) {
delete(m, k)
}
}
}

View File

@@ -0,0 +1,518 @@
// Copyright 2021 The Go 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 slices defines various functions useful with slices of any type.
package slices
import (
"cmp"
// TODO(marc) fix this. "unsafe"
)
// Equal reports whether two slices are equal: the same length and all
// elements equal. If the lengths are different, Equal returns false.
// Otherwise, the elements are compared in increasing index order, and the
// comparison stops at the first unequal pair.
// Floating point NaNs are not considered equal.
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
if len(s1) != len(s2) {
return false
}
for i := range s1 {
if s1[i] != s2[i] {
return false
}
}
return true
}
// EqualFunc reports whether two slices are equal using an equality
// function on each pair of elements. If the lengths are different,
// EqualFunc returns false. Otherwise, the elements are compared in
// increasing index order, and the comparison stops at the first index
// for which eq returns false.
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
if len(s1) != len(s2) {
return false
}
for i, v1 := range s1 {
v2 := s2[i]
if !eq(v1, v2) {
return false
}
}
return true
}
// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
// of elements. The elements are compared sequentially, starting at index 0,
// until one element is not equal to the other.
// The result of comparing the first non-matching elements is returned.
// If both slices are equal until one of them ends, the shorter slice is
// considered less than the longer one.
// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int {
for i, v1 := range s1 {
if i >= len(s2) {
return +1
}
v2 := s2[i]
if c := cmp.Compare(v1, v2); c != 0 {
return c
}
}
if len(s1) < len(s2) {
return -1
}
return 0
}
// CompareFunc is like [Compare] but uses a custom comparison function on each
// pair of elements.
// The result is the first non-zero result of cmp; if cmp always
// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
// and +1 if len(s1) > len(s2).
func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
for i, v1 := range s1 {
if i >= len(s2) {
return +1
}
v2 := s2[i]
if c := cmp(v1, v2); c != 0 {
return c
}
}
if len(s1) < len(s2) {
return -1
}
return 0
}
// Index returns the index of the first occurrence of v in s,
// or -1 if not present.
func Index[S ~[]E, E comparable](s S, v E) int {
for i := range s {
if v == s[i] {
return i
}
}
return -1
}
// IndexFunc returns the first index i satisfying f(s[i]),
// or -1 if none do.
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
for i := range s {
if f(s[i]) {
return i
}
}
return -1
}
// Contains reports whether v is present in s.
func Contains[S ~[]E, E comparable](s S, v E) bool {
return Index(s, v) >= 0
}
// ContainsFunc reports whether at least one
// element e of s satisfies f(e).
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
return IndexFunc(s, f) >= 0
}
// Insert inserts the values v... into s at index i,
// returning the modified slice.
// The elements at s[i:] are shifted up to make room.
// In the returned slice r, r[i] == v[0],
// and r[i+len(v)] == value originally at r[i].
// Insert panics if i is out of range.
// This function is O(len(s) + len(v)).
func Insert[S ~[]E, E any](s S, i int, v ...E) S {
_ = s[i:] // bounds check
m := len(v)
if m == 0 {
return s
}
n := len(s)
if i == n {
return append(s, v...)
}
if n+m > cap(s) {
// Use append rather than make so that we bump the size of
// the slice up to the next storage class.
// This is what Grow does but we don't call Grow because
// that might copy the values twice.
s2 := append(s[:i], make(S, n+m-i)...)
copy(s2[i:], v)
copy(s2[i+m:], s[i:])
return s2
}
s = s[:n+m]
// before:
// s: aaaaaaaabbbbccccccccdddd
// ^ ^ ^ ^
// i i+m n n+m
// after:
// s: aaaaaaaavvvvbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
//
// a are the values that don't move in s.
// v are the values copied in from v.
// b and c are the values from s that are shifted up in index.
// d are the values that get overwritten, never to be seen again.
if !overlaps(v, s[i+m:]) {
// Easy case - v does not overlap either the c or d regions.
// (It might be in some of a or b, or elsewhere entirely.)
// The data we copy up doesn't write to v at all, so just do it.
copy(s[i+m:], s[i:])
// Now we have
// s: aaaaaaaabbbbbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
// Note the b values are duplicated.
copy(s[i:], v)
// Now we have
// s: aaaaaaaavvvvbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
// That's the result we want.
return s
}
// The hard case - v overlaps c or d. We can't just shift up
// the data because we'd move or clobber the values we're trying
// to insert.
// So instead, write v on top of d, then rotate.
copy(s[n:], v)
// Now we have
// s: aaaaaaaabbbbccccccccvvvv
// ^ ^ ^ ^
// i i+m n n+m
rotateRight(s[i:], m)
// Now we have
// s: aaaaaaaavvvvbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
// That's the result we want.
return s
}
// Delete removes the elements s[i:j] from s, returning the modified slice.
// Delete panics if j > len(s) or s[i:j] is not a valid slice of s.
// Delete is O(len(s)-i), so if many items must be deleted, it is better to
// make a single call deleting them all together than to delete one at a time.
// Delete zeroes the elements s[len(s)-(j-i):len(s)].
func Delete[S ~[]E, E any](s S, i, j int) S {
_ = s[i:j:len(s)] // bounds check
if i == j {
return s
}
oldlen := len(s)
s = append(s[:i], s[j:]...)
clear(s[len(s):oldlen]) // zero/nil out the obsolete elements, for GC
return s
}
// DeleteFunc removes any elements from s for which del returns true,
// returning the modified slice.
// DeleteFunc zeroes the elements between the new length and the original length.
func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
i := IndexFunc(s, del)
if i == -1 {
return s
}
// Don't start copying elements until we find one to delete.
for j := i + 1; j < len(s); j++ {
if v := s[j]; !del(v) {
s[i] = v
i++
}
}
clear(s[i:]) // zero/nil out the obsolete elements, for GC
return s[:i]
}
// Replace replaces the elements s[i:j] by the given v, and returns the
// modified slice.
// Replace panics if j > len(s) or s[i:j] is not a valid slice of s.
// When len(v) < (j-i), Replace zeroes the elements between the new length and the original length.
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
_ = s[i:j] // bounds check
if i == j {
return Insert(s, i, v...)
}
if j == len(s) {
return append(s[:i], v...)
}
tot := len(s[:i]) + len(v) + len(s[j:])
if tot > cap(s) {
// Too big to fit, allocate and copy over.
s2 := append(s[:i], make(S, tot-i)...) // See Insert
copy(s2[i:], v)
copy(s2[i+len(v):], s[j:])
return s2
}
r := s[:tot]
if i+len(v) <= j {
// Easy, as v fits in the deleted portion.
copy(r[i:], v)
copy(r[i+len(v):], s[j:])
clear(s[tot:]) // zero/nil out the obsolete elements, for GC
return r
}
// We are expanding (v is bigger than j-i).
// The situation is something like this:
// (example has i=4,j=8,len(s)=16,len(v)=6)
// s: aaaaxxxxbbbbbbbbyy
// ^ ^ ^ ^
// i j len(s) tot
// a: prefix of s
// x: deleted range
// b: more of s
// y: area to expand into
if !overlaps(r[i+len(v):], v) {
// Easy, as v is not clobbered by the first copy.
copy(r[i+len(v):], s[j:])
copy(r[i:], v)
return r
}
// This is a situation where we don't have a single place to which
// we can copy v. Parts of it need to go to two different places.
// We want to copy the prefix of v into y and the suffix into x, then
// rotate |y| spots to the right.
//
// v[2:] v[:2]
// | |
// s: aaaavvvvbbbbbbbbvv
// ^ ^ ^ ^
// i j len(s) tot
//
// If either of those two destinations don't alias v, then we're good.
y := len(v) - (j - i) // length of y portion
if !overlaps(r[i:j], v) {
copy(r[i:j], v[y:])
copy(r[len(s):], v[:y])
rotateRight(r[i:], y)
return r
}
if !overlaps(r[len(s):], v) {
copy(r[len(s):], v[:y])
copy(r[i:j], v[y:])
rotateRight(r[i:], y)
return r
}
// Now we know that v overlaps both x and y.
// That means that the entirety of b is *inside* v.
// So we don't need to preserve b at all; instead we
// can copy v first, then copy the b part of v out of
// v to the right destination.
k := startIdx(v, s[j:])
copy(r[i:], v)
copy(r[i+len(v):], r[i+k:])
return r
}
// Clone returns a copy of the slice.
// The elements are copied using assignment, so this is a shallow clone.
func Clone[S ~[]E, E any](s S) S {
// The s[:0:0] preserves nil in case it matters.
return append(s[:0:0], s...)
}
// Compact replaces consecutive runs of equal elements with a single copy.
// This is like the uniq command found on Unix.
// Compact modifies the contents of the slice s and returns the modified slice,
// which may have a smaller length.
// Compact zeroes the elements between the new length and the original length.
func Compact[S ~[]E, E comparable](s S) S {
if len(s) < 2 {
return s
}
i := 1
for k := 1; k < len(s); k++ {
if s[k] != s[k-1] {
if i != k {
s[i] = s[k]
}
i++
}
}
clear(s[i:]) // zero/nil out the obsolete elements, for GC
return s[:i]
}
// CompactFunc is like [Compact] but uses an equality function to compare elements.
// For runs of elements that compare equal, CompactFunc keeps the first one.
// CompactFunc zeroes the elements between the new length and the original length.
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
if len(s) < 2 {
return s
}
i := 1
for k := 1; k < len(s); k++ {
if !eq(s[k], s[k-1]) {
if i != k {
s[i] = s[k]
}
i++
}
}
clear(s[i:]) // zero/nil out the obsolete elements, for GC
return s[:i]
}
// Grow increases the slice's capacity, if necessary, to guarantee space for
// another n elements. After Grow(n), at least n elements can be appended
// to the slice without another allocation. If n is negative or too large to
// allocate the memory, Grow panics.
func Grow[S ~[]E, E any](s S, n int) S {
if n < 0 {
panic("cannot be negative")
}
if n -= cap(s) - len(s); n > 0 {
s = append(s[:cap(s)], make([]E, n)...)[:len(s)]
}
return s
}
// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
func Clip[S ~[]E, E any](s S) S {
return s[:len(s):len(s)]
}
// Rotation algorithm explanation:
//
// rotate left by 2
// start with
// 0123456789
// split up like this
// 01 234567 89
// swap first 2 and last 2
// 89 234567 01
// join first parts
// 89234567 01
// recursively rotate first left part by 2
// 23456789 01
// join at the end
// 2345678901
//
// rotate left by 8
// start with
// 0123456789
// split up like this
// 01 234567 89
// swap first 2 and last 2
// 89 234567 01
// join last parts
// 89 23456701
// recursively rotate second part left by 6
// 89 01234567
// join at the end
// 8901234567
// TODO: There are other rotate algorithms.
// This algorithm has the desirable property that it moves each element exactly twice.
// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes.
// The follow-cycles algorithm can be 1-write but it is not very cache friendly.
// rotateLeft rotates b left by n spaces.
// s_final[i] = s_orig[i+r], wrapping around.
func rotateLeft[E any](s []E, r int) {
for r != 0 && r != len(s) {
if r*2 <= len(s) {
swap(s[:r], s[len(s)-r:])
s = s[:len(s)-r]
} else {
swap(s[:len(s)-r], s[r:])
s, r = s[len(s)-r:], r*2-len(s)
}
}
}
func rotateRight[E any](s []E, r int) {
rotateLeft(s, len(s)-r)
}
// swap swaps the contents of x and y. x and y must be equal length and disjoint.
func swap[E any](x, y []E) {
for i := 0; i < len(x); i++ {
x[i], y[i] = y[i], x[i]
}
}
// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
func overlaps[E any](a, b []E) bool {
return false
/* TODO(marc): restore the following
if len(a) == 0 || len(b) == 0 {
return false
}
elemSize := unsafe.Sizeof(a[0])
if elemSize == 0 {
return false
}
// TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.
// Also see crypto/internal/alias/alias.go:AnyOverlap
return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) &&
uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1)
*/
}
// startIdx returns the index in haystack where the needle starts.
// prerequisite: the needle must be aliased entirely inside the haystack.
func startIdx[E any](haystack, needle []E) int {
p := &needle[0]
for i := range haystack {
if p == &haystack[i] {
return i
}
}
// TODO: what if the overlap is by a non-integral number of Es?
panic("needle not found")
}
// Reverse reverses the elements of the slice in place.
func Reverse[S ~[]E, E any](s S) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
// Concat returns a new slice concatenating the passed in slices.
func Concat[S ~[]E, E any](slices ...S) S {
size := 0
for _, s := range slices {
size += len(s)
if size < 0 {
panic("len out of range")
}
}
newslice := Grow[S](nil, size)
for _, s := range slices {
newslice = append(newslice, s...)
}
return newslice
}

View File

@@ -0,0 +1,194 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -generic
package slices
import (
"cmp"
"math/bits"
)
// Sort sorts a slice of any ordered type in ascending order.
// When sorting floating-point numbers, NaNs are ordered before other values.
func Sort[S ~[]E, E cmp.Ordered](x S) {
n := len(x)
pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
}
// SortFunc sorts the slice x in ascending order as determined by the cmp
// function. This sort is not guaranteed to be stable.
// cmp(a, b) should return a negative number when a < b, a positive number when
// a > b and zero when a == b.
//
// SortFunc requires that cmp is a strict weak ordering.
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
n := len(x)
pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
}
// SortStableFunc sorts the slice x while keeping the original order of equal
// elements, using cmp to compare elements in the same way as [SortFunc].
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
stableCmpFunc(x, len(x), cmp)
}
// IsSorted reports whether x is sorted in ascending order.
func IsSorted[S ~[]E, E cmp.Ordered](x S) bool {
for i := len(x) - 1; i > 0; i-- {
if cmp.Less(x[i], x[i-1]) {
return false
}
}
return true
}
// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
// comparison function as defined by [SortFunc].
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
for i := len(x) - 1; i > 0; i-- {
if cmp(x[i], x[i-1]) < 0 {
return false
}
}
return true
}
// Min returns the minimal value in x. It panics if x is empty.
// For floating-point numbers, Min propagates NaNs (any NaN value in x
// forces the output to be NaN).
func Min[S ~[]E, E cmp.Ordered](x S) E {
if len(x) < 1 {
panic("slices.Min: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
m = min(m, x[i])
}
return m
}
// MinFunc returns the minimal value in x, using cmp to compare elements.
// It panics if x is empty. If there is more than one minimal element
// according to the cmp function, MinFunc returns the first one.
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
if len(x) < 1 {
panic("slices.MinFunc: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
if cmp(x[i], m) < 0 {
m = x[i]
}
}
return m
}
// Max returns the maximal value in x. It panics if x is empty.
// For floating-point E, Max propagates NaNs (any NaN value in x
// forces the output to be NaN).
func Max[S ~[]E, E cmp.Ordered](x S) E {
if len(x) < 1 {
panic("slices.Max: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
m = max(m, x[i])
}
return m
}
// MaxFunc returns the maximal value in x, using cmp to compare elements.
// It panics if x is empty. If there is more than one maximal element
// according to the cmp function, MaxFunc returns the first one.
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
if len(x) < 1 {
panic("slices.MaxFunc: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
if cmp(x[i], m) > 0 {
m = x[i]
}
}
return m
}
// BinarySearch searches for target in a sorted slice and returns the position
// where target is found, or the position where target would appear in the
// sort order; it also returns a bool saying whether the target is really found
// in the slice. The slice must be sorted in increasing order.
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) {
// Inlining is faster than calling BinarySearchFunc with a lambda.
n := len(x)
// Define x[-1] < target and x[n] >= target.
// Invariant: x[i-1] < target, x[j] >= target.
i, j := 0, n
for i < j {
h := int(uint(i+j) >> 1) // avoid overflow when computing h
// i ≤ h < j
if cmp.Less(x[h], target) {
i = h + 1 // preserves x[i-1] < target
} else {
j = h // preserves x[j] >= target
}
}
// i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
}
// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
// function. The slice must be sorted in increasing order, where "increasing"
// is defined by cmp. cmp should return 0 if the slice element matches
// the target, a negative number if the slice element precedes the target,
// or a positive number if the slice element follows the target.
// cmp must implement the same ordering as the slice, such that if
// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
n := len(x)
// Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
// Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
i, j := 0, n
for i < j {
h := int(uint(i+j) >> 1) // avoid overflow when computing h
// i ≤ h < j
if cmp(x[h], target) < 0 {
i = h + 1 // preserves cmp(x[i - 1], target) < 0
} else {
j = h // preserves cmp(x[j], target) >= 0
}
}
// i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i.
return i, i < n && cmp(x[i], target) == 0
}
type sortedHint int // hint for pdqsort when choosing the pivot
const (
unknownHint sortedHint = iota
increasingHint
decreasingHint
)
// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
type xorshift uint64
func (r *xorshift) Next() uint64 {
*r ^= *r << 13
*r ^= *r >> 17
*r ^= *r << 5
return uint64(*r)
}
func nextPowerOfTwo(length int) uint {
return 1 << bits.Len(uint(length))
}
// isNaN reports whether x is a NaN without requiring the math package.
// This will always return false if T is not floating-point.
func isNaN[T cmp.Ordered](x T) bool {
return x != x
}

View File

@@ -0,0 +1,479 @@
// Code generated by gen_sort_variants.go; DO NOT EDIT.
// Copyright 2022 The Go 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 slices
// insertionSortCmpFunc sorts data[a:b] using insertion sort.
func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
for i := a + 1; i < b; i++ {
for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
data[j], data[j-1] = data[j-1], data[j]
}
}
}
// siftDownCmpFunc implements the heap property on data[lo:hi].
// first is an offset into the array where the root of the heap lies.
func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
root := lo
for {
child := 2*root + 1
if child >= hi {
break
}
if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
child++
}
if !(cmp(data[first+root], data[first+child]) < 0) {
return
}
data[first+root], data[first+child] = data[first+child], data[first+root]
root = child
}
}
func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
first := a
lo := 0
hi := b - a
// Build heap with greatest element at top.
for i := (hi - 1) / 2; i >= 0; i-- {
siftDownCmpFunc(data, i, hi, first, cmp)
}
// Pop elements, largest first, into end of data.
for i := hi - 1; i >= 0; i-- {
data[first], data[first+i] = data[first+i], data[first]
siftDownCmpFunc(data, lo, i, first, cmp)
}
}
// pdqsortCmpFunc sorts data[a:b].
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
// C++ implementation: https://github.com/orlp/pdqsort
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
const maxInsertion = 12
var (
wasBalanced = true // whether the last partitioning was reasonably balanced
wasPartitioned = true // whether the slice was already partitioned
)
for {
length := b - a
if length <= maxInsertion {
insertionSortCmpFunc(data, a, b, cmp)
return
}
// Fall back to heapsort if too many bad choices were made.
if limit == 0 {
heapSortCmpFunc(data, a, b, cmp)
return
}
// If the last partitioning was imbalanced, we need to breaking patterns.
if !wasBalanced {
breakPatternsCmpFunc(data, a, b, cmp)
limit--
}
pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
if hint == decreasingHint {
reverseRangeCmpFunc(data, a, b, cmp)
// The chosen pivot was pivot-a elements after the start of the array.
// After reversing it is pivot-a elements before the end of the array.
// The idea came from Rust's implementation.
pivot = (b - 1) - (pivot - a)
hint = increasingHint
}
// The slice is likely already sorted.
if wasBalanced && wasPartitioned && hint == increasingHint {
if partialInsertionSortCmpFunc(data, a, b, cmp) {
return
}
}
// Probably the slice contains many duplicate elements, partition the slice into
// elements equal to and elements greater than the pivot.
if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
a = mid
continue
}
mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
wasPartitioned = alreadyPartitioned
leftLen, rightLen := mid-a, b-mid
balanceThreshold := length / 8
if leftLen < rightLen {
wasBalanced = leftLen >= balanceThreshold
pdqsortCmpFunc(data, a, mid, limit, cmp)
a = mid + 1
} else {
wasBalanced = rightLen >= balanceThreshold
pdqsortCmpFunc(data, mid+1, b, limit, cmp)
b = mid
}
}
}
// partitionCmpFunc does one quicksort partition.
// Let p = data[pivot]
// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
// On return, data[newpivot] = p
func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
data[a], data[pivot] = data[pivot], data[a]
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
for i <= j && (cmp(data[i], data[a]) < 0) {
i++
}
for i <= j && !(cmp(data[j], data[a]) < 0) {
j--
}
if i > j {
data[j], data[a] = data[a], data[j]
return j, true
}
data[i], data[j] = data[j], data[i]
i++
j--
for {
for i <= j && (cmp(data[i], data[a]) < 0) {
i++
}
for i <= j && !(cmp(data[j], data[a]) < 0) {
j--
}
if i > j {
break
}
data[i], data[j] = data[j], data[i]
i++
j--
}
data[j], data[a] = data[a], data[j]
return j, false
}
// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
data[a], data[pivot] = data[pivot], data[a]
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
for {
for i <= j && !(cmp(data[a], data[i]) < 0) {
i++
}
for i <= j && (cmp(data[a], data[j]) < 0) {
j--
}
if i > j {
break
}
data[i], data[j] = data[j], data[i]
i++
j--
}
return i
}
// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
const (
maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
shortestShifting = 50 // don't shift any elements on short arrays
)
i := a + 1
for j := 0; j < maxSteps; j++ {
for i < b && !(cmp(data[i], data[i-1]) < 0) {
i++
}
if i == b {
return true
}
if b-a < shortestShifting {
return false
}
data[i], data[i-1] = data[i-1], data[i]
// Shift the smaller one to the left.
if i-a >= 2 {
for j := i - 1; j >= 1; j-- {
if !(cmp(data[j], data[j-1]) < 0) {
break
}
data[j], data[j-1] = data[j-1], data[j]
}
}
// Shift the greater one to the right.
if b-i >= 2 {
for j := i + 1; j < b; j++ {
if !(cmp(data[j], data[j-1]) < 0) {
break
}
data[j], data[j-1] = data[j-1], data[j]
}
}
}
return false
}
// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
// that might cause imbalanced partitions in quicksort.
func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
length := b - a
if length >= 8 {
random := xorshift(length)
modulus := nextPowerOfTwo(length)
for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
other := int(uint(random.Next()) & (modulus - 1))
if other >= length {
other -= length
}
data[idx], data[a+other] = data[a+other], data[idx]
}
}
}
// choosePivotCmpFunc chooses a pivot in data[a:b].
//
// [0,8): chooses a static pivot.
// [8,shortestNinther): uses the simple median-of-three method.
// [shortestNinther,∞): uses the Tukey ninther method.
func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
const (
shortestNinther = 50
maxSwaps = 4 * 3
)
l := b - a
var (
swaps int
i = a + l/4*1
j = a + l/4*2
k = a + l/4*3
)
if l >= 8 {
if l >= shortestNinther {
// Tukey ninther method, the idea came from Rust's implementation.
i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
}
// Find the median among i, j, k and stores it into j.
j = medianCmpFunc(data, i, j, k, &swaps, cmp)
}
switch swaps {
case 0:
return j, increasingHint
case maxSwaps:
return j, decreasingHint
default:
return j, unknownHint
}
}
// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
if cmp(data[b], data[a]) < 0 {
*swaps++
return b, a
}
return a, b
}
// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
a, b = order2CmpFunc(data, a, b, swaps, cmp)
b, c = order2CmpFunc(data, b, c, swaps, cmp)
a, b = order2CmpFunc(data, a, b, swaps, cmp)
return b
}
// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
}
func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
i := a
j := b - 1
for i < j {
data[i], data[j] = data[j], data[i]
i++
j--
}
}
func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
for i := 0; i < n; i++ {
data[a+i], data[b+i] = data[b+i], data[a+i]
}
}
func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
blockSize := 20 // must be > 0
a, b := 0, blockSize
for b <= n {
insertionSortCmpFunc(data, a, b, cmp)
a = b
b += blockSize
}
insertionSortCmpFunc(data, a, n, cmp)
for blockSize < n {
a, b = 0, 2*blockSize
for b <= n {
symMergeCmpFunc(data, a, a+blockSize, b, cmp)
a = b
b += 2 * blockSize
}
if m := a + blockSize; m < n {
symMergeCmpFunc(data, a, m, n, cmp)
}
blockSize *= 2
}
}
// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
// Computer Science, pages 714-723. Springer, 2004.
//
// Let M = m-a and N = b-n. Wolog M < N.
// The recursion depth is bound by ceil(log(N+M)).
// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
//
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
// in the paper carries through for Swap operations, especially as the block
// swapping rotate uses only O(M+N) Swaps.
//
// symMerge assumes non-degenerate arguments: a < m && m < b.
// Having the caller check this condition eliminates many leaf recursion calls,
// which improves performance.
func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
// Avoid unnecessary recursions of symMerge
// by direct insertion of data[a] into data[m:b]
// if data[a:m] only contains one element.
if m-a == 1 {
// Use binary search to find the lowest index i
// such that data[i] >= data[a] for m <= i < b.
// Exit the search loop with i == b in case no such index exists.
i := m
j := b
for i < j {
h := int(uint(i+j) >> 1)
if cmp(data[h], data[a]) < 0 {
i = h + 1
} else {
j = h
}
}
// Swap values until data[a] reaches the position before i.
for k := a; k < i-1; k++ {
data[k], data[k+1] = data[k+1], data[k]
}
return
}
// Avoid unnecessary recursions of symMerge
// by direct insertion of data[m] into data[a:m]
// if data[m:b] only contains one element.
if b-m == 1 {
// Use binary search to find the lowest index i
// such that data[i] > data[m] for a <= i < m.
// Exit the search loop with i == m in case no such index exists.
i := a
j := m
for i < j {
h := int(uint(i+j) >> 1)
if !(cmp(data[m], data[h]) < 0) {
i = h + 1
} else {
j = h
}
}
// Swap values until data[m] reaches the position i.
for k := m; k > i; k-- {
data[k], data[k-1] = data[k-1], data[k]
}
return
}
mid := int(uint(a+b) >> 1)
n := mid + m
var start, r int
if m > mid {
start = n - b
r = mid
} else {
start = a
r = m
}
p := n - 1
for start < r {
c := int(uint(start+r) >> 1)
if !(cmp(data[p-c], data[c]) < 0) {
start = c + 1
} else {
r = c
}
}
end := n - start
if start < m && m < end {
rotateCmpFunc(data, start, m, end, cmp)
}
if a < start && start < mid {
symMergeCmpFunc(data, a, start, mid, cmp)
}
if mid < end && end < b {
symMergeCmpFunc(data, mid, end, b, cmp)
}
}
// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
// Data of the form 'x u v y' is changed to 'x v u y'.
// rotate performs at most b-a many calls to data.Swap,
// and it assumes non-degenerate arguments: a < m && m < b.
func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
i := m - a
j := b - m
for i != j {
if i > j {
swapRangeCmpFunc(data, m-i, m, j, cmp)
i -= j
} else {
swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
j -= i
}
}
// i == j
swapRangeCmpFunc(data, m-i, m, i, cmp)
}

View File

@@ -0,0 +1,200 @@
// Copyright 2022 The Go 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 atomic
import "unsafe"
// A Bool is an atomic boolean value.
// The zero value is false.
type Bool struct {
_ noCopy
v uint32
}
// Load atomically loads and returns the value stored in x.
func (x *Bool) Load() bool { return LoadUint32(&x.v) != 0 }
// Store atomically stores val into x.
func (x *Bool) Store(val bool) { StoreUint32(&x.v, b32(val)) }
// Swap atomically stores new into x and returns the previous value.
func (x *Bool) Swap(new bool) (old bool) { return SwapUint32(&x.v, b32(new)) != 0 }
// CompareAndSwap executes the compare-and-swap operation for the boolean value x.
func (x *Bool) CompareAndSwap(old, new bool) (swapped bool) {
return CompareAndSwapUint32(&x.v, b32(old), b32(new))
}
// b32 returns a uint32 0 or 1 representing b.
func b32(b bool) uint32 {
if b {
return 1
}
return 0
}
// For testing *Pointer[T]'s methods can be inlined.
// Keep in sync with cmd/compile/internal/test/inl_test.go:TestIntendedInlining.
var _ = &Pointer[int]{}
// A Pointer is an atomic pointer of type *T. The zero value is a nil *T.
type Pointer[T any] struct {
// Mention *T in a field to disallow conversion between Pointer types.
// See go.dev/issue/56603 for more details.
// Use *T, not T, to avoid spurious recursive type definition errors.
_ [0]*T
_ noCopy
v unsafe.Pointer
}
// Load atomically loads and returns the value stored in x.
func (x *Pointer[T]) Load() *T { return (*T)(LoadPointer(&x.v)) }
// Store atomically stores val into x.
func (x *Pointer[T]) Store(val *T) { StorePointer(&x.v, unsafe.Pointer(val)) }
// Swap atomically stores new into x and returns the previous value.
func (x *Pointer[T]) Swap(new *T) (old *T) { return (*T)(SwapPointer(&x.v, unsafe.Pointer(new))) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool) {
return CompareAndSwapPointer(&x.v, unsafe.Pointer(old), unsafe.Pointer(new))
}
// An Int32 is an atomic int32. The zero value is zero.
type Int32 struct {
_ noCopy
v int32
}
// Load atomically loads and returns the value stored in x.
func (x *Int32) Load() int32 { return LoadInt32(&x.v) }
// Store atomically stores val into x.
func (x *Int32) Store(val int32) { StoreInt32(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Int32) Swap(new int32) (old int32) { return SwapInt32(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) {
return CompareAndSwapInt32(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) }
// An Int64 is an atomic int64. The zero value is zero.
type Int64 struct {
_ noCopy
_ align64
v int64
}
// Load atomically loads and returns the value stored in x.
func (x *Int64) Load() int64 { return LoadInt64(&x.v) }
// Store atomically stores val into x.
func (x *Int64) Store(val int64) { StoreInt64(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Int64) Swap(new int64) (old int64) { return SwapInt64(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) {
return CompareAndSwapInt64(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) }
// A Uint32 is an atomic uint32. The zero value is zero.
type Uint32 struct {
_ noCopy
v uint32
}
// Load atomically loads and returns the value stored in x.
func (x *Uint32) Load() uint32 { return LoadUint32(&x.v) }
// Store atomically stores val into x.
func (x *Uint32) Store(val uint32) { StoreUint32(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Uint32) Swap(new uint32) (old uint32) { return SwapUint32(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) {
return CompareAndSwapUint32(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) }
// A Uint64 is an atomic uint64. The zero value is zero.
type Uint64 struct {
_ noCopy
_ align64
v uint64
}
// Load atomically loads and returns the value stored in x.
func (x *Uint64) Load() uint64 { return LoadUint64(&x.v) }
// Store atomically stores val into x.
func (x *Uint64) Store(val uint64) { StoreUint64(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Uint64) Swap(new uint64) (old uint64) { return SwapUint64(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) {
return CompareAndSwapUint64(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) }
// A Uintptr is an atomic uintptr. The zero value is zero.
type Uintptr struct {
_ noCopy
v uintptr
}
// Load atomically loads and returns the value stored in x.
func (x *Uintptr) Load() uintptr { return LoadUintptr(&x.v) }
// Store atomically stores val into x.
func (x *Uintptr) Store(val uintptr) { StoreUintptr(&x.v, val) }
// Swap atomically stores new into x and returns the previous value.
func (x *Uintptr) Swap(new uintptr) (old uintptr) { return SwapUintptr(&x.v, new) }
// CompareAndSwap executes the compare-and-swap operation for x.
func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) {
return CompareAndSwapUintptr(&x.v, old, new)
}
// Add atomically adds delta to x and returns the new value.
func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) }
// noCopy may be added to structs which must not be copied
// after the first use.
//
// See https://golang.org/issues/8005#issuecomment-190753527
// for details.
//
// Note that it must not be embedded, due to the Lock and Unlock methods.
type noCopy struct{}
// Lock is a no-op used by -copylocks checker from `go vet`.
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}
// align64 may be added to structs that must be 64-bit aligned.
// This struct is recognized by a special case in the compiler
// and will not work if copied to any other package.
type align64 struct{}

View File

@@ -0,0 +1,100 @@
// Copyright 2022 The Go 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 sync
// OnceFunc returns a function that invokes f only once. The returned function
// may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceFunc(f func()) func() {
var (
once Once
valid bool
p any
)
// Construct the inner closure just once to reduce costs on the fast path.
g := func() {
defer func() {
p = recover()
if !valid {
// Re-panic immediately so on the first call the user gets a
// complete stack trace into f.
panic(p)
}
}()
f()
f = nil // Do not keep f alive after invoking it.
valid = true // Set only if f does not panic.
}
return func() {
once.Do(g)
if !valid {
panic(p)
}
}
}
// OnceValue returns a function that invokes f only once and returns the value
// returned by f. The returned function may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceValue[T any](f func() T) func() T {
var (
once Once
valid bool
p any
result T
)
g := func() {
defer func() {
p = recover()
if !valid {
panic(p)
}
}()
result = f()
f = nil
valid = true
}
return func() T {
once.Do(g)
if !valid {
panic(p)
}
return result
}
}
// OnceValues returns a function that invokes f only once and returns the values
// returned by f. The returned function may be called concurrently.
//
// If f panics, the returned function will panic with the same value on every call.
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
var (
once Once
valid bool
p any
r1 T1
r2 T2
)
g := func() {
defer func() {
p = recover()
if !valid {
panic(p)
}
}()
r1, r2 = f()
f = nil
valid = true
}
return func() (T1, T2) {
once.Do(g)
if !valid {
panic(p)
}
return r1, r2
}
}

View File

@@ -1,55 +0,0 @@
// Code generated by 'yaegi extract context'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
package stdlib
import (
"context"
"reflect"
"time"
)
func init() {
Symbols["context/context"] = map[string]reflect.Value{
// function, constant and variable definitions
"Background": reflect.ValueOf(context.Background),
"Canceled": reflect.ValueOf(&context.Canceled).Elem(),
"DeadlineExceeded": reflect.ValueOf(&context.DeadlineExceeded).Elem(),
"TODO": reflect.ValueOf(context.TODO),
"WithCancel": reflect.ValueOf(context.WithCancel),
"WithDeadline": reflect.ValueOf(context.WithDeadline),
"WithTimeout": reflect.ValueOf(context.WithTimeout),
"WithValue": reflect.ValueOf(context.WithValue),
// type definitions
"CancelFunc": reflect.ValueOf((*context.CancelFunc)(nil)),
"Context": reflect.ValueOf((*context.Context)(nil)),
// interface wrapper definitions
"_Context": reflect.ValueOf((*_context_Context)(nil)),
}
}
// _context_Context is an interface wrapper for Context type
type _context_Context struct {
IValue interface{}
WDeadline func() (deadline time.Time, ok bool)
WDone func() <-chan struct{}
WErr func() error
WValue func(key any) any
}
func (W _context_Context) Deadline() (deadline time.Time, ok bool) {
return W.WDeadline()
}
func (W _context_Context) Done() <-chan struct{} {
return W.WDone()
}
func (W _context_Context) Err() error {
return W.WErr()
}
func (W _context_Context) Value(key any) any {
return W.WValue(key)
}

View File

@@ -1,31 +0,0 @@
// Code generated by 'yaegi extract crypto/ed25519'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
package stdlib
import (
"crypto/ed25519"
"go/constant"
"go/token"
"reflect"
)
func init() {
Symbols["crypto/ed25519/ed25519"] = map[string]reflect.Value{
// function, constant and variable definitions
"GenerateKey": reflect.ValueOf(ed25519.GenerateKey),
"NewKeyFromSeed": reflect.ValueOf(ed25519.NewKeyFromSeed),
"PrivateKeySize": reflect.ValueOf(constant.MakeFromLiteral("64", token.INT, 0)),
"PublicKeySize": reflect.ValueOf(constant.MakeFromLiteral("32", token.INT, 0)),
"SeedSize": reflect.ValueOf(constant.MakeFromLiteral("32", token.INT, 0)),
"Sign": reflect.ValueOf(ed25519.Sign),
"SignatureSize": reflect.ValueOf(constant.MakeFromLiteral("64", token.INT, 0)),
"Verify": reflect.ValueOf(ed25519.Verify),
// type definitions
"PrivateKey": reflect.ValueOf((*ed25519.PrivateKey)(nil)),
"PublicKey": reflect.ValueOf((*ed25519.PublicKey)(nil)),
}
}

View File

@@ -1,122 +0,0 @@
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
package stdlib
import (
"crypto/tls"
"go/constant"
"go/token"
"reflect"
)
func init() {
Symbols["crypto/tls/tls"] = map[string]reflect.Value{
// function, constant and variable definitions
"CipherSuiteName": reflect.ValueOf(tls.CipherSuiteName),
"CipherSuites": reflect.ValueOf(tls.CipherSuites),
"Client": reflect.ValueOf(tls.Client),
"CurveP256": reflect.ValueOf(tls.CurveP256),
"CurveP384": reflect.ValueOf(tls.CurveP384),
"CurveP521": reflect.ValueOf(tls.CurveP521),
"Dial": reflect.ValueOf(tls.Dial),
"DialWithDialer": reflect.ValueOf(tls.DialWithDialer),
"ECDSAWithP256AndSHA256": reflect.ValueOf(tls.ECDSAWithP256AndSHA256),
"ECDSAWithP384AndSHA384": reflect.ValueOf(tls.ECDSAWithP384AndSHA384),
"ECDSAWithP521AndSHA512": reflect.ValueOf(tls.ECDSAWithP521AndSHA512),
"ECDSAWithSHA1": reflect.ValueOf(tls.ECDSAWithSHA1),
"Ed25519": reflect.ValueOf(tls.Ed25519),
"InsecureCipherSuites": reflect.ValueOf(tls.InsecureCipherSuites),
"Listen": reflect.ValueOf(tls.Listen),
"LoadX509KeyPair": reflect.ValueOf(tls.LoadX509KeyPair),
"NewLRUClientSessionCache": reflect.ValueOf(tls.NewLRUClientSessionCache),
"NewListener": reflect.ValueOf(tls.NewListener),
"NoClientCert": reflect.ValueOf(tls.NoClientCert),
"PKCS1WithSHA1": reflect.ValueOf(tls.PKCS1WithSHA1),
"PKCS1WithSHA256": reflect.ValueOf(tls.PKCS1WithSHA256),
"PKCS1WithSHA384": reflect.ValueOf(tls.PKCS1WithSHA384),
"PKCS1WithSHA512": reflect.ValueOf(tls.PKCS1WithSHA512),
"PSSWithSHA256": reflect.ValueOf(tls.PSSWithSHA256),
"PSSWithSHA384": reflect.ValueOf(tls.PSSWithSHA384),
"PSSWithSHA512": reflect.ValueOf(tls.PSSWithSHA512),
"RenegotiateFreelyAsClient": reflect.ValueOf(tls.RenegotiateFreelyAsClient),
"RenegotiateNever": reflect.ValueOf(tls.RenegotiateNever),
"RenegotiateOnceAsClient": reflect.ValueOf(tls.RenegotiateOnceAsClient),
"RequestClientCert": reflect.ValueOf(tls.RequestClientCert),
"RequireAndVerifyClientCert": reflect.ValueOf(tls.RequireAndVerifyClientCert),
"RequireAnyClientCert": reflect.ValueOf(tls.RequireAnyClientCert),
"Server": reflect.ValueOf(tls.Server),
"TLS_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_AES_128_GCM_SHA256),
"TLS_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_AES_256_GCM_SHA384),
"TLS_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305),
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256),
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305),
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA),
"TLS_FALLBACK_SCSV": reflect.ValueOf(tls.TLS_FALLBACK_SCSV),
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA),
"TLS_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA),
"TLS_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA256),
"TLS_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_GCM_SHA256),
"TLS_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_CBC_SHA),
"TLS_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_GCM_SHA384),
"TLS_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_RC4_128_SHA),
"VerifyClientCertIfGiven": reflect.ValueOf(tls.VerifyClientCertIfGiven),
"VersionSSL30": reflect.ValueOf(constant.MakeFromLiteral("768", token.INT, 0)),
"VersionTLS10": reflect.ValueOf(constant.MakeFromLiteral("769", token.INT, 0)),
"VersionTLS11": reflect.ValueOf(constant.MakeFromLiteral("770", token.INT, 0)),
"VersionTLS12": reflect.ValueOf(constant.MakeFromLiteral("771", token.INT, 0)),
"VersionTLS13": reflect.ValueOf(constant.MakeFromLiteral("772", token.INT, 0)),
"X25519": reflect.ValueOf(tls.X25519),
"X509KeyPair": reflect.ValueOf(tls.X509KeyPair),
// type definitions
"Certificate": reflect.ValueOf((*tls.Certificate)(nil)),
"CertificateRequestInfo": reflect.ValueOf((*tls.CertificateRequestInfo)(nil)),
"CipherSuite": reflect.ValueOf((*tls.CipherSuite)(nil)),
"ClientAuthType": reflect.ValueOf((*tls.ClientAuthType)(nil)),
"ClientHelloInfo": reflect.ValueOf((*tls.ClientHelloInfo)(nil)),
"ClientSessionCache": reflect.ValueOf((*tls.ClientSessionCache)(nil)),
"ClientSessionState": reflect.ValueOf((*tls.ClientSessionState)(nil)),
"Config": reflect.ValueOf((*tls.Config)(nil)),
"Conn": reflect.ValueOf((*tls.Conn)(nil)),
"ConnectionState": reflect.ValueOf((*tls.ConnectionState)(nil)),
"CurveID": reflect.ValueOf((*tls.CurveID)(nil)),
"Dialer": reflect.ValueOf((*tls.Dialer)(nil)),
"RecordHeaderError": reflect.ValueOf((*tls.RecordHeaderError)(nil)),
"RenegotiationSupport": reflect.ValueOf((*tls.RenegotiationSupport)(nil)),
"SignatureScheme": reflect.ValueOf((*tls.SignatureScheme)(nil)),
// interface wrapper definitions
"_ClientSessionCache": reflect.ValueOf((*_crypto_tls_ClientSessionCache)(nil)),
}
}
// _crypto_tls_ClientSessionCache is an interface wrapper for ClientSessionCache type
type _crypto_tls_ClientSessionCache struct {
IValue interface{}
WGet func(sessionKey string) (session *tls.ClientSessionState, ok bool)
WPut func(sessionKey string, cs *tls.ClientSessionState)
}
func (W _crypto_tls_ClientSessionCache) Get(sessionKey string) (session *tls.ClientSessionState, ok bool) {
return W.WGet(sessionKey)
}
func (W _crypto_tls_ClientSessionCache) Put(sessionKey string, cs *tls.ClientSessionState) {
W.WPut(sessionKey, cs)
}

View File

@@ -1,18 +0,0 @@
// Code generated by 'yaegi extract embed'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
package stdlib
import (
"embed"
"reflect"
)
func init() {
Symbols["embed/embed"] = map[string]reflect.Value{
// type definitions
"FS": reflect.ValueOf((*embed.FS)(nil)),
}
}

View File

@@ -1,21 +0,0 @@
// Code generated by 'yaegi extract errors'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
package stdlib
import (
"errors"
"reflect"
)
func init() {
Symbols["errors/errors"] = map[string]reflect.Value{
// function, constant and variable definitions
"As": reflect.ValueOf(errors.As),
"Is": reflect.ValueOf(errors.Is),
"New": reflect.ValueOf(errors.New),
"Unwrap": reflect.ValueOf(errors.Unwrap),
}
}

View File

@@ -1,36 +0,0 @@
// Code generated by 'yaegi extract net/netip'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
package stdlib
import (
"net/netip"
"reflect"
)
func init() {
Symbols["net/netip/netip"] = map[string]reflect.Value{
// function, constant and variable definitions
"AddrFrom16": reflect.ValueOf(netip.AddrFrom16),
"AddrFrom4": reflect.ValueOf(netip.AddrFrom4),
"AddrFromSlice": reflect.ValueOf(netip.AddrFromSlice),
"AddrPortFrom": reflect.ValueOf(netip.AddrPortFrom),
"IPv4Unspecified": reflect.ValueOf(netip.IPv4Unspecified),
"IPv6LinkLocalAllNodes": reflect.ValueOf(netip.IPv6LinkLocalAllNodes),
"IPv6Unspecified": reflect.ValueOf(netip.IPv6Unspecified),
"MustParseAddr": reflect.ValueOf(netip.MustParseAddr),
"MustParseAddrPort": reflect.ValueOf(netip.MustParseAddrPort),
"MustParsePrefix": reflect.ValueOf(netip.MustParsePrefix),
"ParseAddr": reflect.ValueOf(netip.ParseAddr),
"ParseAddrPort": reflect.ValueOf(netip.ParseAddrPort),
"ParsePrefix": reflect.ValueOf(netip.ParsePrefix),
"PrefixFrom": reflect.ValueOf(netip.PrefixFrom),
// type definitions
"Addr": reflect.ValueOf((*netip.Addr)(nil)),
"AddrPort": reflect.ValueOf((*netip.AddrPort)(nil)),
"Prefix": reflect.ValueOf((*netip.Prefix)(nil)),
}
}

View File

@@ -1,123 +0,0 @@
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
//go:build go1.20
// +build go1.20
package stdlib
import (
"crypto/tls"
"go/constant"
"go/token"
"reflect"
)
func init() {
Symbols["crypto/tls/tls"] = map[string]reflect.Value{
// function, constant and variable definitions
"CipherSuiteName": reflect.ValueOf(tls.CipherSuiteName),
"CipherSuites": reflect.ValueOf(tls.CipherSuites),
"Client": reflect.ValueOf(tls.Client),
"CurveP256": reflect.ValueOf(tls.CurveP256),
"CurveP384": reflect.ValueOf(tls.CurveP384),
"CurveP521": reflect.ValueOf(tls.CurveP521),
"Dial": reflect.ValueOf(tls.Dial),
"DialWithDialer": reflect.ValueOf(tls.DialWithDialer),
"ECDSAWithP256AndSHA256": reflect.ValueOf(tls.ECDSAWithP256AndSHA256),
"ECDSAWithP384AndSHA384": reflect.ValueOf(tls.ECDSAWithP384AndSHA384),
"ECDSAWithP521AndSHA512": reflect.ValueOf(tls.ECDSAWithP521AndSHA512),
"ECDSAWithSHA1": reflect.ValueOf(tls.ECDSAWithSHA1),
"Ed25519": reflect.ValueOf(tls.Ed25519),
"InsecureCipherSuites": reflect.ValueOf(tls.InsecureCipherSuites),
"Listen": reflect.ValueOf(tls.Listen),
"LoadX509KeyPair": reflect.ValueOf(tls.LoadX509KeyPair),
"NewLRUClientSessionCache": reflect.ValueOf(tls.NewLRUClientSessionCache),
"NewListener": reflect.ValueOf(tls.NewListener),
"NoClientCert": reflect.ValueOf(tls.NoClientCert),
"PKCS1WithSHA1": reflect.ValueOf(tls.PKCS1WithSHA1),
"PKCS1WithSHA256": reflect.ValueOf(tls.PKCS1WithSHA256),
"PKCS1WithSHA384": reflect.ValueOf(tls.PKCS1WithSHA384),
"PKCS1WithSHA512": reflect.ValueOf(tls.PKCS1WithSHA512),
"PSSWithSHA256": reflect.ValueOf(tls.PSSWithSHA256),
"PSSWithSHA384": reflect.ValueOf(tls.PSSWithSHA384),
"PSSWithSHA512": reflect.ValueOf(tls.PSSWithSHA512),
"RenegotiateFreelyAsClient": reflect.ValueOf(tls.RenegotiateFreelyAsClient),
"RenegotiateNever": reflect.ValueOf(tls.RenegotiateNever),
"RenegotiateOnceAsClient": reflect.ValueOf(tls.RenegotiateOnceAsClient),
"RequestClientCert": reflect.ValueOf(tls.RequestClientCert),
"RequireAndVerifyClientCert": reflect.ValueOf(tls.RequireAndVerifyClientCert),
"RequireAnyClientCert": reflect.ValueOf(tls.RequireAnyClientCert),
"Server": reflect.ValueOf(tls.Server),
"TLS_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_AES_128_GCM_SHA256),
"TLS_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_AES_256_GCM_SHA384),
"TLS_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305),
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256),
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305),
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA),
"TLS_FALLBACK_SCSV": reflect.ValueOf(tls.TLS_FALLBACK_SCSV),
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA),
"TLS_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA),
"TLS_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA256),
"TLS_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_GCM_SHA256),
"TLS_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_CBC_SHA),
"TLS_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_GCM_SHA384),
"TLS_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_RC4_128_SHA),
"VerifyClientCertIfGiven": reflect.ValueOf(tls.VerifyClientCertIfGiven),
"VersionSSL30": reflect.ValueOf(constant.MakeFromLiteral("768", token.INT, 0)),
"VersionTLS10": reflect.ValueOf(constant.MakeFromLiteral("769", token.INT, 0)),
"VersionTLS11": reflect.ValueOf(constant.MakeFromLiteral("770", token.INT, 0)),
"VersionTLS12": reflect.ValueOf(constant.MakeFromLiteral("771", token.INT, 0)),
"VersionTLS13": reflect.ValueOf(constant.MakeFromLiteral("772", token.INT, 0)),
"X25519": reflect.ValueOf(tls.X25519),
"X509KeyPair": reflect.ValueOf(tls.X509KeyPair),
// type definitions
"Certificate": reflect.ValueOf((*tls.Certificate)(nil)),
"CertificateRequestInfo": reflect.ValueOf((*tls.CertificateRequestInfo)(nil)),
"CertificateVerificationError": reflect.ValueOf((*tls.CertificateVerificationError)(nil)),
"CipherSuite": reflect.ValueOf((*tls.CipherSuite)(nil)),
"ClientAuthType": reflect.ValueOf((*tls.ClientAuthType)(nil)),
"ClientHelloInfo": reflect.ValueOf((*tls.ClientHelloInfo)(nil)),
"ClientSessionCache": reflect.ValueOf((*tls.ClientSessionCache)(nil)),
"ClientSessionState": reflect.ValueOf((*tls.ClientSessionState)(nil)),
"Config": reflect.ValueOf((*tls.Config)(nil)),
"Conn": reflect.ValueOf((*tls.Conn)(nil)),
"ConnectionState": reflect.ValueOf((*tls.ConnectionState)(nil)),
"CurveID": reflect.ValueOf((*tls.CurveID)(nil)),
"Dialer": reflect.ValueOf((*tls.Dialer)(nil)),
"RecordHeaderError": reflect.ValueOf((*tls.RecordHeaderError)(nil)),
"RenegotiationSupport": reflect.ValueOf((*tls.RenegotiationSupport)(nil)),
"SignatureScheme": reflect.ValueOf((*tls.SignatureScheme)(nil)),
// interface wrapper definitions
"_ClientSessionCache": reflect.ValueOf((*_crypto_tls_ClientSessionCache)(nil)),
}
}
// _crypto_tls_ClientSessionCache is an interface wrapper for ClientSessionCache type
type _crypto_tls_ClientSessionCache struct {
IValue interface{}
WGet func(sessionKey string) (session *tls.ClientSessionState, ok bool)
WPut func(sessionKey string, cs *tls.ClientSessionState)
}
func (W _crypto_tls_ClientSessionCache) Get(sessionKey string) (session *tls.ClientSessionState, ok bool) {
return W.WGet(sessionKey)
}
func (W _crypto_tls_ClientSessionCache) Put(sessionKey string, cs *tls.ClientSessionState) {
W.WPut(sessionKey, cs)
}

View File

@@ -1,18 +0,0 @@
// Code generated by 'yaegi extract embed'. DO NOT EDIT.
//go:build go1.20
// +build go1.20
package stdlib
import (
"embed"
"reflect"
)
func init() {
Symbols["embed/embed"] = map[string]reflect.Value{
// type definitions
"FS": reflect.ValueOf((*embed.FS)(nil)),
}
}

View File

@@ -1,22 +0,0 @@
// Code generated by 'yaegi extract errors'. DO NOT EDIT.
//go:build go1.20
// +build go1.20
package stdlib
import (
"errors"
"reflect"
)
func init() {
Symbols["errors/errors"] = map[string]reflect.Value{
// function, constant and variable definitions
"As": reflect.ValueOf(errors.As),
"Is": reflect.ValueOf(errors.Is),
"Join": reflect.ValueOf(errors.Join),
"New": reflect.ValueOf(errors.New),
"Unwrap": reflect.ValueOf(errors.Unwrap),
}
}

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract archive/tar'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
@@ -17,6 +17,7 @@ func init() {
// function, constant and variable definitions
"ErrFieldTooLong": reflect.ValueOf(&tar.ErrFieldTooLong).Elem(),
"ErrHeader": reflect.ValueOf(&tar.ErrHeader).Elem(),
"ErrInsecurePath": reflect.ValueOf(&tar.ErrInsecurePath).Elem(),
"ErrWriteAfterClose": reflect.ValueOf(&tar.ErrWriteAfterClose).Elem(),
"ErrWriteTooLong": reflect.ValueOf(&tar.ErrWriteTooLong).Elem(),
"FileInfoHeader": reflect.ValueOf(tar.FileInfoHeader),

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract archive/zip'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
@@ -17,6 +17,7 @@ func init() {
"ErrAlgorithm": reflect.ValueOf(&zip.ErrAlgorithm).Elem(),
"ErrChecksum": reflect.ValueOf(&zip.ErrChecksum).Elem(),
"ErrFormat": reflect.ValueOf(&zip.ErrFormat).Elem(),
"ErrInsecurePath": reflect.ValueOf(&zip.ErrInsecurePath).Elem(),
"FileInfoHeader": reflect.ValueOf(zip.FileInfoHeader),
"NewReader": reflect.ValueOf(zip.NewReader),
"NewWriter": reflect.ValueOf(zip.NewWriter),

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract bufio'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract bytes'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
@@ -15,12 +15,16 @@ import (
func init() {
Symbols["bytes/bytes"] = map[string]reflect.Value{
// function, constant and variable definitions
"Clone": reflect.ValueOf(bytes.Clone),
"Compare": reflect.ValueOf(bytes.Compare),
"Contains": reflect.ValueOf(bytes.Contains),
"ContainsAny": reflect.ValueOf(bytes.ContainsAny),
"ContainsFunc": reflect.ValueOf(bytes.ContainsFunc),
"ContainsRune": reflect.ValueOf(bytes.ContainsRune),
"Count": reflect.ValueOf(bytes.Count),
"Cut": reflect.ValueOf(bytes.Cut),
"CutPrefix": reflect.ValueOf(bytes.CutPrefix),
"CutSuffix": reflect.ValueOf(bytes.CutSuffix),
"Equal": reflect.ValueOf(bytes.Equal),
"EqualFold": reflect.ValueOf(bytes.EqualFold),
"ErrTooLarge": reflect.ValueOf(&bytes.ErrTooLarge).Elem(),

14
stdlib/go1_21_cmp.go Normal file
View File

@@ -0,0 +1,14 @@
// Code generated by 'yaegi extract cmp'. DO NOT EDIT.
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
import (
"reflect"
)
func init() {
Symbols["cmp/cmp"] = map[string]reflect.Value{}
}

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract compress/bzip2'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract compress/flate'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract compress/gzip'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract compress/lzw'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract compress/zlib'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract container/heap'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract container/list'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract container/ring'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

62
stdlib/go1_21_context.go Normal file
View File

@@ -0,0 +1,62 @@
// Code generated by 'yaegi extract context'. DO NOT EDIT.
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
import (
"context"
"reflect"
"time"
)
func init() {
Symbols["context/context"] = map[string]reflect.Value{
// function, constant and variable definitions
"AfterFunc": reflect.ValueOf(context.AfterFunc),
"Background": reflect.ValueOf(context.Background),
"Canceled": reflect.ValueOf(&context.Canceled).Elem(),
"Cause": reflect.ValueOf(context.Cause),
"DeadlineExceeded": reflect.ValueOf(&context.DeadlineExceeded).Elem(),
"TODO": reflect.ValueOf(context.TODO),
"WithCancel": reflect.ValueOf(context.WithCancel),
"WithCancelCause": reflect.ValueOf(context.WithCancelCause),
"WithDeadline": reflect.ValueOf(context.WithDeadline),
"WithDeadlineCause": reflect.ValueOf(context.WithDeadlineCause),
"WithTimeout": reflect.ValueOf(context.WithTimeout),
"WithTimeoutCause": reflect.ValueOf(context.WithTimeoutCause),
"WithValue": reflect.ValueOf(context.WithValue),
"WithoutCancel": reflect.ValueOf(context.WithoutCancel),
// type definitions
"CancelCauseFunc": reflect.ValueOf((*context.CancelCauseFunc)(nil)),
"CancelFunc": reflect.ValueOf((*context.CancelFunc)(nil)),
"Context": reflect.ValueOf((*context.Context)(nil)),
// interface wrapper definitions
"_Context": reflect.ValueOf((*_context_Context)(nil)),
}
}
// _context_Context is an interface wrapper for Context type
type _context_Context struct {
IValue interface{}
WDeadline func() (deadline time.Time, ok bool)
WDone func() <-chan struct{}
WErr func() error
WValue func(key any) any
}
func (W _context_Context) Deadline() (deadline time.Time, ok bool) {
return W.WDeadline()
}
func (W _context_Context) Done() <-chan struct{} {
return W.WDone()
}
func (W _context_Context) Err() error {
return W.WErr()
}
func (W _context_Context) Value(key any) any {
return W.WValue(key)
}

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/aes'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/cipher'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/des'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/dsa'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -0,0 +1,48 @@
// Code generated by 'yaegi extract crypto/ecdh'. DO NOT EDIT.
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
import (
"crypto/ecdh"
"io"
"reflect"
)
func init() {
Symbols["crypto/ecdh/ecdh"] = map[string]reflect.Value{
// function, constant and variable definitions
"P256": reflect.ValueOf(ecdh.P256),
"P384": reflect.ValueOf(ecdh.P384),
"P521": reflect.ValueOf(ecdh.P521),
"X25519": reflect.ValueOf(ecdh.X25519),
// type definitions
"Curve": reflect.ValueOf((*ecdh.Curve)(nil)),
"PrivateKey": reflect.ValueOf((*ecdh.PrivateKey)(nil)),
"PublicKey": reflect.ValueOf((*ecdh.PublicKey)(nil)),
// interface wrapper definitions
"_Curve": reflect.ValueOf((*_crypto_ecdh_Curve)(nil)),
}
}
// _crypto_ecdh_Curve is an interface wrapper for Curve type
type _crypto_ecdh_Curve struct {
IValue interface{}
WGenerateKey func(rand io.Reader) (*ecdh.PrivateKey, error)
WNewPrivateKey func(key []byte) (*ecdh.PrivateKey, error)
WNewPublicKey func(key []byte) (*ecdh.PublicKey, error)
}
func (W _crypto_ecdh_Curve) GenerateKey(rand io.Reader) (*ecdh.PrivateKey, error) {
return W.WGenerateKey(rand)
}
func (W _crypto_ecdh_Curve) NewPrivateKey(key []byte) (*ecdh.PrivateKey, error) {
return W.WNewPrivateKey(key)
}
func (W _crypto_ecdh_Curve) NewPublicKey(key []byte) (*ecdh.PublicKey, error) {
return W.WNewPublicKey(key)
}

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/ecdsa'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -0,0 +1,33 @@
// Code generated by 'yaegi extract crypto/ed25519'. DO NOT EDIT.
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
import (
"crypto/ed25519"
"go/constant"
"go/token"
"reflect"
)
func init() {
Symbols["crypto/ed25519/ed25519"] = map[string]reflect.Value{
// function, constant and variable definitions
"GenerateKey": reflect.ValueOf(ed25519.GenerateKey),
"NewKeyFromSeed": reflect.ValueOf(ed25519.NewKeyFromSeed),
"PrivateKeySize": reflect.ValueOf(constant.MakeFromLiteral("64", token.INT, 0)),
"PublicKeySize": reflect.ValueOf(constant.MakeFromLiteral("32", token.INT, 0)),
"SeedSize": reflect.ValueOf(constant.MakeFromLiteral("32", token.INT, 0)),
"Sign": reflect.ValueOf(ed25519.Sign),
"SignatureSize": reflect.ValueOf(constant.MakeFromLiteral("64", token.INT, 0)),
"Verify": reflect.ValueOf(ed25519.Verify),
"VerifyWithOptions": reflect.ValueOf(ed25519.VerifyWithOptions),
// type definitions
"Options": reflect.ValueOf((*ed25519.Options)(nil)),
"PrivateKey": reflect.ValueOf((*ed25519.PrivateKey)(nil)),
"PublicKey": reflect.ValueOf((*ed25519.PublicKey)(nil)),
}
}

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/elliptic'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/hmac'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/md5'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/rand'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/rc4'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/rsa'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/sha1'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/sha256'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/sha512'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/subtle'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
@@ -19,5 +19,6 @@ func init() {
"ConstantTimeEq": reflect.ValueOf(subtle.ConstantTimeEq),
"ConstantTimeLessOrEq": reflect.ValueOf(subtle.ConstantTimeLessOrEq),
"ConstantTimeSelect": reflect.ValueOf(subtle.ConstantTimeSelect),
"XORBytes": reflect.ValueOf(subtle.XORBytes),
}
}

148
stdlib/go1_21_crypto_tls.go Normal file
View File

@@ -0,0 +1,148 @@
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
import (
"crypto/tls"
"go/constant"
"go/token"
"reflect"
)
func init() {
Symbols["crypto/tls/tls"] = map[string]reflect.Value{
// function, constant and variable definitions
"CipherSuiteName": reflect.ValueOf(tls.CipherSuiteName),
"CipherSuites": reflect.ValueOf(tls.CipherSuites),
"Client": reflect.ValueOf(tls.Client),
"CurveP256": reflect.ValueOf(tls.CurveP256),
"CurveP384": reflect.ValueOf(tls.CurveP384),
"CurveP521": reflect.ValueOf(tls.CurveP521),
"Dial": reflect.ValueOf(tls.Dial),
"DialWithDialer": reflect.ValueOf(tls.DialWithDialer),
"ECDSAWithP256AndSHA256": reflect.ValueOf(tls.ECDSAWithP256AndSHA256),
"ECDSAWithP384AndSHA384": reflect.ValueOf(tls.ECDSAWithP384AndSHA384),
"ECDSAWithP521AndSHA512": reflect.ValueOf(tls.ECDSAWithP521AndSHA512),
"ECDSAWithSHA1": reflect.ValueOf(tls.ECDSAWithSHA1),
"Ed25519": reflect.ValueOf(tls.Ed25519),
"InsecureCipherSuites": reflect.ValueOf(tls.InsecureCipherSuites),
"Listen": reflect.ValueOf(tls.Listen),
"LoadX509KeyPair": reflect.ValueOf(tls.LoadX509KeyPair),
"NewLRUClientSessionCache": reflect.ValueOf(tls.NewLRUClientSessionCache),
"NewListener": reflect.ValueOf(tls.NewListener),
"NewResumptionState": reflect.ValueOf(tls.NewResumptionState),
"NoClientCert": reflect.ValueOf(tls.NoClientCert),
"PKCS1WithSHA1": reflect.ValueOf(tls.PKCS1WithSHA1),
"PKCS1WithSHA256": reflect.ValueOf(tls.PKCS1WithSHA256),
"PKCS1WithSHA384": reflect.ValueOf(tls.PKCS1WithSHA384),
"PKCS1WithSHA512": reflect.ValueOf(tls.PKCS1WithSHA512),
"PSSWithSHA256": reflect.ValueOf(tls.PSSWithSHA256),
"PSSWithSHA384": reflect.ValueOf(tls.PSSWithSHA384),
"PSSWithSHA512": reflect.ValueOf(tls.PSSWithSHA512),
"ParseSessionState": reflect.ValueOf(tls.ParseSessionState),
"QUICClient": reflect.ValueOf(tls.QUICClient),
"QUICEncryptionLevelApplication": reflect.ValueOf(tls.QUICEncryptionLevelApplication),
"QUICEncryptionLevelEarly": reflect.ValueOf(tls.QUICEncryptionLevelEarly),
"QUICEncryptionLevelHandshake": reflect.ValueOf(tls.QUICEncryptionLevelHandshake),
"QUICEncryptionLevelInitial": reflect.ValueOf(tls.QUICEncryptionLevelInitial),
"QUICHandshakeDone": reflect.ValueOf(tls.QUICHandshakeDone),
"QUICNoEvent": reflect.ValueOf(tls.QUICNoEvent),
"QUICRejectedEarlyData": reflect.ValueOf(tls.QUICRejectedEarlyData),
"QUICServer": reflect.ValueOf(tls.QUICServer),
"QUICSetReadSecret": reflect.ValueOf(tls.QUICSetReadSecret),
"QUICSetWriteSecret": reflect.ValueOf(tls.QUICSetWriteSecret),
"QUICTransportParameters": reflect.ValueOf(tls.QUICTransportParameters),
"QUICTransportParametersRequired": reflect.ValueOf(tls.QUICTransportParametersRequired),
"QUICWriteData": reflect.ValueOf(tls.QUICWriteData),
"RenegotiateFreelyAsClient": reflect.ValueOf(tls.RenegotiateFreelyAsClient),
"RenegotiateNever": reflect.ValueOf(tls.RenegotiateNever),
"RenegotiateOnceAsClient": reflect.ValueOf(tls.RenegotiateOnceAsClient),
"RequestClientCert": reflect.ValueOf(tls.RequestClientCert),
"RequireAndVerifyClientCert": reflect.ValueOf(tls.RequireAndVerifyClientCert),
"RequireAnyClientCert": reflect.ValueOf(tls.RequireAnyClientCert),
"Server": reflect.ValueOf(tls.Server),
"TLS_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_AES_128_GCM_SHA256),
"TLS_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_AES_256_GCM_SHA384),
"TLS_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305),
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256),
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305),
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
"TLS_ECDHE_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA),
"TLS_FALLBACK_SCSV": reflect.ValueOf(tls.TLS_FALLBACK_SCSV),
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA),
"TLS_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA),
"TLS_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA256),
"TLS_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_GCM_SHA256),
"TLS_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_CBC_SHA),
"TLS_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_GCM_SHA384),
"TLS_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_RC4_128_SHA),
"VerifyClientCertIfGiven": reflect.ValueOf(tls.VerifyClientCertIfGiven),
"VersionName": reflect.ValueOf(tls.VersionName),
"VersionSSL30": reflect.ValueOf(constant.MakeFromLiteral("768", token.INT, 0)),
"VersionTLS10": reflect.ValueOf(constant.MakeFromLiteral("769", token.INT, 0)),
"VersionTLS11": reflect.ValueOf(constant.MakeFromLiteral("770", token.INT, 0)),
"VersionTLS12": reflect.ValueOf(constant.MakeFromLiteral("771", token.INT, 0)),
"VersionTLS13": reflect.ValueOf(constant.MakeFromLiteral("772", token.INT, 0)),
"X25519": reflect.ValueOf(tls.X25519),
"X509KeyPair": reflect.ValueOf(tls.X509KeyPair),
// type definitions
"AlertError": reflect.ValueOf((*tls.AlertError)(nil)),
"Certificate": reflect.ValueOf((*tls.Certificate)(nil)),
"CertificateRequestInfo": reflect.ValueOf((*tls.CertificateRequestInfo)(nil)),
"CertificateVerificationError": reflect.ValueOf((*tls.CertificateVerificationError)(nil)),
"CipherSuite": reflect.ValueOf((*tls.CipherSuite)(nil)),
"ClientAuthType": reflect.ValueOf((*tls.ClientAuthType)(nil)),
"ClientHelloInfo": reflect.ValueOf((*tls.ClientHelloInfo)(nil)),
"ClientSessionCache": reflect.ValueOf((*tls.ClientSessionCache)(nil)),
"ClientSessionState": reflect.ValueOf((*tls.ClientSessionState)(nil)),
"Config": reflect.ValueOf((*tls.Config)(nil)),
"Conn": reflect.ValueOf((*tls.Conn)(nil)),
"ConnectionState": reflect.ValueOf((*tls.ConnectionState)(nil)),
"CurveID": reflect.ValueOf((*tls.CurveID)(nil)),
"Dialer": reflect.ValueOf((*tls.Dialer)(nil)),
"QUICConfig": reflect.ValueOf((*tls.QUICConfig)(nil)),
"QUICConn": reflect.ValueOf((*tls.QUICConn)(nil)),
"QUICEncryptionLevel": reflect.ValueOf((*tls.QUICEncryptionLevel)(nil)),
"QUICEvent": reflect.ValueOf((*tls.QUICEvent)(nil)),
"QUICEventKind": reflect.ValueOf((*tls.QUICEventKind)(nil)),
"QUICSessionTicketOptions": reflect.ValueOf((*tls.QUICSessionTicketOptions)(nil)),
"RecordHeaderError": reflect.ValueOf((*tls.RecordHeaderError)(nil)),
"RenegotiationSupport": reflect.ValueOf((*tls.RenegotiationSupport)(nil)),
"SessionState": reflect.ValueOf((*tls.SessionState)(nil)),
"SignatureScheme": reflect.ValueOf((*tls.SignatureScheme)(nil)),
// interface wrapper definitions
"_ClientSessionCache": reflect.ValueOf((*_crypto_tls_ClientSessionCache)(nil)),
}
}
// _crypto_tls_ClientSessionCache is an interface wrapper for ClientSessionCache type
type _crypto_tls_ClientSessionCache struct {
IValue interface{}
WGet func(sessionKey string) (session *tls.ClientSessionState, ok bool)
WPut func(sessionKey string, cs *tls.ClientSessionState)
}
func (W _crypto_tls_ClientSessionCache) Get(sessionKey string) (session *tls.ClientSessionState, ok bool) {
return W.WGet(sessionKey)
}
func (W _crypto_tls_ClientSessionCache) Put(sessionKey string, cs *tls.ClientSessionState) {
W.WPut(sessionKey, cs)
}

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/x509'. DO NOT EDIT.
//go:build go1.20
// +build go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
@@ -115,6 +115,7 @@ func init() {
"PEMCipher": reflect.ValueOf((*x509.PEMCipher)(nil)),
"PublicKeyAlgorithm": reflect.ValueOf((*x509.PublicKeyAlgorithm)(nil)),
"RevocationList": reflect.ValueOf((*x509.RevocationList)(nil)),
"RevocationListEntry": reflect.ValueOf((*x509.RevocationListEntry)(nil)),
"SignatureAlgorithm": reflect.ValueOf((*x509.SignatureAlgorithm)(nil)),
"SystemRootsError": reflect.ValueOf((*x509.SystemRootsError)(nil)),
"UnhandledCriticalExtension": reflect.ValueOf((*x509.UnhandledCriticalExtension)(nil)),

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract crypto/x509/pkix'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract database/sql'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract database/sql/driver'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract debug/buildinfo'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract debug/dwarf'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract debug/elf'. DO NOT EDIT.
//go:build go1.20
// +build go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib
@@ -21,6 +21,38 @@ func init() {
"COMPRESS_LOOS": reflect.ValueOf(elf.COMPRESS_LOOS),
"COMPRESS_LOPROC": reflect.ValueOf(elf.COMPRESS_LOPROC),
"COMPRESS_ZLIB": reflect.ValueOf(elf.COMPRESS_ZLIB),
"COMPRESS_ZSTD": reflect.ValueOf(elf.COMPRESS_ZSTD),
"DF_1_CONFALT": reflect.ValueOf(elf.DF_1_CONFALT),
"DF_1_DIRECT": reflect.ValueOf(elf.DF_1_DIRECT),
"DF_1_DISPRELDNE": reflect.ValueOf(elf.DF_1_DISPRELDNE),
"DF_1_DISPRELPND": reflect.ValueOf(elf.DF_1_DISPRELPND),
"DF_1_EDITED": reflect.ValueOf(elf.DF_1_EDITED),
"DF_1_ENDFILTEE": reflect.ValueOf(elf.DF_1_ENDFILTEE),
"DF_1_GLOBAL": reflect.ValueOf(elf.DF_1_GLOBAL),
"DF_1_GLOBAUDIT": reflect.ValueOf(elf.DF_1_GLOBAUDIT),
"DF_1_GROUP": reflect.ValueOf(elf.DF_1_GROUP),
"DF_1_IGNMULDEF": reflect.ValueOf(elf.DF_1_IGNMULDEF),
"DF_1_INITFIRST": reflect.ValueOf(elf.DF_1_INITFIRST),
"DF_1_INTERPOSE": reflect.ValueOf(elf.DF_1_INTERPOSE),
"DF_1_KMOD": reflect.ValueOf(elf.DF_1_KMOD),
"DF_1_LOADFLTR": reflect.ValueOf(elf.DF_1_LOADFLTR),
"DF_1_NOCOMMON": reflect.ValueOf(elf.DF_1_NOCOMMON),
"DF_1_NODEFLIB": reflect.ValueOf(elf.DF_1_NODEFLIB),
"DF_1_NODELETE": reflect.ValueOf(elf.DF_1_NODELETE),
"DF_1_NODIRECT": reflect.ValueOf(elf.DF_1_NODIRECT),
"DF_1_NODUMP": reflect.ValueOf(elf.DF_1_NODUMP),
"DF_1_NOHDR": reflect.ValueOf(elf.DF_1_NOHDR),
"DF_1_NOKSYMS": reflect.ValueOf(elf.DF_1_NOKSYMS),
"DF_1_NOOPEN": reflect.ValueOf(elf.DF_1_NOOPEN),
"DF_1_NORELOC": reflect.ValueOf(elf.DF_1_NORELOC),
"DF_1_NOW": reflect.ValueOf(elf.DF_1_NOW),
"DF_1_ORIGIN": reflect.ValueOf(elf.DF_1_ORIGIN),
"DF_1_PIE": reflect.ValueOf(elf.DF_1_PIE),
"DF_1_SINGLETON": reflect.ValueOf(elf.DF_1_SINGLETON),
"DF_1_STUB": reflect.ValueOf(elf.DF_1_STUB),
"DF_1_SYMINTPOSE": reflect.ValueOf(elf.DF_1_SYMINTPOSE),
"DF_1_TRANS": reflect.ValueOf(elf.DF_1_TRANS),
"DF_1_WEAKFILTER": reflect.ValueOf(elf.DF_1_WEAKFILTER),
"DF_BIND_NOW": reflect.ValueOf(elf.DF_BIND_NOW),
"DF_ORIGIN": reflect.ValueOf(elf.DF_ORIGIN),
"DF_STATIC_TLS": reflect.ValueOf(elf.DF_STATIC_TLS),
@@ -1097,6 +1129,7 @@ func init() {
"R_PPC64_REL16_LO": reflect.ValueOf(elf.R_PPC64_REL16_LO),
"R_PPC64_REL24": reflect.ValueOf(elf.R_PPC64_REL24),
"R_PPC64_REL24_NOTOC": reflect.ValueOf(elf.R_PPC64_REL24_NOTOC),
"R_PPC64_REL24_P9NOTOC": reflect.ValueOf(elf.R_PPC64_REL24_P9NOTOC),
"R_PPC64_REL30": reflect.ValueOf(elf.R_PPC64_REL30),
"R_PPC64_REL32": reflect.ValueOf(elf.R_PPC64_REL32),
"R_PPC64_REL64": reflect.ValueOf(elf.R_PPC64_REL64),
@@ -1460,6 +1493,7 @@ func init() {
"Dyn32": reflect.ValueOf((*elf.Dyn32)(nil)),
"Dyn64": reflect.ValueOf((*elf.Dyn64)(nil)),
"DynFlag": reflect.ValueOf((*elf.DynFlag)(nil)),
"DynFlag1": reflect.ValueOf((*elf.DynFlag1)(nil)),
"DynTag": reflect.ValueOf((*elf.DynTag)(nil)),
"File": reflect.ValueOf((*elf.File)(nil)),
"FileHeader": reflect.ValueOf((*elf.FileHeader)(nil)),

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract debug/gosym'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

View File

@@ -1,7 +1,7 @@
// Code generated by 'yaegi extract debug/macho'. DO NOT EDIT.
//go:build go1.19 && !go1.20
// +build go1.19,!go1.20
//go:build go1.21 && !go1.22
// +build go1.21,!go1.22
package stdlib

Some files were not shown because too many files have changed in this diff Show More