build: separate compiler and libs

This commit is contained in:
Li Jie
2025-01-07 21:49:08 +08:00
parent b0123567cd
commit 1172e5bdce
559 changed files with 190 additions and 176 deletions

View File

@@ -1,14 +0,0 @@
// 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 abi
// Map constants common to several packages
// runtime/runtime-gdb.py:MapTypePrinter contains its own copy
const (
MapBucketCountBits = 3 // log2 of number of elements in a bucket.
MapBucketCount = 1 << MapBucketCountBits
MapMaxKeyBytes = 128 // Must fit in a uint8.
MapMaxElemBytes = 128 // Must fit in a uint8.
)

View File

@@ -1,610 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package abi
import (
"unsafe"
)
// IsExported reports whether name starts with an upper-case letter.
func IsExported(name string) bool {
if len(name) > 0 {
c := name[0]
return 'A' <= c && c <= 'Z'
}
return false
}
// -----------------------------------------------------------------------------
// Type is the runtime representation of a Go type.
//
// Type is also referenced implicitly
// (in the form of expressions involving constants and arch.PtrSize)
// in cmd/compile/internal/reflectdata/reflect.go
// and cmd/link/internal/ld/decodesym.go
// (e.g. data[2*arch.PtrSize+4] references the TFlag field)
// unsafe.OffsetOf(Type{}.TFlag) cannot be used directly in those
// places because it varies with cross compilation and experiments.
type Type struct {
Size_ uintptr
PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers
Hash uint32 // hash of type; avoids computation in hash tables
TFlag TFlag // extra type information flags
Align_ uint8 // alignment of variable with this type
FieldAlign_ uint8 // alignment of struct field with this type
Kind_ uint8 // enumeration for C
// function for comparing objects of this type
// (ptr to object A, ptr to object B) -> ==?
Equal func(unsafe.Pointer, unsafe.Pointer) bool
// GCData stores the GC type data for the garbage collector.
// If the KindGCProg bit is set in kind, GCData is a GC program.
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
GCData *byte
Str_ string // string form
PtrToThis_ *Type // type for pointer to this type, may be nil
}
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
type Kind uint
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Pointer
Slice
String
Struct
UnsafePointer
)
const (
// TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible.
KindDirectIface = 1 << 5
KindGCProg = 1 << 6 // Type.gc points to GC program
KindMask = (1 << 5) - 1
)
// String returns the name of k.
func (k Kind) String() string {
if int(k) < len(kindNames) {
return kindNames[k]
}
return kindNames[0]
}
var kindNames = []string{
Invalid: "invalid",
Bool: "bool",
Int: "int",
Int8: "int8",
Int16: "int16",
Int32: "int32",
Int64: "int64",
Uint: "uint",
Uint8: "uint8",
Uint16: "uint16",
Uint32: "uint32",
Uint64: "uint64",
Uintptr: "uintptr",
Float32: "float32",
Float64: "float64",
Complex64: "complex64",
Complex128: "complex128",
Array: "array",
Chan: "chan",
Func: "func",
Interface: "interface",
Map: "map",
Pointer: "ptr",
Slice: "slice",
String: "string",
Struct: "struct",
UnsafePointer: "unsafe.Pointer",
}
// TFlag is used by a Type to signal what extra type information is
// available in the memory directly following the Type value.
type TFlag uint8
const (
// TFlagUncommon means that there is a data with a type, UncommonType,
// just beyond the shared-per-type common data. That is, the data
// for struct types will store their UncommonType at one offset, the
// data for interface types will store their UncommonType at a different
// offset. UncommonType is always accessed via a pointer that is computed
// using trust-us-we-are-the-implementors pointer arithmetic.
//
// For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0,
// then t has UncommonType data and it can be accessed as:
//
// type structTypeUncommon struct {
// structType
// u UncommonType
// }
// u := &(*structTypeUncommon)(unsafe.Pointer(t)).u
TFlagUncommon TFlag = 1 << 0
// TFlagExtraStar means the name in the str field has an
// extraneous '*' prefix. This is because for most types T in
// a program, the type *T also exists and reusing the str data
// saves binary size.
TFlagExtraStar TFlag = 1 << 1
// TFlagNamed means the type has a name.
TFlagNamed TFlag = 1 << 2
// TFlagRegularMemory means that equal and hash functions can treat
// this type as a single region of t.size bytes.
TFlagRegularMemory TFlag = 1 << 3
// TFlagVariadic means a funcType with variadic parameters
TFlagVariadic TFlag = 1 << 4
// TFflagClosure means the structType is a closure
TFlagClosure TFlag = 1 << 5
// TFlagUninited means this type is not fully initialized.
TFlagUninited TFlag = 1 << 7
)
// -----------------------------------------------------------------------------
// ArrayType represents a fixed array type.
type ArrayType struct {
Type
Elem *Type // array element type
Slice *Type // slice type
Len uintptr
}
type SliceType struct {
Type
Elem *Type // slice element type
}
type MapType struct {
Type
Key *Type
Elem *Type
Bucket *Type // internal type representing a hash bucket
// function for hashing keys (ptr to key, seed) -> hash
Hasher func(unsafe.Pointer, uintptr) uintptr
KeySize uint8 // size of key slot
ValueSize uint8 // size of elem slot
BucketSize uint16 // size of bucket
Flags uint32
}
// Note: flag values must match those used in the TMAP case
// in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
func (mt *MapType) IndirectKey() bool { // store ptr to key instead of key itself
return mt.Flags&1 != 0
}
func (mt *MapType) IndirectElem() bool { // store ptr to elem instead of elem itself
return mt.Flags&2 != 0
}
func (mt *MapType) ReflexiveKey() bool { // true if k==k for all keys
return mt.Flags&4 != 0
}
func (mt *MapType) NeedKeyUpdate() bool { // true if we need to update key on an overwrite
return mt.Flags&8 != 0
}
func (mt *MapType) HashMightPanic() bool { // true if hash function might panic
return mt.Flags&16 != 0
}
func (t *Type) Key() *Type {
if t.Kind() == Map {
return (*MapType)(unsafe.Pointer(t)).Key
}
return nil
}
type PtrType struct {
Type
Elem *Type // pointer element (pointed at) type
}
type ChanDir int
const (
RecvDir ChanDir = 1 << iota // <-chan
SendDir // chan<-
BothDir = RecvDir | SendDir // chan
InvalidDir ChanDir = 0
)
// ChanType represents a channel type
type ChanType struct {
Type
Elem *Type
Dir ChanDir
}
// funcType represents a function type.
type FuncType struct {
Type
In []*Type
Out []*Type
}
// Variadic reports whether the function type is variadic.
func (p *FuncType) Variadic() bool {
return p.TFlag&TFlagVariadic != 0
}
type StructField struct {
Name_ string // name is always non-empty
Typ *Type // type of field
Offset uintptr // byte offset of field
Tag_ string
Embedded_ bool
}
// Embedded reports whether the field is embedded.
func (f *StructField) Embedded() bool {
return f.Embedded_
}
// Exported reports whether the field is exported.
func (f *StructField) Exported() bool {
return IsExported(f.Name_)
}
type StructType struct {
Type
PkgPath_ string
Fields []StructField
}
type InterfaceType struct {
Type
PkgPath_ string // import path
Methods []Imethod // sorted by hash
}
type Text = unsafe.Pointer // TODO(xsw): to be confirmed
// Method on non-interface type
type Method struct {
Name_ string // name of method
Mtyp_ *FuncType // method type (without receiver)
Ifn_ Text // fn used in interface call (one-word receiver)
Tfn_ Text // fn used for normal method call
}
// Exported reports whether the method is exported.
func (p *Method) Exported() bool {
return lastDot(p.Name_) == -1
}
// Name returns the tag string for method.
func (p *Method) Name() string {
_, name := splitName(p.Name_)
return name
}
// PkgPath returns the pkgpath string for method, or empty if there is none.
func (p *Method) PkgPath() string {
pkg, _ := splitName(p.Name_)
return pkg
}
// UncommonType is present only for defined types or types with methods
// (if T is a defined type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe a non-defined type with no methods.
type UncommonType struct {
PkgPath_ string // import path; empty for built-in types like int, string
Mcount uint16 // number of methods
Xcount uint16 // number of exported methods
Moff uint32 // offset from this uncommontype to [mcount]Method
}
func (t *UncommonType) Methods() []Method {
if t.Mcount == 0 {
return nil
}
return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.mcount > 0"))[:t.Mcount:t.Mcount]
}
func (t *UncommonType) ExportedMethods() []Method {
if t.Xcount == 0 {
return nil
}
return (*[1 << 16]Method)(addChecked(unsafe.Pointer(t), uintptr(t.Moff), "t.xcount > 0"))[:t.Xcount:t.Xcount]
}
// Imethod represents a method on an interface type
type Imethod struct {
Name_ string // name of method
Typ_ *FuncType // .(*FuncType) underneath
}
// Exported reports whether the imethod is exported.
func (p *Imethod) Exported() bool {
return lastDot(p.Name_) == -1
}
// Name returns the tag string for imethod.
func (p *Imethod) Name() string {
_, name := splitName(p.Name_)
return name
}
// PkgPath returns the pkgpath string for imethod, or empty if there is none.
func (p *Imethod) PkgPath() string {
pkg, _ := splitName(p.Name_)
return pkg
}
func (t *Type) Kind() Kind { return Kind(t.Kind_ & KindMask) }
func (t *Type) HasName() bool {
return t.TFlag&TFlagNamed != 0
}
func (t *Type) Pointers() bool { return t.PtrBytes != 0 }
// IfaceIndir reports whether t is stored indirectly in an interface value.
func (t *Type) IfaceIndir() bool {
return t.Kind_&KindDirectIface == 0
}
// IsDirectIface reports whether t is stored directly in an interface value.
func (t *Type) IsDirectIface() bool {
return t.Kind_&KindDirectIface != 0
}
// IsClosure reports whether t is closure struct
func (t *Type) IsClosure() bool {
return t.TFlag&TFlagClosure != 0
}
// Size returns the size of data with type t.
func (t *Type) Size() uintptr { return t.Size_ }
// Align returns the alignment of data with type t.
func (t *Type) Align() int { return int(t.Align_) }
func (t *Type) FieldAlign() int { return int(t.FieldAlign_) }
// String returns string form of type t.
func (t *Type) String() string {
if t.TFlag&TFlagExtraStar != 0 {
return "*" + t.Str_ // TODO(xsw): misunderstand
}
return t.Str_
}
func (t *Type) Common() *Type {
return t
}
type structTypeUncommon struct {
StructType
u UncommonType
}
// ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0).
func (t *Type) ChanDir() ChanDir {
if t.Kind() == Chan {
ch := (*ChanType)(unsafe.Pointer(t))
return ch.Dir
}
return InvalidDir
}
// Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil
func (t *Type) Uncommon() *UncommonType {
if t.TFlag&TFlagUncommon == 0 {
return nil
}
switch t.Kind() {
case Struct:
return &(*structTypeUncommon)(unsafe.Pointer(t)).u
case Pointer:
type u struct {
PtrType
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
case Func:
type u struct {
FuncType
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
case Slice:
type u struct {
SliceType
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
case Array:
type u struct {
ArrayType
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
case Chan:
type u struct {
ChanType
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
case Map:
type u struct {
MapType
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
case Interface:
type u struct {
InterfaceType
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
default:
type u struct {
Type
u UncommonType
}
return &(*u)(unsafe.Pointer(t)).u
}
}
// Len returns the length of t if t is an array type, otherwise 0
func (t *Type) Len() int {
if t.Kind() == Array {
return int((*ArrayType)(unsafe.Pointer(t)).Len)
}
return 0
}
// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil.
func (t *Type) Elem() *Type {
switch t.Kind() {
case Pointer:
tt := (*PtrType)(unsafe.Pointer(t))
return tt.Elem
case Slice:
tt := (*SliceType)(unsafe.Pointer(t))
return tt.Elem
case Map:
tt := (*MapType)(unsafe.Pointer(t))
return tt.Elem
case Array:
tt := (*ArrayType)(unsafe.Pointer(t))
return tt.Elem
case Chan:
tt := (*ChanType)(unsafe.Pointer(t))
return tt.Elem
}
return nil
}
// StructType returns t cast to a *StructType, or nil if its tag does not match.
func (t *Type) StructType() *StructType {
if t.Kind() != Struct {
return nil
}
return (*StructType)(unsafe.Pointer(t))
}
// MapType returns t cast to a *MapType, or nil if its tag does not match.
func (t *Type) MapType() *MapType {
if t.Kind() != Map {
return nil
}
return (*MapType)(unsafe.Pointer(t))
}
// ArrayType returns t cast to a *ArrayType, or nil if its tag does not match.
func (t *Type) ArrayType() *ArrayType {
if t.Kind() != Array {
return nil
}
return (*ArrayType)(unsafe.Pointer(t))
}
// FuncType returns t cast to a *FuncType, or nil if its tag does not match.
func (t *Type) FuncType() *FuncType {
if t.Kind() != Func {
return nil
}
return (*FuncType)(unsafe.Pointer(t))
}
// InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match.
func (t *Type) InterfaceType() *InterfaceType {
if t.Kind() != Interface {
return nil
}
return (*InterfaceType)(unsafe.Pointer(t))
}
func (t *Type) ExportedMethods() []Method {
ut := t.Uncommon()
if ut == nil {
return nil
}
return ut.ExportedMethods()
}
func (t *Type) NumMethod() int {
if t.Kind() == Interface {
tt := (*InterfaceType)(unsafe.Pointer(t))
return len(tt.Methods)
}
return len(t.ExportedMethods())
}
// -----------------------------------------------------------------------------
// addChecked returns p+x.
//
// The whySafe string is ignored, so that the function still inlines
// as efficiently as p+x, but all call sites should use the string to
// record why the addition is safe, which is to say why the addition
// does not cause x to advance to the very end of p's allocation
// and therefore point incorrectly at the next block in memory.
func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
_ = whySafe
return unsafe.Pointer(uintptr(p) + x)
}
func splitName(s string) (pkg string, name string) {
i := lastDot(s)
if i == -1 {
return "", s
}
return s[:i], s[i+1:]
}
func lastDot(s string) int {
i := len(s) - 1
for i >= 0 && s[i] != '.' {
i--
}
return i
}
// -----------------------------------------------------------------------------

View File

@@ -1,32 +0,0 @@
// Copyright 2024 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 aliases
import (
"go/token"
"go/types"
)
// Package aliases defines backward compatible shims
// for the types.Alias type representation added in 1.22.
// This defines placeholders for x/tools until 1.26.
// NewAlias creates a new TypeName in Package pkg that
// is an alias for the type rhs.
//
// The enabled parameter determines whether the resulting [TypeName]'s
// type is an [types.Alias]. Its value must be the result of a call to
// [Enabled], which computes the effective value of
// GODEBUG=gotypesalias=... by invoking the type checker. The Enabled
// function is expensive and should be called once per task (e.g.
// package import), not once per call to NewAlias.
func NewAlias(enabled bool, pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName {
if enabled {
tname := types.NewTypeName(pos, pkg, name, nil)
newAlias(tname, rhs)
return tname
}
return types.NewTypeName(pos, pkg, name, rhs)
}

View File

@@ -1,31 +0,0 @@
// Copyright 2024 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:build !go1.22
// +build !go1.22
package aliases
import (
"go/types"
)
// Alias is a placeholder for a go/types.Alias for <=1.21.
// It will never be created by go/types.
type Alias struct{}
func (*Alias) String() string { panic("unreachable") }
func (*Alias) Underlying() types.Type { panic("unreachable") }
func (*Alias) Obj() *types.TypeName { panic("unreachable") }
func Rhs(alias *Alias) types.Type { panic("unreachable") }
// Unalias returns the type t for go <=1.21.
func Unalias(t types.Type) types.Type { return t }
func newAlias(name *types.TypeName, rhs types.Type) *Alias { panic("unreachable") }
// Enabled reports whether [NewAlias] should create [types.Alias] types.
//
// Before go1.22, this function always returns false.
func Enabled() bool { return false }

View File

@@ -1,63 +0,0 @@
// Copyright 2024 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:build go1.22
// +build go1.22
package aliases
import (
"go/ast"
"go/parser"
"go/token"
"go/types"
)
// Alias is an alias of types.Alias.
type Alias = types.Alias
// Rhs returns the type on the right-hand side of the alias declaration.
func Rhs(alias *Alias) types.Type {
if alias, ok := any(alias).(interface{ Rhs() types.Type }); ok {
return alias.Rhs() // go1.23+
}
// go1.22's Alias didn't have the Rhs method,
// so Unalias is the best we can do.
return Unalias(alias)
}
// Unalias is a wrapper of types.Unalias.
func Unalias(t types.Type) types.Type { return types.Unalias(t) }
// newAlias is an internal alias around types.NewAlias.
// Direct usage is discouraged as the moment.
// Try to use NewAlias instead.
func newAlias(tname *types.TypeName, rhs types.Type) *Alias {
a := types.NewAlias(tname, rhs)
// TODO(go.dev/issue/65455): Remove kludgy workaround to set a.actual as a side-effect.
Unalias(a)
return a
}
// Enabled reports whether [NewAlias] should create [types.Alias] types.
//
// This function is expensive! Call it sparingly.
func Enabled() bool {
// The only reliable way to compute the answer is to invoke go/types.
// We don't parse the GODEBUG environment variable, because
// (a) it's tricky to do so in a manner that is consistent
// with the godebug package; in particular, a simple
// substring check is not good enough. The value is a
// rightmost-wins list of options. But more importantly:
// (b) it is impossible to detect changes to the effective
// setting caused by os.Setenv("GODEBUG"), as happens in
// many tests. Therefore any attempt to cache the result
// is just incorrect.
fset := token.NewFileSet()
f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", 0)
pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil)
_, enabled := pkg.Scope().Lookup("A").Type().(*types.Alias)
return enabled
}

View File

@@ -1,612 +0,0 @@
// 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 parser
import (
"fmt"
"go/ast"
"go/token"
"strings"
)
const debugResolve = false
// resolveFile walks the given file to resolve identifiers within the file
// scope, updating ast.Ident.Obj fields with declaration information.
//
// If declErr is non-nil, it is used to report declaration errors during
// resolution. tok is used to format position in error messages.
func resolveFile(file *ast.File, handle *token.File, declErr func(token.Pos, string)) {
pkgScope := ast.NewScope(nil)
r := &resolver{
handle: handle,
declErr: declErr,
topScope: pkgScope,
pkgScope: pkgScope,
depth: 1,
}
for _, decl := range file.Decls {
ast.Walk(r, decl)
}
r.closeScope()
assert(r.topScope == nil, "unbalanced scopes")
assert(r.labelScope == nil, "unbalanced label scopes")
// resolve global identifiers within the same file
i := 0
for _, ident := range r.unresolved {
// i <= index for current ident
assert(ident.Obj == unresolved, "object already resolved")
ident.Obj = r.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel
if ident.Obj == nil {
r.unresolved[i] = ident
i++
} else if debugResolve {
pos := ident.Obj.Decl.(interface{ Pos() token.Pos }).Pos()
r.trace("resolved %s@%v to package object %v", ident.Name, ident.Pos(), pos)
}
}
file.Scope = r.pkgScope
file.Unresolved = r.unresolved[0:i]
}
const maxScopeDepth int = 1e3
type resolver struct {
handle *token.File
declErr func(token.Pos, string)
// Ordinary identifier scopes
pkgScope *ast.Scope // pkgScope.Outer == nil
topScope *ast.Scope // top-most scope; may be pkgScope
unresolved []*ast.Ident // unresolved identifiers
depth int // scope depth
// Label scopes
// (maintained by open/close LabelScope)
labelScope *ast.Scope // label scope for current function
targetStack [][]*ast.Ident // stack of unresolved labels
}
func (r *resolver) trace(format string, args ...any) {
fmt.Println(strings.Repeat(". ", r.depth) + r.sprintf(format, args...))
}
func (r *resolver) sprintf(format string, args ...any) string {
for i, arg := range args {
switch arg := arg.(type) {
case token.Pos:
args[i] = r.handle.Position(arg)
}
}
return fmt.Sprintf(format, args...)
}
func (r *resolver) openScope(pos token.Pos) {
r.depth++
if r.depth > maxScopeDepth {
panic(bailout{pos: pos, msg: "exceeded max scope depth during object resolution"})
}
if debugResolve {
r.trace("opening scope @%v", pos)
}
r.topScope = ast.NewScope(r.topScope)
}
func (r *resolver) closeScope() {
r.depth--
if debugResolve {
r.trace("closing scope")
}
r.topScope = r.topScope.Outer
}
func (r *resolver) openLabelScope() {
r.labelScope = ast.NewScope(r.labelScope)
r.targetStack = append(r.targetStack, nil)
}
func (r *resolver) closeLabelScope() {
// resolve labels
n := len(r.targetStack) - 1
scope := r.labelScope
for _, ident := range r.targetStack[n] {
ident.Obj = scope.Lookup(ident.Name)
if ident.Obj == nil && r.declErr != nil {
r.declErr(ident.Pos(), fmt.Sprintf("label %s undefined", ident.Name))
}
}
// pop label scope
r.targetStack = r.targetStack[0:n]
r.labelScope = r.labelScope.Outer
}
func (r *resolver) declare(decl, data any, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
for _, ident := range idents {
if ident.Obj != nil {
panic(fmt.Sprintf("%v: identifier %s already declared or resolved", ident.Pos(), ident.Name))
}
obj := ast.NewObj(kind, ident.Name)
// remember the corresponding declaration for redeclaration
// errors and global variable resolution/typechecking phase
obj.Decl = decl
obj.Data = data
// Identifiers (for receiver type parameters) are written to the scope, but
// never set as the resolved object. See issue #50956.
if _, ok := decl.(*ast.Ident); !ok {
ident.Obj = obj
}
if ident.Name != "_" {
if debugResolve {
r.trace("declaring %s@%v", ident.Name, ident.Pos())
}
if alt := scope.Insert(obj); alt != nil && r.declErr != nil {
prevDecl := ""
if pos := alt.Pos(); pos.IsValid() {
prevDecl = r.sprintf("\n\tprevious declaration at %v", pos)
}
r.declErr(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
}
}
}
}
func (r *resolver) shortVarDecl(decl *ast.AssignStmt) {
// Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with
// the same type, and at least one of the non-blank variables is new.
n := 0 // number of new variables
for _, x := range decl.Lhs {
if ident, isIdent := x.(*ast.Ident); isIdent {
assert(ident.Obj == nil, "identifier already declared or resolved")
obj := ast.NewObj(ast.Var, ident.Name)
// remember corresponding assignment for other tools
obj.Decl = decl
ident.Obj = obj
if ident.Name != "_" {
if debugResolve {
r.trace("declaring %s@%v", ident.Name, ident.Pos())
}
if alt := r.topScope.Insert(obj); alt != nil {
ident.Obj = alt // redeclaration
} else {
n++ // new declaration
}
}
}
}
if n == 0 && r.declErr != nil {
r.declErr(decl.Lhs[0].Pos(), "no new variables on left side of :=")
}
}
// The unresolved object is a sentinel to mark identifiers that have been added
// to the list of unresolved identifiers. The sentinel is only used for verifying
// internal consistency.
var unresolved = new(ast.Object)
// If x is an identifier, resolve attempts to resolve x by looking up
// the object it denotes. If no object is found and collectUnresolved is
// set, x is marked as unresolved and collected in the list of unresolved
// identifiers.
func (r *resolver) resolve(ident *ast.Ident, collectUnresolved bool) {
if ident.Obj != nil {
panic(r.sprintf("%v: identifier %s already declared or resolved", ident.Pos(), ident.Name))
}
// '_' should never refer to existing declarations, because it has special
// handling in the spec.
if ident.Name == "_" {
return
}
for s := r.topScope; s != nil; s = s.Outer {
if obj := s.Lookup(ident.Name); obj != nil {
if debugResolve {
r.trace("resolved %v:%s to %v", ident.Pos(), ident.Name, obj)
}
assert(obj.Name != "", "obj with no name")
// Identifiers (for receiver type parameters) are written to the scope,
// but never set as the resolved object. See issue #50956.
if _, ok := obj.Decl.(*ast.Ident); !ok {
ident.Obj = obj
}
return
}
}
// all local scopes are known, so any unresolved identifier
// must be found either in the file scope, package scope
// (perhaps in another file), or universe scope --- collect
// them so that they can be resolved later
if collectUnresolved {
ident.Obj = unresolved
r.unresolved = append(r.unresolved, ident)
}
}
func (r *resolver) walkExprs(list []ast.Expr) {
for _, node := range list {
ast.Walk(r, node)
}
}
func (r *resolver) walkLHS(list []ast.Expr) {
for _, expr := range list {
expr := unparen(expr)
if _, ok := expr.(*ast.Ident); !ok && expr != nil {
ast.Walk(r, expr)
}
}
}
func (r *resolver) walkStmts(list []ast.Stmt) {
for _, stmt := range list {
ast.Walk(r, stmt)
}
}
func (r *resolver) Visit(node ast.Node) ast.Visitor {
if debugResolve && node != nil {
r.trace("node %T@%v", node, node.Pos())
}
switch n := node.(type) {
// Expressions.
case *ast.Ident:
r.resolve(n, true)
case *ast.FuncLit:
r.openScope(n.Pos())
defer r.closeScope()
r.walkFuncType(n.Type)
r.walkBody(n.Body)
case *ast.SelectorExpr:
ast.Walk(r, n.X)
// Note: don't try to resolve n.Sel, as we don't support qualified
// resolution.
case *ast.StructType:
r.openScope(n.Pos())
defer r.closeScope()
r.walkFieldList(n.Fields, ast.Var)
case *ast.FuncType:
r.openScope(n.Pos())
defer r.closeScope()
r.walkFuncType(n)
case *ast.CompositeLit:
if n.Type != nil {
ast.Walk(r, n.Type)
}
for _, e := range n.Elts {
if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
// See issue #45160: try to resolve composite lit keys, but don't
// collect them as unresolved if resolution failed. This replicates
// existing behavior when resolving during parsing.
if ident, _ := kv.Key.(*ast.Ident); ident != nil {
r.resolve(ident, false)
} else {
ast.Walk(r, kv.Key)
}
ast.Walk(r, kv.Value)
} else {
ast.Walk(r, e)
}
}
case *ast.InterfaceType:
r.openScope(n.Pos())
defer r.closeScope()
r.walkFieldList(n.Methods, ast.Fun)
// Statements
case *ast.LabeledStmt:
r.declare(n, nil, r.labelScope, ast.Lbl, n.Label)
ast.Walk(r, n.Stmt)
case *ast.AssignStmt:
r.walkExprs(n.Rhs)
if n.Tok == token.DEFINE {
r.shortVarDecl(n)
} else {
r.walkExprs(n.Lhs)
}
case *ast.BranchStmt:
// add to list of unresolved targets
if n.Tok != token.FALLTHROUGH && n.Label != nil {
depth := len(r.targetStack) - 1
r.targetStack[depth] = append(r.targetStack[depth], n.Label)
}
case *ast.BlockStmt:
r.openScope(n.Pos())
defer r.closeScope()
r.walkStmts(n.List)
case *ast.IfStmt:
r.openScope(n.Pos())
defer r.closeScope()
if n.Init != nil {
ast.Walk(r, n.Init)
}
ast.Walk(r, n.Cond)
ast.Walk(r, n.Body)
if n.Else != nil {
ast.Walk(r, n.Else)
}
case *ast.CaseClause:
r.walkExprs(n.List)
r.openScope(n.Pos())
defer r.closeScope()
r.walkStmts(n.Body)
case *ast.SwitchStmt:
r.openScope(n.Pos())
defer r.closeScope()
if n.Init != nil {
ast.Walk(r, n.Init)
}
if n.Tag != nil {
// The scope below reproduces some unnecessary behavior of the parser,
// opening an extra scope in case this is a type switch. It's not needed
// for expression switches.
// TODO: remove this once we've matched the parser resolution exactly.
if n.Init != nil {
r.openScope(n.Tag.Pos())
defer r.closeScope()
}
ast.Walk(r, n.Tag)
}
if n.Body != nil {
r.walkStmts(n.Body.List)
}
case *ast.TypeSwitchStmt:
if n.Init != nil {
r.openScope(n.Pos())
defer r.closeScope()
ast.Walk(r, n.Init)
}
r.openScope(n.Assign.Pos())
defer r.closeScope()
ast.Walk(r, n.Assign)
// s.Body consists only of case clauses, so does not get its own
// scope.
if n.Body != nil {
r.walkStmts(n.Body.List)
}
case *ast.CommClause:
r.openScope(n.Pos())
defer r.closeScope()
if n.Comm != nil {
ast.Walk(r, n.Comm)
}
r.walkStmts(n.Body)
case *ast.SelectStmt:
// as for switch statements, select statement bodies don't get their own
// scope.
if n.Body != nil {
r.walkStmts(n.Body.List)
}
case *ast.ForStmt:
r.openScope(n.Pos())
defer r.closeScope()
if n.Init != nil {
ast.Walk(r, n.Init)
}
if n.Cond != nil {
ast.Walk(r, n.Cond)
}
if n.Post != nil {
ast.Walk(r, n.Post)
}
ast.Walk(r, n.Body)
case *ast.RangeStmt:
r.openScope(n.Pos())
defer r.closeScope()
ast.Walk(r, n.X)
var lhs []ast.Expr
if n.Key != nil {
lhs = append(lhs, n.Key)
}
if n.Value != nil {
lhs = append(lhs, n.Value)
}
if len(lhs) > 0 {
if n.Tok == token.DEFINE {
// Note: we can't exactly match the behavior of object resolution
// during the parsing pass here, as it uses the position of the RANGE
// token for the RHS OpPos. That information is not contained within
// the AST.
as := &ast.AssignStmt{
Lhs: lhs,
Tok: token.DEFINE,
TokPos: n.TokPos,
Rhs: []ast.Expr{&ast.UnaryExpr{Op: token.RANGE, X: n.X}},
}
// TODO(rFindley): this walkLHS reproduced the parser resolution, but
// is it necessary? By comparison, for a normal AssignStmt we don't
// walk the LHS in case there is an invalid identifier list.
r.walkLHS(lhs)
r.shortVarDecl(as)
} else {
r.walkExprs(lhs)
}
}
ast.Walk(r, n.Body)
// Declarations
case *ast.GenDecl:
switch n.Tok {
case token.CONST, token.VAR:
for i, spec := range n.Specs {
spec := spec.(*ast.ValueSpec)
kind := ast.Con
if n.Tok == token.VAR {
kind = ast.Var
}
r.walkExprs(spec.Values)
if spec.Type != nil {
ast.Walk(r, spec.Type)
}
r.declare(spec, i, r.topScope, kind, spec.Names...)
}
case token.TYPE:
for _, spec := range n.Specs {
spec := spec.(*ast.TypeSpec)
// Go spec: The scope of a type identifier declared inside a function begins
// at the identifier in the TypeSpec and ends at the end of the innermost
// containing block.
r.declare(spec, nil, r.topScope, ast.Typ, spec.Name)
if spec.TypeParams != nil {
r.openScope(spec.Pos())
r.walkTParams(spec.TypeParams)
r.closeScope()
}
ast.Walk(r, spec.Type)
}
}
case *ast.FuncDecl:
// Open the function scope.
r.openScope(n.Pos())
defer r.closeScope()
r.walkRecv(n.Recv)
// Type parameters are walked normally: they can reference each other, and
// can be referenced by normal parameters.
if n.Type.TypeParams != nil {
r.walkTParams(n.Type.TypeParams)
// TODO(rFindley): need to address receiver type parameters.
}
// Resolve and declare parameters in a specific order to get duplicate
// declaration errors in the correct location.
r.resolveList(n.Type.Params)
r.resolveList(n.Type.Results)
r.declareList(n.Recv, ast.Var)
r.declareList(n.Type.Params, ast.Var)
r.declareList(n.Type.Results, ast.Var)
r.walkBody(n.Body)
if n.Recv == nil && n.Name.Name != "init" {
r.declare(n, nil, r.pkgScope, ast.Fun, n.Name)
}
default:
return r
}
return nil
}
func (r *resolver) walkFuncType(typ *ast.FuncType) {
// typ.TypeParams must be walked separately for FuncDecls.
r.resolveList(typ.Params)
r.resolveList(typ.Results)
r.declareList(typ.Params, ast.Var)
r.declareList(typ.Results, ast.Var)
}
func (r *resolver) resolveList(list *ast.FieldList) {
if list == nil {
return
}
for _, f := range list.List {
if f.Type != nil {
ast.Walk(r, f.Type)
}
}
}
func (r *resolver) declareList(list *ast.FieldList, kind ast.ObjKind) {
if list == nil {
return
}
for _, f := range list.List {
r.declare(f, nil, r.topScope, kind, f.Names...)
}
}
func (r *resolver) walkRecv(recv *ast.FieldList) {
// If our receiver has receiver type parameters, we must declare them before
// trying to resolve the rest of the receiver, and avoid re-resolving the
// type parameter identifiers.
if recv == nil || len(recv.List) == 0 {
return // nothing to do
}
typ := recv.List[0].Type
if ptr, ok := typ.(*ast.StarExpr); ok {
typ = ptr.X
}
var declareExprs []ast.Expr // exprs to declare
var resolveExprs []ast.Expr // exprs to resolve
switch typ := typ.(type) {
case *ast.IndexExpr:
declareExprs = []ast.Expr{typ.Index}
resolveExprs = append(resolveExprs, typ.X)
case *ast.IndexListExpr:
declareExprs = typ.Indices
resolveExprs = append(resolveExprs, typ.X)
default:
resolveExprs = append(resolveExprs, typ)
}
for _, expr := range declareExprs {
if id, _ := expr.(*ast.Ident); id != nil {
r.declare(expr, nil, r.topScope, ast.Typ, id)
} else {
// The receiver type parameter expression is invalid, but try to resolve
// it anyway for consistency.
resolveExprs = append(resolveExprs, expr)
}
}
for _, expr := range resolveExprs {
if expr != nil {
ast.Walk(r, expr)
}
}
// The receiver is invalid, but try to resolve it anyway for consistency.
for _, f := range recv.List[1:] {
if f.Type != nil {
ast.Walk(r, f.Type)
}
}
}
func (r *resolver) walkFieldList(list *ast.FieldList, kind ast.ObjKind) {
if list == nil {
return
}
r.resolveList(list)
r.declareList(list, kind)
}
// walkTParams is like walkFieldList, but declares type parameters eagerly so
// that they may be resolved in the constraint expressions held in the field
// Type.
func (r *resolver) walkTParams(list *ast.FieldList) {
r.declareList(list, ast.Typ)
r.resolveList(list)
}
func (r *resolver) walkBody(body *ast.BlockStmt) {
if body == nil {
return
}
r.openLabelScope()
defer r.closeLabelScope()
r.walkStmts(body.List)
}

View File

@@ -1,292 +0,0 @@
// Copyright 2010 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 textproto implements generic support for text-based request/response
// protocols in the style of HTTP, NNTP, and SMTP.
//
// The package provides:
//
// Error, which represents a numeric error response from
// a server.
//
// Pipeline, to manage pipelined requests and responses
// in a client.
//
// Reader, to read numeric response code lines,
// key: value headers, lines wrapped with leading spaces
// on continuation lines, and whole text blocks ending
// with a dot on a line by itself.
//
// Writer, to write dot-encoded text blocks.
//
// Conn, a convenient packaging of Reader, Writer, and Pipeline for use
// with a single network connection.
package textproto
import (
"bufio"
"errors"
"fmt"
"io"
"io/fs"
"strings"
"syscall"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/net"
"github.com/goplus/llgo/c/os"
)
// An Error represents a numeric error response from a server.
type Error struct {
Code int
Msg string
}
func (e *Error) Error() string {
return fmt.Sprintf("%03d %s", e.Code, e.Msg)
}
// A ProtocolError describes a protocol violation such
// as an invalid response or a hung-up connection.
type ProtocolError string
func (p ProtocolError) Error() string {
return string(p)
}
// A Conn represents a textual network protocol connection.
// It consists of a Reader and Writer to manage I/O
// and a Pipeline to sequence concurrent requests on the connection.
// These embedded types carry methods with them;
// see the documentation of those types for details.
type Conn struct {
Reader
Writer
Pipeline
conn io.ReadWriteCloser
}
// NewConn returns a new Conn using conn for I/O.
func NewConn(conn io.ReadWriteCloser) *Conn {
return &Conn{
Reader: Reader{R: bufio.NewReader(conn)},
Writer: Writer{W: bufio.NewWriter(conn)},
conn: conn,
}
}
// Close closes the connection.
func (c *Conn) Close() error {
return c.conn.Close()
}
// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, error) {
cconn, err := dialNetWork(network, addr)
if err != nil {
return nil, err
}
return NewConn(cconn), nil
}
type cConn struct {
socketFd c.Int
closed bool
}
func (conn *cConn) Read(p []byte) (n int, err error) {
if conn == nil || conn.closed {
return 0, fs.ErrClosed
}
if len(p) == 0 {
return 0, nil
}
for n < len(p) {
result := os.Read(conn.socketFd, unsafe.Pointer(&p[n:][0]), uintptr(len(p)-n))
if result < 0 {
if os.Errno() == c.Int(syscall.EINTR) {
continue
}
return n, errors.New("read error")
}
if result == 0 {
return n, io.EOF
}
n += result
}
return n, nil
}
func (conn *cConn) Write(p []byte) (n int, err error) {
if conn == nil || conn.closed {
return 0, fs.ErrClosed
}
for n < len(p) {
result := os.Write(conn.socketFd, unsafe.Pointer(&p[n:][0]), uintptr(len(p)-n))
if result < 0 {
if os.Errno() == c.Int(syscall.EINTR) {
continue
}
return n, errors.New("write error")
}
n += result
}
if n < len(p) {
return n, io.ErrShortWrite
}
return n, nil
}
func (conn *cConn) Close() error {
if conn == nil {
return nil
}
if conn.closed {
return fs.ErrClosed
}
conn.closed = true
result := os.Close(conn.socketFd)
if result < 0 {
return errors.New(c.GoString(c.Strerror(os.Errno())))
}
return nil
}
func dialNetWork(network, addr string) (*cConn, error) {
host, port, err := splitAddr(addr)
if err != nil {
return nil, err
}
var hints net.AddrInfo
var res *net.AddrInfo
c.Memset(unsafe.Pointer(&hints), 0, unsafe.Sizeof(hints))
hints.Family = net.AF_UNSPEC
hints.SockType = net.SOCK_STREAM
status := net.Getaddrinfo(c.AllocaCStr(host), c.AllocaCStr(port), &hints, &res)
if status != 0 {
return nil, errors.New("getaddrinfo error")
}
socketFd := net.Socket(res.Family, res.SockType, res.Protocol)
if socketFd == -1 {
net.Freeaddrinfo(res)
return nil, errors.New("socket error")
}
if net.Connect(socketFd, res.Addr, res.AddrLen) == -1 {
os.Close(socketFd)
net.Freeaddrinfo(res)
return nil, errors.New("connect error")
}
net.Freeaddrinfo(res)
return &cConn{
socketFd: socketFd,
}, nil
}
func splitAddr(addr string) (host, port string, err error) {
// Handle IPv6 addresses
if strings.HasPrefix(addr, "[") {
closeBracket := strings.LastIndex(addr, "]")
if closeBracket == -1 {
return "", "", errors.New("invalid IPv6 address: missing closing bracket")
}
host = addr[1:closeBracket]
if len(addr) > closeBracket+1 {
if addr[closeBracket+1] != ':' {
return "", "", errors.New("invalid address: colon missing after IPv6 address")
}
port = addr[closeBracket+2:]
}
} else {
// Handle IPv4 addresses or domain names
parts := strings.Split(addr, ":")
if len(parts) > 2 {
return "", "", errors.New("invalid address: too many colons")
}
host = parts[0]
if len(parts) == 2 {
port = parts[1]
}
}
if host == "" {
return "", "", errors.New("invalid address: host is empty")
}
if port == "" {
port = "80" // Default port is 80
}
return host, port, nil
}
// Cmd is a convenience method that sends a command after
// waiting its turn in the pipeline. The command text is the
// result of formatting format with args and appending \r\n.
// Cmd returns the id of the command, for use with StartResponse and EndResponse.
//
// For example, a client might run a HELP command that returns a dot-body
// by using:
//
// id, err := c.Cmd("HELP")
// if err != nil {
// return nil, err
// }
//
// c.StartResponse(id)
// defer c.EndResponse(id)
//
// if _, _, err = c.ReadCodeLine(110); err != nil {
// return nil, err
// }
// text, err := c.ReadDotBytes()
// if err != nil {
// return nil, err
// }
// return c.ReadCodeLine(250)
func (c *Conn) Cmd(format string, args ...any) (id uint, err error) {
id = c.Next()
c.StartRequest(id)
err = c.PrintfLine(format, args...)
c.EndRequest(id)
if err != nil {
return 0, err
}
return id, nil
}
// TrimString returns s without leading and trailing ASCII space.
func TrimString(s string) string {
for len(s) > 0 && isASCIISpace(s[0]) {
s = s[1:]
}
for len(s) > 0 && isASCIISpace(s[len(s)-1]) {
s = s[:len(s)-1]
}
return s
}
// TrimBytes returns b without leading and trailing ASCII space.
func TrimBytes(b []byte) []byte {
for len(b) > 0 && isASCIISpace(b[0]) {
b = b[1:]
}
for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
b = b[:len(b)-1]
}
return b
}
func isASCIISpace(b byte) bool {
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}
func isASCIILetter(b byte) bool {
b |= 0x20 // make lower case
return 'a' <= b && b <= 'z'
}

View File

@@ -1,884 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package build
import (
"bytes"
"debug/macho"
"fmt"
"go/ast"
"go/build"
"go/constant"
"go/token"
"go/types"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strings"
"unsafe"
"golang.org/x/tools/go/ssa"
"github.com/goplus/llgo/cl"
"github.com/goplus/llgo/internal/env"
"github.com/goplus/llgo/internal/packages"
"github.com/goplus/llgo/internal/typepatch"
"github.com/goplus/llgo/ssa/abi"
xenv "github.com/goplus/llgo/xtool/env"
"github.com/goplus/llgo/xtool/env/llvm"
llssa "github.com/goplus/llgo/ssa"
clangCheck "github.com/goplus/llgo/xtool/clang/check"
)
type Mode int
const (
ModeBuild Mode = iota
ModeInstall
ModeRun
ModeCmpTest
ModeGen
)
const (
debugBuild = packages.DebugPackagesLoad
)
func needLLFile(mode Mode) bool {
return mode != ModeBuild
}
type Config struct {
BinPath string
AppExt string // ".exe" on Windows, empty on Unix
OutFile string // only valid for ModeBuild when len(pkgs) == 1
RunArgs []string // only valid for ModeRun
Mode Mode
GenExpect bool // only valid for ModeCmpTest
}
func NewDefaultConf(mode Mode) *Config {
bin := os.Getenv("GOBIN")
if bin == "" {
gopath, err := envGOPATH()
if err != nil {
panic(fmt.Errorf("cannot get GOPATH: %v", err))
}
bin = filepath.Join(gopath, "bin")
}
if err := os.MkdirAll(bin, 0755); err != nil {
panic(fmt.Errorf("cannot create bin directory: %v", err))
}
conf := &Config{
BinPath: bin,
Mode: mode,
AppExt: DefaultAppExt(),
}
return conf
}
func envGOPATH() (string, error) {
if gopath := os.Getenv("GOPATH"); gopath != "" {
return gopath, nil
}
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, "go"), nil
}
func DefaultAppExt() string {
if runtime.GOOS == "windows" {
return ".exe"
}
return ""
}
// -----------------------------------------------------------------------------
const (
loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
loadImports = loadFiles | packages.NeedImports
loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
)
func Do(args []string, conf *Config) ([]Package, error) {
flags, patterns, verbose := ParseArgs(args, buildFlags)
flags = append(flags, "-tags", "llgo")
cfg := &packages.Config{
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
BuildFlags: flags,
Fset: token.NewFileSet(),
}
if len(overlayFiles) > 0 {
cfg.Overlay = make(map[string][]byte)
for file, src := range overlayFiles {
overlay := unsafe.Slice(unsafe.StringData(src), len(src))
cfg.Overlay[filepath.Join(runtime.GOROOT(), "src", file)] = overlay
}
}
cl.EnableDebugSymbols(IsDebugEnabled())
llssa.Initialize(llssa.InitAll)
target := &llssa.Target{
GOOS: build.Default.GOOS,
GOARCH: build.Default.GOARCH,
}
prog := llssa.NewProgram(target)
sizes := prog.TypeSizes
dedup := packages.NewDeduper()
dedup.SetPreload(func(pkg *types.Package, files []*ast.File) {
if canSkipToBuild(pkg.Path()) {
return
}
cl.ParsePkgSyntax(prog, pkg, files)
})
if patterns == nil {
patterns = []string{"."}
}
initial, err := packages.LoadEx(dedup, sizes, cfg, patterns...)
check(err)
mode := conf.Mode
if len(initial) == 1 && len(initial[0].CompiledGoFiles) > 0 {
if mode == ModeBuild {
mode = ModeInstall
}
} else if mode == ModeRun {
if len(initial) > 1 {
return nil, fmt.Errorf("cannot run multiple packages")
} else {
return nil, fmt.Errorf("no Go files in matched packages")
}
}
altPkgPaths := altPkgs(initial, llssa.PkgRuntime)
// Use LLGoROOT as default implementation if `github.com/goplus/llgo` is not
// imported in user's go.mod. This ensures compilation works without import
// while allowing `github.com/goplus/llgo` upgrades via go.mod.
//
// WARNING(lijie): This approach cannot guarantee compatibility between `llgo`
// executable and runtime. This is a known design limitation that needs to be
// addressed in future improvements. The runtime should be:
// 1. Released and fully tested with the `llgo` compiler across different Go
// compiler versions and user-specified go versions in go.mod
// 2. Not be dependent on `github.com/goplus/llgo/c` library. Current runtime directly
// depends on it, causing version conflicts: using LLGoROOT makes user's specified
// version ineffective, while not using it leaves runtime unable to follow compiler
// updates. Since `github.com/goplus/llgo/c/*` contains many application libraries
// that may change frequently, a possible solution is to have both depend on a
// stable and limited c core API.
if !llgoPkgImported(initial) {
cfg.Dir = env.LLGoROOT()
}
altPkgs, err := packages.LoadEx(dedup, sizes, cfg, altPkgPaths...)
check(err)
noRt := 1
prog.SetRuntime(func() *types.Package {
noRt = 0
return altPkgs[0].Types
})
prog.SetPython(func() *types.Package {
return dedup.Check(llssa.PkgPython).Types
})
buildMode := ssaBuildMode
if IsDebugEnabled() {
buildMode |= ssa.GlobalDebug
}
if !IsOptimizeEnabled() {
buildMode |= ssa.NaiveForm
}
progSSA := ssa.NewProgram(initial[0].Fset, buildMode)
patches := make(cl.Patches, len(altPkgPaths))
altSSAPkgs(progSSA, patches, altPkgs[1:], verbose)
env := llvm.New("")
os.Setenv("PATH", env.BinDir()+":"+os.Getenv("PATH")) // TODO(xsw): check windows
ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0}
pkgs := buildAllPkgs(ctx, initial, verbose)
if mode == ModeGen {
for _, pkg := range pkgs {
if pkg.Package == initial[0] {
return []*aPackage{pkg}, nil
}
}
return nil, fmt.Errorf("initial package not found")
}
dpkg := buildAllPkgs(ctx, altPkgs[noRt:], verbose)
var linkArgs []string
for _, pkg := range dpkg {
linkArgs = append(linkArgs, pkg.LinkArgs...)
}
if mode != ModeBuild {
nErr := 0
for _, pkg := range initial {
if pkg.Name == "main" {
nErr += linkMainPkg(ctx, pkg, pkgs, linkArgs, conf, mode, verbose)
}
}
if nErr > 0 {
os.Exit(nErr)
}
}
return dpkg, nil
}
func llgoPkgImported(pkgs []*packages.Package) bool {
for _, pkg := range pkgs {
for _, imp := range pkg.Imports {
if imp.Module != nil && imp.Module.Path == env.LLGoCompilerPkg {
return true
}
}
}
return false
}
func setNeedRuntimeOrPyInit(pkg *packages.Package, needRuntime, needPyInit bool) {
v := []byte{'0', '0'}
if needRuntime {
v[0] = '1'
}
if needPyInit {
v[1] = '1'
}
pkg.ID = string(v) // just use pkg.ID to mark it needs runtime
}
func isNeedRuntimeOrPyInit(pkg *packages.Package) (needRuntime, needPyInit bool) {
if len(pkg.ID) == 2 {
return pkg.ID[0] == '1', pkg.ID[1] == '1'
}
return
}
const (
ssaBuildMode = ssa.SanityCheckFunctions | ssa.InstantiateGenerics
)
type context struct {
env *llvm.Env
conf *packages.Config
progSSA *ssa.Program
prog llssa.Program
dedup packages.Deduper
patches cl.Patches
built map[string]none
initial []*packages.Package
mode Mode
nLibdir int
}
func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage) {
prog := ctx.prog
pkgs, errPkgs := allPkgs(ctx, initial, verbose)
for _, errPkg := range errPkgs {
for _, err := range errPkg.Errors {
fmt.Fprintln(os.Stderr, err)
}
fmt.Fprintln(os.Stderr, "cannot build SSA for package", errPkg)
}
if len(errPkgs) > 0 {
os.Exit(1)
}
built := ctx.built
for _, aPkg := range pkgs {
pkg := aPkg.Package
if _, ok := built[pkg.PkgPath]; ok {
pkg.ExportFile = ""
continue
}
built[pkg.PkgPath] = none{}
switch kind, param := cl.PkgKindOf(pkg.Types); kind {
case cl.PkgDeclOnly:
// skip packages that only contain declarations
// and set no export file
pkg.ExportFile = ""
case cl.PkgLinkIR, cl.PkgLinkExtern, cl.PkgPyModule:
if len(pkg.GoFiles) > 0 {
cgoLdflags, err := buildPkg(ctx, aPkg, verbose)
if err != nil {
panic(err)
}
linkParts := concatPkgLinkFiles(ctx, pkg, verbose)
allParts := append(linkParts, cgoLdflags...)
allParts = append(allParts, pkg.ExportFile)
aPkg.LinkArgs = allParts
} else {
// panic("todo")
// TODO(xsw): support packages out of llgo
pkg.ExportFile = ""
}
if kind == cl.PkgLinkExtern {
// need to be linked with external library
// format: ';' separated alternative link methods. e.g.
// link: $LLGO_LIB_PYTHON; $(pkg-config --libs python3-embed); -lpython3
altParts := strings.Split(param, ";")
expdArgs := make([]string, 0, len(altParts))
for _, param := range altParts {
param = strings.TrimSpace(param)
if strings.ContainsRune(param, '$') {
expdArgs = append(expdArgs, xenv.ExpandEnvToArgs(param)...)
ctx.nLibdir++
} else {
fields := strings.Fields(param)
expdArgs = append(expdArgs, fields...)
}
if len(expdArgs) > 0 {
break
}
}
if len(expdArgs) == 0 {
panic(fmt.Sprintf("'%s' cannot locate the external library", param))
}
pkgLinkArgs := make([]string, 0, 3)
if expdArgs[0][0] == '-' {
pkgLinkArgs = append(pkgLinkArgs, expdArgs...)
} else {
linkFile := expdArgs[0]
dir, lib := filepath.Split(linkFile)
pkgLinkArgs = append(pkgLinkArgs, "-l"+lib)
if dir != "" {
pkgLinkArgs = append(pkgLinkArgs, "-L"+dir)
ctx.nLibdir++
}
}
if err := clangCheck.CheckLinkArgs(pkgLinkArgs); err != nil {
panic(fmt.Sprintf("test link args '%s' failed\n\texpanded to: %v\n\tresolved to: %v\n\terror: %v", param, expdArgs, pkgLinkArgs, err))
}
aPkg.LinkArgs = append(aPkg.LinkArgs, pkgLinkArgs...)
}
default:
cgoLdflags, err := buildPkg(ctx, aPkg, verbose)
if err != nil {
panic(err)
}
aPkg.LinkArgs = append(cgoLdflags, pkg.ExportFile)
setNeedRuntimeOrPyInit(pkg, prog.NeedRuntime, prog.NeedPyInit)
}
}
return
}
func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, linkArgs []string, conf *Config, mode Mode, verbose bool) (nErr int) {
pkgPath := pkg.PkgPath
name := path.Base(pkgPath)
app := conf.OutFile
if app == "" {
app = filepath.Join(conf.BinPath, name+conf.AppExt)
}
args := make([]string, 0, len(pkg.Imports)+len(linkArgs)+16)
args = append(
args,
"-o", app,
"-fuse-ld=lld",
"-Wno-override-module",
// "-O2", // FIXME: This will cause TestFinalizer in _test/bdwgc.go to fail on macOS.
)
switch runtime.GOOS {
case "darwin": // ld64.lld (macOS)
args = append(
args,
"-rpath", "@loader_path",
"-rpath", "@loader_path/../lib",
"-Xlinker", "-dead_strip",
)
case "windows": // lld-link (Windows)
// TODO: Add options for Windows.
default: // ld.lld (Unix), wasm-ld (WebAssembly)
args = append(
args,
"-rpath", "$ORIGIN",
"-rpath", "$ORIGIN/../lib",
"-fdata-sections",
"-ffunction-sections",
"-Xlinker", "--gc-sections",
"-lm",
"-latomic",
"-lpthread", // libpthread is built-in since glibc 2.34 (2021-08-01); we need to support earlier versions.
)
}
needRuntime := false
needPyInit := false
pkgsMap := make(map[*packages.Package]*aPackage, len(pkgs))
for _, v := range pkgs {
pkgsMap[v.Package] = v
}
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
if p.ExportFile != "" { // skip packages that only contain declarations
aPkg := pkgsMap[p]
args = append(args, aPkg.LinkArgs...)
need1, need2 := isNeedRuntimeOrPyInit(p)
if !needRuntime {
needRuntime = need1
}
if !needPyInit {
needPyInit = need2
}
}
})
var aPkg *aPackage
for _, v := range pkgs {
if v.Package == pkg { // found this package
aPkg = v
break
}
}
dirty := false
if needRuntime {
args = append(args, linkArgs...)
} else {
dirty = true
fn := aPkg.LPkg.FuncOf(cl.RuntimeInit)
fn.MakeBody(1).Return()
}
if needPyInit {
dirty = aPkg.LPkg.PyInit()
}
if dirty && needLLFile(mode) {
lpkg := aPkg.LPkg
os.WriteFile(pkg.ExportFile, []byte(lpkg.String()), 0644)
}
if verbose || mode != ModeRun {
fmt.Fprintln(os.Stderr, "#", pkgPath)
}
defer func() {
if e := recover(); e != nil {
nErr = 1
}
}()
// add rpath and find libs
exargs := make([]string, 0, ctx.nLibdir<<1)
libs := make([]string, 0, ctx.nLibdir*3)
for _, arg := range args {
if strings.HasPrefix(arg, "-L") {
exargs = append(exargs, "-rpath", arg[2:])
} else if strings.HasPrefix(arg, "-l") {
libs = append(libs, arg[2:])
}
}
args = append(args, exargs...)
if IsDebugEnabled() {
args = append(args, "-gdwarf-4")
}
// TODO(xsw): show work
if verbose {
fmt.Fprintln(os.Stderr, "clang", args)
}
err := ctx.env.Clang().Exec(args...)
check(err)
if runtime.GOOS == "darwin" {
dylibDeps := make([]string, 0, len(libs))
for _, lib := range libs {
dylibDep := findDylibDep(app, lib)
if dylibDep != "" {
dylibDeps = append(dylibDeps, dylibDep)
}
}
err := ctx.env.InstallNameTool().ChangeToRpath(app, dylibDeps...)
check(err)
}
switch mode {
case ModeRun:
cmd := exec.Command(app, conf.RunArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
if s := cmd.ProcessState; s != nil {
os.Exit(s.ExitCode())
}
case ModeCmpTest:
cmpTest(filepath.Dir(pkg.GoFiles[0]), pkgPath, app, conf.GenExpect, conf.RunArgs)
}
return
}
func buildPkg(ctx *context, aPkg *aPackage, verbose bool) (cgoLdflags []string, err error) {
pkg := aPkg.Package
pkgPath := pkg.PkgPath
if debugBuild || verbose {
fmt.Fprintln(os.Stderr, pkgPath)
}
if canSkipToBuild(pkgPath) {
pkg.ExportFile = ""
return
}
var syntax = pkg.Syntax
if altPkg := aPkg.AltPkg; altPkg != nil {
syntax = append(syntax, altPkg.Syntax...)
}
showDetail := verbose && pkgExists(ctx.initial, pkg)
if showDetail {
llssa.SetDebug(llssa.DbgFlagAll)
cl.SetDebug(cl.DbgFlagAll)
}
ret, externs, err := cl.NewPackageEx(ctx.prog, ctx.patches, aPkg.SSA, syntax)
if showDetail {
llssa.SetDebug(0)
cl.SetDebug(0)
}
check(err)
aPkg.LPkg = ret
cgoLdflags, err = buildCgo(ctx, aPkg, aPkg.Package.Syntax, externs, verbose)
if needLLFile(ctx.mode) {
pkg.ExportFile += ".ll"
os.WriteFile(pkg.ExportFile, []byte(ret.String()), 0644)
if debugBuild || verbose {
fmt.Fprintf(os.Stderr, "==> Export %s: %s\n", aPkg.PkgPath, pkg.ExportFile)
}
if IsCheckEnable() {
if err, msg := llcCheck(ctx.env, pkg.ExportFile); err != nil {
fmt.Fprintf(os.Stderr, "==> lcc %v: %v\n%v\n", pkg.PkgPath, pkg.ExportFile, msg)
}
}
}
return
}
func llcCheck(env *llvm.Env, exportFile string) (err error, msg string) {
bin := filepath.Join(env.BinDir(), "llc")
cmd := exec.Command(bin, "-filetype=null", exportFile)
var buf bytes.Buffer
cmd.Stderr = &buf
if err = cmd.Run(); err != nil {
msg = buf.String()
}
return
}
const (
altPkgPathPrefix = abi.PatchPathPrefix
)
func altPkgs(initial []*packages.Package, alts ...string) []string {
packages.Visit(initial, nil, func(p *packages.Package) {
if p.Types != nil && !p.IllTyped {
if _, ok := hasAltPkg[p.PkgPath]; ok {
alts = append(alts, altPkgPathPrefix+p.PkgPath)
}
}
})
return alts
}
func altSSAPkgs(prog *ssa.Program, patches cl.Patches, alts []*packages.Package, verbose bool) {
packages.Visit(alts, nil, func(p *packages.Package) {
if typs := p.Types; typs != nil && !p.IllTyped {
if debugBuild || verbose {
log.Println("==> BuildSSA", p.PkgPath)
}
pkgSSA := prog.CreatePackage(typs, p.Syntax, p.TypesInfo, true)
if strings.HasPrefix(p.PkgPath, altPkgPathPrefix) {
path := p.PkgPath[len(altPkgPathPrefix):]
patches[path] = cl.Patch{Alt: pkgSSA, Types: typepatch.Clone(typs)}
if debugBuild || verbose {
log.Println("==> Patching", path)
}
}
}
})
prog.Build()
}
type aPackage struct {
*packages.Package
SSA *ssa.Package
AltPkg *packages.Cached
LPkg llssa.Package
LinkArgs []string
}
type Package = *aPackage
func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) {
prog := ctx.progSSA
built := ctx.built
packages.Visit(initial, nil, func(p *packages.Package) {
if p.Types != nil && !p.IllTyped {
pkgPath := p.PkgPath
if _, ok := built[pkgPath]; ok || strings.HasPrefix(pkgPath, altPkgPathPrefix) {
return
}
var altPkg *packages.Cached
var ssaPkg = createSSAPkg(prog, p, verbose)
if _, ok := hasAltPkg[pkgPath]; ok {
if altPkg = ctx.dedup.Check(altPkgPathPrefix + pkgPath); altPkg == nil {
return
}
}
all = append(all, &aPackage{p, ssaPkg, altPkg, nil, nil})
} else {
errs = append(errs, p)
}
})
return
}
func createSSAPkg(prog *ssa.Program, p *packages.Package, verbose bool) *ssa.Package {
pkgSSA := prog.ImportedPackage(p.PkgPath)
if pkgSSA == nil {
if debugBuild || verbose {
log.Println("==> BuildSSA", p.PkgPath)
}
pkgSSA = prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true)
pkgSSA.Build() // TODO(xsw): build concurrently
}
return pkgSSA
}
var (
// TODO(xsw): complete build flags
buildFlags = map[string]bool{
"-C": true, // -C dir: Change to dir before running the command
"-a": false, // -a: force rebuilding of packages that are already up-to-date
"-n": false, // -n: print the commands but do not run them
"-p": true, // -p n: the number of programs to run in parallel
"-race": false, // -race: enable data race detection
"-cover": false, // -cover: enable coverage analysis
"-covermode": true, // -covermode mode: set the mode for coverage analysis
"-v": false, // -v: print the names of packages as they are compiled
"-work": false, // -work: print the name of the temporary work directory and do not delete it when exiting
"-x": false, // -x: print the commands
"-tags": true, // -tags 'tag,list': a space-separated list of build tags to consider satisfied during the build
"-pkgdir": true, // -pkgdir dir: install and load all packages from dir instead of the usual locations
"-ldflags": true, // --ldflags 'flag list': arguments to pass on each go tool link invocation
}
)
const llgoDebug = "LLGO_DEBUG"
const llgoOptimize = "LLGO_OPTIMIZE"
const llgoCheck = "LLGO_CHECK"
func isEnvOn(env string, defVal bool) bool {
envVal := strings.ToLower(os.Getenv(env))
if envVal == "" {
return defVal
}
return envVal == "1" || envVal == "true" || envVal == "on"
}
func IsDebugEnabled() bool {
return isEnvOn(llgoDebug, false)
}
func IsOptimizeEnabled() bool {
return isEnvOn(llgoOptimize, true)
}
func IsCheckEnable() bool {
return isEnvOn(llgoCheck, false)
}
func ParseArgs(args []string, swflags map[string]bool) (flags, patterns []string, verbose bool) {
n := len(args)
for i := 0; i < n; i++ {
arg := args[i]
if strings.HasPrefix(arg, "-") {
checkFlag(arg, &i, &verbose, swflags)
} else {
patterns = append([]string{}, args[i:]...)
flags = append([]string{}, args[:i]...)
return
}
}
return
}
func SkipFlagArgs(args []string) int {
n := len(args)
for i := 0; i < n; i++ {
arg := args[i]
if strings.HasPrefix(arg, "-") {
checkFlag(arg, &i, nil, buildFlags)
} else {
return i
}
}
return -1
}
func checkFlag(arg string, i *int, verbose *bool, swflags map[string]bool) {
if pos := strings.IndexByte(arg, '='); pos > 0 {
if verbose != nil && arg == "-v=true" {
*verbose = true
}
} else if hasarg, ok := swflags[arg]; ok {
if hasarg {
*i++
} else if verbose != nil && arg == "-v" {
*verbose = true
}
} else {
panic("unknown flag: " + arg)
}
}
func concatPkgLinkFiles(ctx *context, pkg *packages.Package, verbose bool) (parts []string) {
llgoPkgLinkFiles(ctx, pkg, func(linkFile string) {
parts = append(parts, linkFile)
}, verbose)
return
}
// const LLGoFiles = "file1; file2; ..."
func llgoPkgLinkFiles(ctx *context, pkg *packages.Package, procFile func(linkFile string), verbose bool) {
if o := pkg.Types.Scope().Lookup("LLGoFiles"); o != nil {
val := o.(*types.Const).Val()
if val.Kind() == constant.String {
clFiles(ctx, constant.StringVal(val), pkg, procFile, verbose)
}
}
}
// files = "file1; file2; ..."
// files = "$(pkg-config --cflags xxx): file1; file2; ..."
func clFiles(ctx *context, files string, pkg *packages.Package, procFile func(linkFile string), verbose bool) {
dir := filepath.Dir(pkg.GoFiles[0])
expFile := pkg.ExportFile
args := make([]string, 0, 16)
if strings.HasPrefix(files, "$") { // has cflags
if pos := strings.IndexByte(files, ':'); pos > 0 {
cflags := xenv.ExpandEnvToArgs(files[:pos])
files = files[pos+1:]
args = append(args, cflags...)
}
}
for _, file := range strings.Split(files, ";") {
cFile := filepath.Join(dir, strings.TrimSpace(file))
clFile(ctx, args, cFile, expFile, procFile, verbose)
}
}
func clFile(ctx *context, args []string, cFile, expFile string, procFile func(linkFile string), verbose bool) {
llFile := expFile + filepath.Base(cFile) + ".ll"
args = append(args, "-emit-llvm", "-S", "-o", llFile, "-c", cFile)
if verbose {
fmt.Fprintln(os.Stderr, "clang", args)
}
err := ctx.env.Clang().Exec(args...)
check(err)
procFile(llFile)
}
func pkgExists(initial []*packages.Package, pkg *packages.Package) bool {
for _, v := range initial {
if v == pkg {
return true
}
}
return false
}
func canSkipToBuild(pkgPath string) bool {
if _, ok := hasAltPkg[pkgPath]; ok {
return false
}
switch pkgPath {
case "unsafe":
return true
default:
return strings.HasPrefix(pkgPath, "internal/") ||
strings.HasPrefix(pkgPath, "runtime/internal/")
}
}
// findDylibDep finds the dylib dependency in the executable. It returns empty
// string if not found.
func findDylibDep(exe, lib string) string {
file, err := macho.Open(exe)
check(err)
defer file.Close()
for _, load := range file.Loads {
if dylib, ok := load.(*macho.Dylib); ok {
if strings.HasPrefix(filepath.Base(dylib.Name), fmt.Sprintf("lib%s.", lib)) {
return dylib.Name
}
}
}
return ""
}
type none struct{}
var hasAltPkg = map[string]none{
"crypto/hmac": {},
"crypto/md5": {},
"crypto/rand": {},
"crypto/sha1": {},
"crypto/sha256": {},
"crypto/sha512": {},
"crypto/subtle": {},
"fmt": {},
"hash/crc32": {},
"internal/abi": {},
"internal/bytealg": {},
"internal/itoa": {},
"internal/filepathlite": {},
"internal/oserror": {},
"internal/race": {},
"internal/reflectlite": {},
"internal/stringslite": {},
"internal/syscall/execenv": {},
"internal/syscall/unix": {},
"math": {},
"math/big": {},
"math/cmplx": {},
"math/rand": {},
"reflect": {},
"sync": {},
"sync/atomic": {},
"syscall": {},
"time": {},
"os": {},
"os/exec": {},
"runtime": {},
"io": {},
}
func check(err error) {
if err != nil {
panic(err)
}
}
// -----------------------------------------------------------------------------

View File

@@ -1,400 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package build
import (
"encoding/json"
"fmt"
"go/ast"
"go/token"
"go/types"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/goplus/llgo/internal/buildtags"
"github.com/goplus/llgo/internal/safesplit"
llssa "github.com/goplus/llgo/ssa"
)
type cgoDecl struct {
tag string
cflags []string
ldflags []string
}
type cgoPreamble struct {
goFile string
src string
}
const (
cgoHeader = `
#include <stdlib.h>
static void* _Cmalloc(size_t size) {
return malloc(size);
}
`
)
func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs []string, verbose bool) (cgoLdflags []string, err error) {
cfiles, preambles, cdecls, err := parseCgo_(pkg, files)
if err != nil {
return
}
tagUsed := make(map[string]bool)
for _, cdecl := range cdecls {
if cdecl.tag != "" {
tagUsed[cdecl.tag] = false
}
}
buildtags.CheckTags(ctx.conf.BuildFlags, tagUsed)
cflags := []string{}
ldflags := []string{}
for _, cdecl := range cdecls {
if cdecl.tag == "" || tagUsed[cdecl.tag] {
if len(cdecl.cflags) > 0 {
cflags = append(cflags, cdecl.cflags...)
}
if len(cdecl.ldflags) > 0 {
ldflags = append(ldflags, cdecl.ldflags...)
}
}
}
incDirs := make(map[string]none)
for _, preamble := range preambles {
dir, _ := filepath.Split(preamble.goFile)
if _, ok := incDirs[dir]; !ok {
incDirs[dir] = none{}
cflags = append(cflags, "-I"+dir)
}
}
for _, cfile := range cfiles {
clFile(ctx, cflags, cfile, pkg.ExportFile, func(linkFile string) {
cgoLdflags = append(cgoLdflags, linkFile)
}, verbose)
}
re := regexp.MustCompile(`^(_cgo_[^_]+_(Cfunc|Cmacro)_)(.*)$`)
cgoSymbols := make(map[string]string)
mallocFix := false
for _, symbolName := range externs {
lastPart := symbolName
lastDot := strings.LastIndex(symbolName, ".")
if lastDot != -1 {
lastPart = symbolName[lastDot+1:]
}
if strings.HasPrefix(lastPart, "__cgo_") {
// func ptr var: main.__cgo_func_name
cgoSymbols[symbolName] = lastPart
} else if m := re.FindStringSubmatch(symbolName); len(m) > 0 {
prefix := m[1] // _cgo_hash_(Cfunc|Cmacro)_
name := m[3] // remaining part
cgoSymbols[symbolName] = name
// fix missing _cgo_9113e32b6599_Cfunc__Cmalloc
if !mallocFix && m[2] == "Cfunc" {
mallocName := prefix + "_Cmalloc"
cgoSymbols[mallocName] = "_Cmalloc"
mallocFix = true
}
}
}
for _, preamble := range preambles {
tmpFile, err := os.CreateTemp("", "-cgo-*.c")
if err != nil {
return nil, fmt.Errorf("failed to create temp file: %v", err)
}
tmpName := tmpFile.Name()
defer os.Remove(tmpName)
code := cgoHeader + "\n\n" + preamble.src
externDecls, err := genExternDeclsByClang(pkg, code, cflags, cgoSymbols)
if err != nil {
return nil, err
}
if err = os.WriteFile(tmpName, []byte(code+"\n\n"+externDecls), 0644); err != nil {
return nil, err
}
clFile(ctx, cflags, tmpName, pkg.ExportFile, func(linkFile string) {
cgoLdflags = append(cgoLdflags, linkFile)
}, verbose)
}
for _, ldflag := range ldflags {
cgoLdflags = append(cgoLdflags, safesplit.SplitPkgConfigFlags(ldflag)...)
}
return
}
// clangASTNode represents a node in clang's AST
type clangASTNode struct {
Kind string `json:"kind"`
Name string `json:"name,omitempty"`
Inner []clangASTNode `json:"inner,omitempty"`
}
func genExternDeclsByClang(pkg *aPackage, src string, cflags []string, cgoSymbols map[string]string) (string, error) {
tmpSrc, err := os.CreateTemp("", "cgo-src-*.c")
if err != nil {
return "", err
}
defer os.Remove(tmpSrc.Name())
if err := os.WriteFile(tmpSrc.Name(), []byte(src), 0644); err != nil {
return "", err
}
symbolNames := make(map[string]bool)
if err := getFuncNames(tmpSrc.Name(), cflags, symbolNames); err != nil {
return "", err
}
macroNames := make(map[string]bool)
if err := getMacroNames(tmpSrc.Name(), cflags, macroNames); err != nil {
return "", err
}
b := strings.Builder{}
var toRemove []string
for cgoName, symbolName := range cgoSymbols {
if strings.HasPrefix(symbolName, "__cgo_") {
gofuncName := strings.Replace(cgoName, ".__cgo_", ".", 1)
gofn := pkg.LPkg.FuncOf(gofuncName)
cgoVar := pkg.LPkg.VarOf(cgoName)
if gofn != nil {
cgoVar.ReplaceAllUsesWith(gofn.Expr)
} else {
cfuncName := symbolName[len("__cgo_"):]
cfn := pkg.LPkg.NewFunc(cfuncName, types.NewSignatureType(nil, nil, nil, nil, nil, false), llssa.InC)
cgoVar.ReplaceAllUsesWith(cfn.Expr)
}
toRemove = append(toRemove, cgoName)
} else {
usePtr := ""
if symbolNames[symbolName] {
usePtr = "*"
} else if !macroNames[symbolName] {
continue
}
/* template:
typeof(fputs)* _cgo_1574167f3838_Cfunc_fputs;
__attribute__((constructor))
static void _init__cgo_1574167f3838_Cfunc_fputs() {
_cgo_1574167f3838_Cfunc_fputs = fputs;
}*/
b.WriteString(fmt.Sprintf(`
typeof(%s)%s %s;
__attribute__((constructor))
static void _init_%s() {
%s = %s;
}
`,
symbolName, usePtr, cgoName,
cgoName,
cgoName, symbolName))
toRemove = append(toRemove, cgoName)
}
}
for _, funcName := range toRemove {
delete(cgoSymbols, funcName)
}
return b.String(), nil
}
func getMacroNames(file string, cflags []string, macroNames map[string]bool) error {
args := append([]string{"-dM", "-E"}, cflags...)
args = append(args, file)
cmd := exec.Command("clang", args...)
output, err := cmd.Output()
if err != nil {
return err
}
for _, line := range strings.Split(string(output), "\n") {
if strings.HasPrefix(line, "#define ") {
define := strings.TrimPrefix(line, "#define ")
parts := strings.SplitN(define, " ", 2)
if len(parts) > 1 {
macroNames[parts[0]] = true
}
}
}
return nil
}
func getFuncNames(file string, cflags []string, symbolNames map[string]bool) error {
args := append([]string{"-Xclang", "-ast-dump=json", "-fsyntax-only"}, cflags...)
args = append(args, file)
cmd := exec.Command("clang", args...)
output, err := cmd.Output()
if err != nil {
return err
}
var astRoot clangASTNode
if err := json.Unmarshal(output, &astRoot); err != nil {
return err
}
extractFuncNames(&astRoot, symbolNames)
return nil
}
func extractFuncNames(node *clangASTNode, funcNames map[string]bool) {
for _, inner := range node.Inner {
if inner.Kind == "FunctionDecl" && inner.Name != "" {
funcNames[inner.Name] = true
}
}
}
func parseCgo_(pkg *aPackage, files []*ast.File) (cfiles []string, preambles []cgoPreamble, cdecls []cgoDecl, err error) {
dirs := make(map[string]none)
for _, file := range files {
pos := pkg.Fset.Position(file.Name.NamePos)
dir, _ := filepath.Split(pos.Filename)
dirs[dir] = none{}
}
for dir := range dirs {
matches, err := filepath.Glob(filepath.Join(dir, "*.c"))
if err != nil {
continue
}
for _, match := range matches {
if strings.HasSuffix(match, "_test.c") {
continue
}
if fi, err := os.Stat(match); err == nil && !fi.IsDir() {
cfiles = append(cfiles, match)
}
}
}
for _, file := range files {
for _, decl := range file.Decls {
switch decl := decl.(type) {
case *ast.GenDecl:
if decl.Tok == token.IMPORT {
if doc := decl.Doc; doc != nil && len(decl.Specs) == 1 {
spec := decl.Specs[0].(*ast.ImportSpec)
if spec.Path.Value == "\"unsafe\"" {
pos := pkg.Fset.Position(doc.Pos())
preamble, flags, err := parseCgoPreamble(pos, doc.Text())
if err != nil {
panic(err)
}
preambles = append(preambles, preamble)
cdecls = append(cdecls, flags...)
}
}
}
}
}
}
return
}
func parseCgoPreamble(pos token.Position, text string) (preamble cgoPreamble, decls []cgoDecl, err error) {
b := strings.Builder{}
fline := pos.Line
fname := pos.Filename
b.WriteString(fmt.Sprintf("#line %d %q\n", fline, fname))
for _, line := range strings.Split(text, "\n") {
fline++
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "#cgo ") {
var cgoDecls []cgoDecl
cgoDecls, err = parseCgoDecl(line)
if err != nil {
return
}
decls = append(decls, cgoDecls...)
b.WriteString(fmt.Sprintf("#line %d %q\n", fline, fname))
} else {
b.WriteString(line)
b.WriteString("\n")
}
}
preamble = cgoPreamble{
goFile: pos.Filename,
src: b.String(),
}
return
}
// Parse cgo directive like:
// #cgo pkg-config: python3
// #cgo windows CFLAGS: -IC:/Python312/include
// #cgo windows LDFLAGS: -LC:/Python312/libs -lpython312
// #cgo CFLAGS: -I/usr/include/python3.12
// #cgo LDFLAGS: -L/usr/lib/python3.12/config-3.12-x86_64-linux-gnu -lpython3.12
func parseCgoDecl(line string) (cgoDecls []cgoDecl, err error) {
idx := strings.Index(line, ":")
if idx == -1 {
err = fmt.Errorf("invalid cgo format: %v", line)
return
}
decl := strings.TrimSpace(line[:idx])
arg := strings.TrimSpace(line[idx+1:])
// Split on first space to remove #cgo
parts := strings.SplitN(decl, " ", 2)
if len(parts) < 2 {
err = fmt.Errorf("invalid cgo directive: %v", line)
return
}
// Process remaining part
remaining := strings.TrimSpace(parts[1])
var tag, flag string
// Split on last space to get flag
if lastSpace := strings.LastIndex(remaining, " "); lastSpace != -1 {
tag = strings.TrimSpace(remaining[:lastSpace])
flag = strings.TrimSpace(remaining[lastSpace+1:])
} else {
flag = remaining
}
switch flag {
case "pkg-config":
ldflags, e := exec.Command("pkg-config", "--libs", arg).Output()
if e != nil {
err = fmt.Errorf("pkg-config: %v", e)
return
}
cflags, e := exec.Command("pkg-config", "--cflags", arg).Output()
if e != nil {
err = fmt.Errorf("pkg-config: %v", e)
return
}
cgoDecls = append(cgoDecls, cgoDecl{
tag: tag,
cflags: safesplit.SplitPkgConfigFlags(string(cflags)),
ldflags: safesplit.SplitPkgConfigFlags(string(ldflags)),
})
case "CFLAGS":
cgoDecls = append(cgoDecls, cgoDecl{
tag: tag,
cflags: safesplit.SplitPkgConfigFlags(arg),
})
case "LDFLAGS":
cgoDecls = append(cgoDecls, cgoDecl{
tag: tag,
ldflags: safesplit.SplitPkgConfigFlags(arg),
})
}
return
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package build
import (
"fmt"
"os"
"path"
"path/filepath"
"github.com/goplus/llgo/internal/packages"
)
var (
// TODO(xsw): complete clean flags
cleanFlags = map[string]bool{
"-v": false, // -v: print the paths of packages as they are clean
}
)
func Clean(args []string, conf *Config) {
flags, patterns, verbose := ParseArgs(args, cleanFlags)
cfg := &packages.Config{
Mode: loadSyntax | packages.NeedExportFile,
BuildFlags: flags,
}
if patterns == nil {
patterns = []string{"."}
}
initial, err := packages.LoadEx(nil, nil, cfg, patterns...)
check(err)
cleanPkgs(initial, verbose)
for _, pkg := range initial {
if pkg.Name == "main" {
cleanMainPkg(pkg, conf, verbose)
}
}
}
func cleanMainPkg(pkg *packages.Package, conf *Config, verbose bool) {
pkgPath := pkg.PkgPath
name := path.Base(pkgPath)
fname := name + conf.AppExt
app := filepath.Join(conf.BinPath, fname)
removeFile(app, verbose)
if len(pkg.CompiledGoFiles) > 0 {
dir := filepath.Dir(pkg.CompiledGoFiles[0])
buildApp := filepath.Join(dir, fname)
removeFile(buildApp, verbose)
}
}
func cleanPkgs(initial []*packages.Package, verbose bool) {
packages.Visit(initial, nil, func(p *packages.Package) {
file := p.ExportFile + ".ll"
removeFile(file, verbose)
})
}
func removeFile(file string, verbose bool) {
if _, err := os.Stat(file); os.IsNotExist(err) {
return
}
if verbose {
fmt.Fprintln(os.Stderr, "Remove", file)
}
os.Remove(file)
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package build
import (
"bytes"
"errors"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
)
func cmpTest(dir, pkgPath, llApp string, genExpect bool, runArgs []string) {
var llgoOut, llgoErr bytes.Buffer
var llgoRunErr = runApp(runArgs, dir, &llgoOut, &llgoErr, llApp)
llgoExpect := formatExpect(llgoOut.Bytes(), llgoErr.Bytes(), llgoRunErr)
llgoExpectFile := filepath.Join(dir, "llgo.expect")
if genExpect {
if _, err := os.Stat(llgoExpectFile); !errors.Is(err, os.ErrNotExist) {
fatal(fmt.Errorf("llgo.expect file already exists: %s", llgoExpectFile))
}
if err := os.WriteFile(llgoExpectFile, llgoExpect, 0644); err != nil {
fatal(err)
}
return
}
if b, err := os.ReadFile(llgoExpectFile); err == nil {
checkEqual("llgo.expect", llgoExpect, b)
return
} else if !errors.Is(err, os.ErrNotExist) {
fatal(err)
}
var goOut, goErr bytes.Buffer
var goRunErr = runApp(runArgs, dir, &goOut, &goErr, "go", "run", pkgPath)
checkEqual("output", llgoOut.Bytes(), goOut.Bytes())
checkEqual("stderr", llgoErr.Bytes(), goErr.Bytes())
checkEqualRunErr(llgoRunErr, goRunErr)
}
func formatExpect(stdout, stderr []byte, runErr error) []byte {
var exitCode int
if runErr != nil {
if ee, ok := runErr.(*exec.ExitError); ok {
exitCode = ee.ExitCode()
} else { // This should never happen, but just in case.
exitCode = 255
}
}
return []byte(fmt.Sprintf("#stdout\n%s\n#stderr\n%s\n#exit %d\n", stdout, stderr, exitCode))
}
func checkEqualRunErr(llgoRunErr, goRunErr error) {
if llgoRunErr == goRunErr {
return
}
fmt.Fprintln(os.Stderr, "=> Exit:", llgoRunErr)
fmt.Fprintln(os.Stderr, "\n=> Expected Exit:", goRunErr)
}
func checkEqual(prompt string, a, expected []byte) {
if bytes.Equal(a, expected) {
return
}
fmt.Fprintln(os.Stderr, "=> Result of", prompt)
os.Stderr.Write(a)
fmt.Fprintln(os.Stderr, "\n=> Expected", prompt)
os.Stderr.Write(expected)
fatal(errors.New("checkEqual: unexpected " + prompt))
}
func runApp(runArgs []string, dir string, stdout, stderr io.Writer, app string, args ...string) error {
if len(runArgs) > 0 {
if len(args) > 0 {
args = append(args, runArgs...)
} else {
args = runArgs
}
}
cmd := exec.Command(app, args...)
cmd.Dir = dir
cmd.Stdout = stdout
cmd.Stderr = stderr
return cmd.Run()
}
func fatal(err error) {
log.Panicln(err)
}

View File

@@ -1,17 +0,0 @@
package build
import (
_ "embed"
)
//go:embed _overlay/go/parser/resolver.go
var go_parser_resolver string
//go:embed _overlay/net/textproto/textproto.go
var net_textproto string
var overlayFiles = map[string]string{
"math/exp_amd64.go": "package math;",
"go/parser/resolver.go": go_parser_resolver,
"net/textproto/textproto.go": net_textproto,
}

View File

@@ -1,114 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package buildtags
import (
"fmt"
"go/build"
"io"
"io/fs"
"strings"
)
// checkTags checks which build tags are valid by creating virtual test files
// and using build.Context.MatchFile to verify them
func CheckTags(buildFlags []string, testTags map[string]bool) {
buildCtx := build.Default
buildCtx.BuildTags = parseBuildTags(buildFlags)
// Create virtual filesystem
vfs := &virtualFS{
files: make(map[string]virtualFile),
}
// Generate virtual files for each test tag
i := 0
fileToTag := make(map[string]string) // Map to track which file corresponds to which tag
for tag := range testTags {
fileName := fmt.Sprintf("a%02d.go", i)
content := fmt.Sprintf("// +build %s\n\npackage check\n", tag)
vfs.files[fileName] = virtualFile{
name: fileName,
content: content,
dir: ".",
}
fileToTag[fileName] = tag
i++
}
// Override OpenFile to return our virtual file contents
buildCtx.OpenFile = func(name string) (io.ReadCloser, error) {
if file, ok := vfs.files[name]; ok {
return io.NopCloser(strings.NewReader(file.content)), nil
}
return nil, fs.ErrNotExist
}
// Check each file against build context
for fileName, tag := range fileToTag {
match, err := buildCtx.MatchFile(".", fileName)
if err == nil && match {
testTags[tag] = true
}
}
}
// virtualFile represents a virtual build tag check file
type virtualFile struct {
name string
content string
dir string
}
// virtualFS implements a virtual filesystem for build tag checking
type virtualFS struct {
files map[string]virtualFile
}
func parseBuildTags(buildFlags []string) []string {
buildTags := make([]string, 0)
// Extract tags from buildFlags
for i := 0; i < len(buildFlags); i++ {
flag := buildFlags[i]
if flag == "-tags" && i+1 < len(buildFlags) {
// Handle "-tags xxx" format
tags := strings.FieldsFunc(buildFlags[i+1], func(r rune) bool {
return r == ',' || r == ' '
})
buildTags = append(buildTags, tags...)
i++ // Skip the next item since we've processed it
} else if strings.HasPrefix(flag, "-tags=") {
// Handle "-tags=xxx" format
value := strings.TrimPrefix(flag, "-tags=")
tags := strings.FieldsFunc(value, func(r rune) bool {
return r == ',' || r == ' '
})
buildTags = append(buildTags, tags...)
}
}
// Remove duplicates from tags
seen := make(map[string]bool)
uniqueBuildTags := make([]string, 0, len(buildTags))
for _, tag := range buildTags {
if !seen[tag] {
seen[tag] = true
uniqueBuildTags = append(uniqueBuildTags, tag)
}
}
return uniqueBuildTags
}

View File

@@ -1,153 +0,0 @@
package buildtags
import (
"reflect"
"runtime"
"testing"
)
func TestCheckTags(t *testing.T) {
tests := []struct {
name string
buildFlags []string
testTags map[string]bool
want map[string]bool
}{
{
name: "mywindows tags",
buildFlags: []string{"-tags", "mywindows"},
testTags: map[string]bool{
"mywindows": false,
"!mywindows": false,
"mywindows,myamd64": false,
},
want: map[string]bool{
"mywindows": true,
"!mywindows": false,
"mywindows,myamd64": runtime.GOARCH == "myamd64",
},
},
{
name: "non-mywindows tags",
buildFlags: []string{"-tags", "mylinux"},
testTags: map[string]bool{
"mywindows": false,
"!mywindows": false,
"mylinux,myamd64": false,
"!mywindows,myamd64": false,
},
want: map[string]bool{
"mywindows": false,
"!mywindows": true,
"mylinux,myamd64": runtime.GOARCH == "myamd64",
"!mywindows,myamd64": runtime.GOARCH == "myamd64",
},
},
{
name: "multiple tags",
buildFlags: []string{"-tags", "mywindows,myamd64"},
testTags: map[string]bool{
"mywindows": false,
"myamd64": false,
"mywindows,myamd64": false,
"mylinux,myamd64": false,
},
want: map[string]bool{
"mywindows": true,
"myamd64": true,
"mywindows,myamd64": true,
"mylinux,myamd64": false,
},
},
{
name: "tags with equals format",
buildFlags: []string{"-tags=mywindows,myamd64"},
testTags: map[string]bool{
"mywindows": false,
"myamd64": false,
"mywindows,myamd64": false,
},
want: map[string]bool{
"mywindows": true,
"myamd64": true,
"mywindows,myamd64": true,
},
},
{
name: "complex tag combinations",
buildFlags: []string{"-tags", "mylinux,myamd64"},
testTags: map[string]bool{
"mywindows": false,
"!mywindows": false,
"mylinux": false,
"mylinux,myamd64": false,
"!mywindows,myamd64": false,
},
want: map[string]bool{
"mywindows": false,
"!mywindows": true,
"mylinux": true,
"mylinux,myamd64": true,
"!mywindows,myamd64": true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testTags := make(map[string]bool)
for k := range tt.testTags {
testTags[k] = false
}
CheckTags(tt.buildFlags, testTags)
if !reflect.DeepEqual(testTags, tt.want) {
t.Errorf("CheckTags() = %v, want %v", testTags, tt.want)
}
})
}
}
func TestParseBuildTags(t *testing.T) {
tests := []struct {
name string
buildFlags []string
want []string
}{
{
name: "space separated tags",
buildFlags: []string{"-tags", "mywindows myamd64"},
want: []string{"mywindows", "myamd64"},
},
{
name: "equals format",
buildFlags: []string{"-tags=mywindows,myamd64"},
want: []string{"mywindows", "myamd64"},
},
{
name: "multiple -tags flags",
buildFlags: []string{"-tags", "mywindows", "-tags", "myamd64"},
want: []string{"mywindows", "myamd64"},
},
{
name: "duplicate tags",
buildFlags: []string{"-tags", "mywindows myamd64", "-tags=mywindows"},
want: []string{"mywindows", "myamd64"},
},
{
name: "empty tags",
buildFlags: []string{},
want: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := parseBuildTags(tt.buildFlags)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("name: %v, parseBuildTags() = %v, want %v", tt.name, got, tt.want)
}
})
}
}

58
internal/env/env.go vendored
View File

@@ -1,58 +0,0 @@
package env
import (
"os"
"path/filepath"
"strings"
)
const (
LLGoCompilerPkg = "github.com/goplus/llgo"
)
func LLGoROOT() string {
if root, ok := isLLGoRoot(os.Getenv("LLGO_ROOT")); ok {
return root
}
// Get executable path
exe, err := os.Executable()
if err != nil {
return ""
}
// Resolve any symlinks
exe, err = filepath.EvalSymlinks(exe)
if err != nil {
return ""
}
// Check if parent directory is bin
dir := filepath.Dir(exe)
if filepath.Base(dir) != "bin" {
return ""
}
// Get parent directory of bin
root := filepath.Dir(dir)
if root, ok := isLLGoRoot(root); ok {
return root
}
return ""
}
func isLLGoRoot(root string) (string, bool) {
if root == "" {
return "", false
}
root, err := filepath.Abs(root)
if err != nil {
return "", false
}
// Check for go.mod
data, err := os.ReadFile(filepath.Join(root, "go.mod"))
if err != nil {
return "", false
}
// Check module name
if !strings.Contains(string(data), "module "+LLGoCompilerPkg+"\n") {
return "", false
}
return root, true
}

View File

@@ -1,72 +0,0 @@
package hmac
// llgo:skipall
import (
"crypto/sha256"
"crypto/subtle"
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
type eface struct {
_type unsafe.Pointer
funcPtr *unsafe.Pointer
}
func funcOf(a any) unsafe.Pointer {
e := (*eface)(unsafe.Pointer(&a))
return *e.funcPtr
}
type digest openssl.HMAC_CTX
func (d *digest) Size() int { panic("todo: hmac.(*digest).Size") }
func (d *digest) BlockSize() int { panic("todo: hmac.(*digest).BlockSize") }
func (d *digest) Reset() {
(*openssl.HMAC_CTX)(d).Reset()
}
func (d *digest) Write(p []byte) (nn int, err error) {
(*openssl.HMAC_CTX)(d).UpdateBytes(p)
return len(p), nil
}
func (d *digest) Sum(in []byte) []byte {
const Size = openssl.EVP_MAX_MD_SIZE
var digestLen c.Uint
hash := (*[Size]byte)(c.Alloca(Size))
(*openssl.HMAC_CTX)(d).Final(&hash[0], &digestLen)
return append(in, hash[:digestLen]...)
}
// New returns a new HMAC hash using the given [hash.Hash] type and key.
// New functions like sha256.New from [crypto/sha256] can be used as h.
// h must return a new Hash every time it is called.
// Note that unlike other hash implementations in the standard library,
// the returned Hash does not implement [encoding.BinaryMarshaler]
// or [encoding.BinaryUnmarshaler].
func New(h func() hash.Hash, key []byte) hash.Hash {
var md *openssl.EVP_MD
switch funcOf(h) {
case c.Func(sha256.New):
md = openssl.EVP_sha256()
default:
panic("todo: hmac.New: unsupported hash function")
}
ctx := openssl.NewHMAC_CTX()
ctx.InitBytes(key, md)
return (*digest)(ctx)
}
// Equal compares two MACs for equality without leaking timing information.
func Equal(mac1, mac2 []byte) bool {
// We don't have to be constant time if the lengths of the MACs are
// different as that suggests that a completely different hash function
// was used.
return subtle.ConstantTimeCompare(mac1, mac2) == 1
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package md5
// llgo:skipall
import (
"crypto"
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
func init() {
crypto.RegisterHash(crypto.MD5, New)
}
// The blocksize of MD5 in bytes.
const BlockSize = 64
// The size of an MD5 checksum in bytes.
const Size = 16
type digest struct {
ctx openssl.MD5_CTX
}
func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Reset() {
d.ctx.Init()
}
func (d *digest) Write(p []byte) (nn int, err error) {
d.ctx.UpdateBytes(p)
return len(p), nil
}
func (d *digest) Sum(in []byte) []byte {
hash := (*[Size]byte)(c.Alloca(Size))
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
return append(in, hash[:]...)
}
func New() hash.Hash {
d := new(digest)
d.ctx.Init()
return d
}
func Sum(data []byte) (ret [Size]byte) {
openssl.MD5Bytes(data, &ret[0])
return
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rand
// llgo:skipall
import (
"io"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
"github.com/qiniu/x/errors"
)
type rndReader struct{}
func (rndReader) Read(p []byte) (n int, err error) {
return Read(p)
}
// Reader is a global, shared instance of a cryptographically
// secure random number generator.
var Reader io.Reader = rndReader{}
type opensslError struct {
file *c.Char
line c.Int
flags c.Int
function *c.Char
data *c.Char
err openssl.Errno
}
// [error code]:[library name]:[function name]:[reason string]:[[filename:line]]: [text message]
func (p *opensslError) Error() string {
const bufsize = 1024
buf := (*c.Char)(c.Alloca(bufsize))
lib := openssl.ERRLibErrorString(p.err)
reason := openssl.ERRReasonErrorString(p.err)
n := uintptr(c.Snprintf(
buf, bufsize,
c.Str("%d:%s:%s:%s:[%s:%d]: "),
p.err, lib, p.function, reason, p.file, p.line))
n += c.Strlen(openssl.ERRErrorString(p.err, c.Advance(buf, n)))
return c.GoString(buf, n)
}
func getError() *opensslError {
ret := new(opensslError)
err := openssl.ERRGetErrorAll(&ret.file, &ret.line, &ret.function, &ret.data, &ret.flags)
if err == 0 {
return nil
}
return ret
}
func getErrors() error {
var errs errors.List
for openssl.ERRPeekError() != 0 {
errs.Add(getError())
}
return errs.ToError()
}
// Read is a helper function that calls Reader.Read using io.ReadFull.
// On return, n == len(b) if and only if err == nil.
func Read(b []byte) (n int, err error) {
if openssl.RANDBytes(b) != 0 {
return len(b), nil
}
return 0, getErrors()
}
/* TODO(xsw):
// batched returns a function that calls f to populate a []byte by chunking it
// into subslices of, at most, readMax bytes.
func batched(f func([]byte) error, readMax int) func([]byte) error {
return func(out []byte) error {
for len(out) > 0 {
read := len(out)
if read > readMax {
read = readMax
}
if err := f(out[:read]); err != nil {
return err
}
out = out[read:]
}
return nil
}
}
*/

View File

@@ -1,98 +0,0 @@
// Copyright 2011 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 rand
/* TODO(xsw):
import (
"errors"
"io"
"math/big"
)
// Prime returns a number of the given bit length that is prime with high probability.
// Prime will return error for any error returned by rand.Read or if bits < 2.
func Prime(rand io.Reader, bits int) (*big.Int, error) {
if bits < 2 {
return nil, errors.New("crypto/rand: prime size must be at least 2-bit")
}
b := uint(bits % 8)
if b == 0 {
b = 8
}
bytes := make([]byte, (bits+7)/8)
p := new(big.Int)
for {
if _, err := io.ReadFull(rand, bytes); err != nil {
return nil, err
}
// Clear bits in the first byte to make sure the candidate has a size <= bits.
bytes[0] &= uint8(int(1<<b) - 1)
// Don't let the value be too small, i.e, set the most significant two bits.
// Setting the top two bits, rather than just the top bit,
// means that when two of these values are multiplied together,
// the result isn't ever one bit short.
if b >= 2 {
bytes[0] |= 3 << (b - 2)
} else {
// Here b==1, because b cannot be zero.
bytes[0] |= 1
if len(bytes) > 1 {
bytes[1] |= 0x80
}
}
// Make the value odd since an even number this large certainly isn't prime.
bytes[len(bytes)-1] |= 1
p.SetBytes(bytes)
if p.ProbablyPrime(20) {
return p, nil
}
}
}
// Int returns a uniform random value in [0, max). It panics if max <= 0.
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
if max.Sign() <= 0 {
panic("crypto/rand: argument to Int is <= 0")
}
n = new(big.Int)
n.Sub(max, n.SetUint64(1))
// bitLen is the maximum bit length needed to encode a value < max.
bitLen := n.BitLen()
if bitLen == 0 {
// the only valid result is 0
return
}
// k is the maximum byte length needed to encode a value < max.
k := (bitLen + 7) / 8
// b is the number of bits in the most significant byte of max-1.
b := uint(bitLen % 8)
if b == 0 {
b = 8
}
bytes := make([]byte, k)
for {
_, err = io.ReadFull(rand, bytes)
if err != nil {
return nil, err
}
// Clear bits in the first byte to increase the probability
// that the candidate is < max.
bytes[0] &= uint8(int(1<<b) - 1)
n.SetBytes(bytes)
if n.Cmp(max) < 0 {
return
}
}
}
*/

View File

@@ -1,73 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sha1
// llgo:skipall
import (
"crypto"
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
func init() {
crypto.RegisterHash(crypto.SHA1, New)
}
// The blocksize of SHA-1 in bytes.
const BlockSize = 64
// The size of a SHA-1 checksum in bytes.
const Size = 20
type digest struct {
ctx openssl.SHA_CTX
}
func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Reset() {
d.ctx.Init()
}
func (d *digest) Write(p []byte) (nn int, err error) {
d.ctx.UpdateBytes(p)
return len(p), nil
}
func (d *digest) Sum(in []byte) []byte {
hash := (*[Size]byte)(c.Alloca(Size))
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
return append(in, hash[:]...)
}
// New returns a new hash.Hash computing the SHA1 checksum.
func New() hash.Hash {
d := new(digest)
d.ctx.Init()
return d
}
// Sum returns the SHA-1 checksum of the data.
func Sum(data []byte) (ret [Size]byte) {
openssl.SHA1Bytes(data, &ret[0])
return
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sha256
import (
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
// The size of a SHA224 checksum in bytes.
const Size224 = 28
type digest224 struct {
ctx openssl.SHA224_CTX
}
func (d *digest224) Size() int { return Size224 }
func (d *digest224) BlockSize() int { return BlockSize }
func (d *digest224) Reset() {
d.ctx.Init()
}
func (d *digest224) Write(p []byte) (nn int, err error) {
d.ctx.UpdateBytes(p)
return len(p), nil
}
func (d *digest224) Sum(in []byte) []byte {
hash := (*[Size]byte)(c.Alloca(Size))
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
return append(in, hash[:]...)
}
// New224 returns a new hash.Hash computing the SHA224 checksum.
func New224() hash.Hash {
d := new(digest224)
d.ctx.Init()
return d
}
// Sum224 returns the SHA224 checksum of the data.
func Sum224(data []byte) (ret [Size224]byte) {
openssl.SHA224Bytes(data, &ret[0])
return
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sha256
// llgo:skipall
import (
"crypto"
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
func init() {
crypto.RegisterHash(crypto.SHA224, New224)
crypto.RegisterHash(crypto.SHA256, New)
}
// The blocksize of SHA256 and SHA224 in bytes.
const BlockSize = 64
// The size of a SHA256 checksum in bytes.
const Size = 32
type digest256 struct {
ctx openssl.SHA256_CTX
}
func (d *digest256) Size() int { return Size }
func (d *digest256) BlockSize() int { return BlockSize }
func (d *digest256) Reset() {
d.ctx.Init()
}
func (d *digest256) Write(p []byte) (nn int, err error) {
d.ctx.UpdateBytes(p)
return len(p), nil
}
func (d *digest256) Sum(in []byte) []byte {
hash := (*[Size]byte)(c.Alloca(Size))
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
return append(in, hash[:]...)
}
// New returns a new hash.Hash computing the SHA256 checksum.
func New() hash.Hash {
d := new(digest256)
d.ctx.Init()
return d
}
// Sum256 returns the SHA256 checksum of the data.
func Sum256(data []byte) (ret [Size]byte) {
openssl.SHA256Bytes(data, &ret[0])
return
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sha512
import (
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
type digest384 struct {
ctx openssl.SHA384_CTX
}
func (d *digest384) Size() int { return Size384 }
func (d *digest384) BlockSize() int { return BlockSize }
func (d *digest384) Reset() {
d.ctx.Init()
}
func (d *digest384) Write(p []byte) (nn int, err error) {
d.ctx.UpdateBytes(p)
return len(p), nil
}
func (d *digest384) Sum(in []byte) []byte {
hash := (*[Size]byte)(c.Alloca(Size))
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
return append(in, hash[:]...)
}
func New384() hash.Hash {
d := new(digest384)
d.ctx.Init()
return d
}
func Sum384(data []byte) (ret [Size384]byte) {
openssl.SHA384Bytes(data, &ret[0])
return
}

View File

@@ -1,102 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sha512
// llgo:skipall
import (
"crypto"
"hash"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
func init() {
crypto.RegisterHash(crypto.SHA384, New384)
crypto.RegisterHash(crypto.SHA512, New)
crypto.RegisterHash(crypto.SHA512_224, New512_224)
crypto.RegisterHash(crypto.SHA512_256, New512_256)
}
const (
// Size is the size, in bytes, of a SHA-512 checksum.
Size = 64
// Size224 is the size, in bytes, of a SHA-512/224 checksum.
Size224 = 28
// Size256 is the size, in bytes, of a SHA-512/256 checksum.
Size256 = 32
// Size384 is the size, in bytes, of a SHA-384 checksum.
Size384 = 48
// BlockSize is the block size, in bytes, of the SHA-512/224,
// SHA-512/256, SHA-384 and SHA-512 hash functions.
BlockSize = 128
)
type digest512 struct {
ctx openssl.SHA512_CTX
}
func (d *digest512) Size() int { return Size }
func (d *digest512) BlockSize() int { return BlockSize }
func (d *digest512) Reset() {
d.ctx.Init()
}
func (d *digest512) Write(p []byte) (nn int, err error) {
d.ctx.UpdateBytes(p)
return len(p), nil
}
func (d *digest512) Sum(in []byte) []byte {
hash := (*[Size]byte)(c.Alloca(Size))
d.ctx.Final((*byte)(unsafe.Pointer(hash)))
return append(in, hash[:]...)
}
func New() hash.Hash {
d := new(digest512)
d.ctx.Init()
return d
}
func Sum512(data []byte) (ret [Size]byte) {
openssl.SHA512Bytes(data, &ret[0])
return
}
func New512_224() hash.Hash {
panic("todo: crypto/sha512.New512_224")
}
func Sum512_224(data []byte) [Size224]byte {
panic("todo: crypto/sha512.Sum512_224")
}
func New512_256() hash.Hash {
panic("todo: crypto/sha512.New512_256")
}
func Sum512_256(data []byte) [Size256]byte {
panic("todo: crypto/sha512.Sum512_256")
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package subtle
// llgo:skip XORBytes
import (
_ "unsafe"
)

View File

@@ -1,78 +0,0 @@
// Copyright 2018 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 fmt
import (
"errors"
"sort"
)
// Errorf formats according to a format specifier and returns the string as a
// value that satisfies error.
//
// If the format specifier includes a %w verb with an error operand,
// the returned error will implement an Unwrap method returning the operand.
// If there is more than one %w verb, the returned error will implement an
// Unwrap method returning a []error containing all the %w operands in the
// order they appear in the arguments.
// It is invalid to supply the %w verb with an operand that does not implement
// the error interface. The %w verb is otherwise a synonym for %v.
func Errorf(format string, a ...any) error {
p := newPrinter()
p.wrapErrs = true
p.doPrintf(format, a)
s := string(p.buf)
var err error
switch len(p.wrappedErrs) {
case 0:
err = errors.New(s)
case 1:
w := &wrapError{msg: s}
w.err, _ = a[p.wrappedErrs[0]].(error)
err = w
default:
if p.reordered {
sort.Ints(p.wrappedErrs)
}
var errs []error
for i, argNum := range p.wrappedErrs {
if i > 0 && p.wrappedErrs[i-1] == argNum {
continue
}
if e, ok := a[argNum].(error); ok {
errs = append(errs, e)
}
}
err = &wrapErrors{s, errs}
}
p.free()
return err
}
type wrapError struct {
msg string
err error
}
func (e *wrapError) Error() string {
return e.msg
}
func (e *wrapError) Unwrap() error {
return e.err
}
type wrapErrors struct {
msg string
errs []error
}
func (e *wrapErrors) Error() string {
return e.msg
}
func (e *wrapErrors) Unwrap() []error {
return e.errs
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fmt
// llgo:skipall
import (
_ "unsafe"
)

View File

@@ -1,594 +0,0 @@
// 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 fmt
import (
"strconv"
"unicode/utf8"
)
const (
ldigits = "0123456789abcdefx"
udigits = "0123456789ABCDEFX"
)
const (
signed = true
unsigned = false
)
// flags placed in a separate struct for easy clearing.
type fmtFlags struct {
widPresent bool
precPresent bool
minus bool
plus bool
sharp bool
space bool
zero bool
// For the formats %+v %#v, we set the plusV/sharpV flags
// and clear the plus/sharp flags since %+v and %#v are in effect
// different, flagless formats set at the top level.
plusV bool
sharpV bool
}
// A fmt is the raw formatter used by Printf etc.
// It prints into a buffer that must be set up separately.
type fmt struct {
buf *buffer
fmtFlags
wid int // width
prec int // precision
// intbuf is large enough to store %b of an int64 with a sign and
// avoids padding at the end of the struct on 32 bit architectures.
intbuf [68]byte
}
func (f *fmt) clearflags() {
f.fmtFlags = fmtFlags{}
}
func (f *fmt) init(buf *buffer) {
f.buf = buf
f.clearflags()
}
// writePadding generates n bytes of padding.
func (f *fmt) writePadding(n int) {
if n <= 0 { // No padding bytes needed.
return
}
buf := *f.buf
oldLen := len(buf)
newLen := oldLen + n
// Make enough room for padding.
if newLen > cap(buf) {
buf = make(buffer, cap(buf)*2+n)
copy(buf, *f.buf)
}
// Decide which byte the padding should be filled with.
padByte := byte(' ')
if f.zero {
padByte = byte('0')
}
// Fill padding with padByte.
padding := buf[oldLen:newLen]
for i := range padding {
padding[i] = padByte
}
*f.buf = buf[:newLen]
}
// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) pad(b []byte) {
if !f.widPresent || f.wid == 0 {
f.buf.write(b)
return
}
width := f.wid - utf8.RuneCount(b)
if !f.minus {
// left padding
f.writePadding(width)
f.buf.write(b)
} else {
// right padding
f.buf.write(b)
f.writePadding(width)
}
}
// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) padString(s string) {
if !f.widPresent || f.wid == 0 {
f.buf.writeString(s)
return
}
width := f.wid - utf8.RuneCountInString(s)
if !f.minus {
// left padding
f.writePadding(width)
f.buf.writeString(s)
} else {
// right padding
f.buf.writeString(s)
f.writePadding(width)
}
}
// fmtBoolean formats a boolean.
func (f *fmt) fmtBoolean(v bool) {
if v {
f.padString("true")
} else {
f.padString("false")
}
}
// fmtUnicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
func (f *fmt) fmtUnicode(u uint64) {
buf := f.intbuf[0:]
// With default precision set the maximum needed buf length is 18
// for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
// into the already allocated intbuf with a capacity of 68 bytes.
prec := 4
if f.precPresent && f.prec > 4 {
prec = f.prec
// Compute space needed for "U+" , number, " '", character, "'".
width := 2 + prec + 2 + utf8.UTFMax + 1
if width > len(buf) {
buf = make([]byte, width)
}
}
// Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
i := len(buf)
// For %#U we want to add a space and a quoted character at the end of the buffer.
if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
i--
buf[i] = '\''
i -= utf8.RuneLen(rune(u))
utf8.EncodeRune(buf[i:], rune(u))
i--
buf[i] = '\''
i--
buf[i] = ' '
}
// Format the Unicode code point u as a hexadecimal number.
for u >= 16 {
i--
buf[i] = udigits[u&0xF]
prec--
u >>= 4
}
i--
buf[i] = udigits[u]
prec--
// Add zeros in front of the number until requested precision is reached.
for prec > 0 {
i--
buf[i] = '0'
prec--
}
// Add a leading "U+".
i--
buf[i] = '+'
i--
buf[i] = 'U'
oldZero := f.zero
f.zero = false
f.pad(buf[i:])
f.zero = oldZero
}
// fmtInteger formats signed and unsigned integers.
func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits string) {
negative := isSigned && int64(u) < 0
if negative {
u = -u
}
buf := f.intbuf[0:]
// The already allocated f.intbuf with a capacity of 68 bytes
// is large enough for integer formatting when no precision or width is set.
if f.widPresent || f.precPresent {
// Account 3 extra bytes for possible addition of a sign and "0x".
width := 3 + f.wid + f.prec // wid and prec are always positive.
if width > len(buf) {
// We're going to need a bigger boat.
buf = make([]byte, width)
}
}
// Two ways to ask for extra leading zero digits: %.3d or %03d.
// If both are specified the f.zero flag is ignored and
// padding with spaces is used instead.
prec := 0
if f.precPresent {
prec = f.prec
// Precision of 0 and value of 0 means "print nothing" but padding.
if prec == 0 && u == 0 {
oldZero := f.zero
f.zero = false
f.writePadding(f.wid)
f.zero = oldZero
return
}
} else if f.zero && f.widPresent {
prec = f.wid
if negative || f.plus || f.space {
prec-- // leave room for sign
}
}
// Because printing is easier right-to-left: format u into buf, ending at buf[i].
// We could make things marginally faster by splitting the 32-bit case out
// into a separate block but it's not worth the duplication, so u has 64 bits.
i := len(buf)
// Use constants for the division and modulo for more efficient code.
// Switch cases ordered by popularity.
switch base {
case 10:
for u >= 10 {
i--
next := u / 10
buf[i] = byte('0' + u - next*10)
u = next
}
case 16:
for u >= 16 {
i--
buf[i] = digits[u&0xF]
u >>= 4
}
case 8:
for u >= 8 {
i--
buf[i] = byte('0' + u&7)
u >>= 3
}
case 2:
for u >= 2 {
i--
buf[i] = byte('0' + u&1)
u >>= 1
}
default:
panic("fmt: unknown base; can't happen")
}
i--
buf[i] = digits[u]
for i > 0 && prec > len(buf)-i {
i--
buf[i] = '0'
}
// Various prefixes: 0x, -, etc.
if f.sharp {
switch base {
case 2:
// Add a leading 0b.
i--
buf[i] = 'b'
i--
buf[i] = '0'
case 8:
if buf[i] != '0' {
i--
buf[i] = '0'
}
case 16:
// Add a leading 0x or 0X.
i--
buf[i] = digits[16]
i--
buf[i] = '0'
}
}
if verb == 'O' {
i--
buf[i] = 'o'
i--
buf[i] = '0'
}
if negative {
i--
buf[i] = '-'
} else if f.plus {
i--
buf[i] = '+'
} else if f.space {
i--
buf[i] = ' '
}
// Left padding with zeros has already been handled like precision earlier
// or the f.zero flag is ignored due to an explicitly set precision.
oldZero := f.zero
f.zero = false
f.pad(buf[i:])
f.zero = oldZero
}
// truncateString truncates the string s to the specified precision, if present.
func (f *fmt) truncateString(s string) string {
if f.precPresent {
n := f.prec
for i := range s {
n--
if n < 0 {
return s[:i]
}
}
}
return s
}
// truncate truncates the byte slice b as a string of the specified precision, if present.
func (f *fmt) truncate(b []byte) []byte {
if f.precPresent {
n := f.prec
for i := 0; i < len(b); {
n--
if n < 0 {
return b[:i]
}
wid := 1
if b[i] >= utf8.RuneSelf {
_, wid = utf8.DecodeRune(b[i:])
}
i += wid
}
}
return b
}
// fmtS formats a string.
func (f *fmt) fmtS(s string) {
s = f.truncateString(s)
f.padString(s)
}
// fmtBs formats the byte slice b as if it was formatted as string with fmtS.
func (f *fmt) fmtBs(b []byte) {
b = f.truncate(b)
f.pad(b)
}
// fmtSbx formats a string or byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmtSbx(s string, b []byte, digits string) {
length := len(b)
if b == nil {
// No byte slice present. Assume string s should be encoded.
length = len(s)
}
// Set length to not process more bytes than the precision demands.
if f.precPresent && f.prec < length {
length = f.prec
}
// Compute width of the encoding taking into account the f.sharp and f.space flag.
width := 2 * length
if width > 0 {
if f.space {
// Each element encoded by two hexadecimals will get a leading 0x or 0X.
if f.sharp {
width *= 2
}
// Elements will be separated by a space.
width += length - 1
} else if f.sharp {
// Only a leading 0x or 0X will be added for the whole string.
width += 2
}
} else { // The byte slice or string that should be encoded is empty.
if f.widPresent {
f.writePadding(f.wid)
}
return
}
// Handle padding to the left.
if f.widPresent && f.wid > width && !f.minus {
f.writePadding(f.wid - width)
}
// Write the encoding directly into the output buffer.
buf := *f.buf
if f.sharp {
// Add leading 0x or 0X.
buf = append(buf, '0', digits[16])
}
var c byte
for i := 0; i < length; i++ {
if f.space && i > 0 {
// Separate elements with a space.
buf = append(buf, ' ')
if f.sharp {
// Add leading 0x or 0X for each element.
buf = append(buf, '0', digits[16])
}
}
if b != nil {
c = b[i] // Take a byte from the input byte slice.
} else {
c = s[i] // Take a byte from the input string.
}
// Encode each byte as two hexadecimal digits.
buf = append(buf, digits[c>>4], digits[c&0xF])
}
*f.buf = buf
// Handle padding to the right.
if f.widPresent && f.wid > width && f.minus {
f.writePadding(f.wid - width)
}
}
// fmtSx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmtSx(s, digits string) {
f.fmtSbx(s, nil, digits)
}
// fmtBx formats a byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmtBx(b []byte, digits string) {
f.fmtSbx("", b, digits)
}
// fmtQ formats a string as a double-quoted, escaped Go string constant.
// If f.sharp is set a raw (backquoted) string may be returned instead
// if the string does not contain any control characters other than tab.
func (f *fmt) fmtQ(s string) {
s = f.truncateString(s)
if f.sharp && strconv.CanBackquote(s) {
f.padString("`" + s + "`")
return
}
buf := f.intbuf[:0]
if f.plus {
f.pad(strconv.AppendQuoteToASCII(buf, s))
} else {
f.pad(strconv.AppendQuote(buf, s))
}
}
// fmtC formats an integer as a Unicode character.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmtC(c uint64) {
// Explicitly check whether c exceeds utf8.MaxRune since the conversion
// of a uint64 to a rune may lose precision that indicates an overflow.
r := rune(c)
if c > utf8.MaxRune {
r = utf8.RuneError
}
buf := f.intbuf[:0]
f.pad(utf8.AppendRune(buf, r))
}
// fmtQc formats an integer as a single-quoted, escaped Go character constant.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmtQc(c uint64) {
r := rune(c)
if c > utf8.MaxRune {
r = utf8.RuneError
}
buf := f.intbuf[:0]
if f.plus {
f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
} else {
f.pad(strconv.AppendQuoteRune(buf, r))
}
}
// fmtFloat formats a float64. It assumes that verb is a valid format specifier
// for strconv.AppendFloat and therefore fits into a byte.
func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) {
// Explicit precision in format specifier overrules default precision.
if f.precPresent {
prec = f.prec
}
// Format number, reserving space for leading + sign if needed.
num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
if num[1] == '-' || num[1] == '+' {
num = num[1:]
} else {
num[0] = '+'
}
// f.space means to add a leading space instead of a "+" sign unless
// the sign is explicitly asked for by f.plus.
if f.space && num[0] == '+' && !f.plus {
num[0] = ' '
}
// Special handling for infinities and NaN,
// which don't look like a number so shouldn't be padded with zeros.
if num[1] == 'I' || num[1] == 'N' {
oldZero := f.zero
f.zero = false
// Remove sign before NaN if not asked for.
if num[1] == 'N' && !f.space && !f.plus {
num = num[1:]
}
f.pad(num)
f.zero = oldZero
return
}
// The sharp flag forces printing a decimal point for non-binary formats
// and retains trailing zeros, which we may need to restore.
if f.sharp && verb != 'b' {
digits := 0
switch verb {
case 'v', 'g', 'G', 'x':
digits = prec
// If no precision is set explicitly use a precision of 6.
if digits == -1 {
digits = 6
}
}
// Buffer pre-allocated with enough room for
// exponent notations of the form "e+123" or "p-1023".
var tailBuf [6]byte
tail := tailBuf[:0]
hasDecimalPoint := false
sawNonzeroDigit := false
// Starting from i = 1 to skip sign at num[0].
for i := 1; i < len(num); i++ {
switch num[i] {
case '.':
hasDecimalPoint = true
case 'p', 'P':
tail = append(tail, num[i:]...)
num = num[:i]
case 'e', 'E':
if verb != 'x' && verb != 'X' {
tail = append(tail, num[i:]...)
num = num[:i]
break
}
fallthrough
default:
if num[i] != '0' {
sawNonzeroDigit = true
}
// Count significant digits after the first non-zero digit.
if sawNonzeroDigit {
digits--
}
}
}
if !hasDecimalPoint {
// Leading digit 0 should contribute once to digits.
if len(num) == 2 && num[1] == '0' {
digits--
}
num = append(num, '.')
}
for digits > 0 {
num = append(num, '0')
digits--
}
num = append(num, tail...)
}
// We want a sign if asked for and if the sign is not positive.
if f.plus || num[0] != '+' {
// If we're zero padding to the left we want the sign before the leading zeros.
// Achieve this by writing the sign out and then padding the unsigned number.
if f.zero && f.widPresent && f.wid > len(num) {
f.buf.writeByte(num[0])
f.writePadding(f.wid - len(num))
f.buf.write(num[1:])
return
}
f.pad(num)
return
}
// No sign to show and the number is positive; just print the unsigned number.
f.pad(num[1:])
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,112 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package crc32
// llgo:skipall
import (
"hash"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/zlib"
)
// The size of a CRC-32 checksum in bytes.
const Size = 4
// Predefined polynomials.
const (
// IEEE is by far and away the most common CRC-32 polynomial.
// Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ...
IEEE = 0xedb88320
// Castagnoli's polynomial, used in iSCSI.
// Has better error detection characteristics than IEEE.
// https://dx.doi.org/10.1109/26.231911
Castagnoli = 0x82f63b78
// Koopman's polynomial.
// Also has better error detection characteristics than IEEE.
// https://dx.doi.org/10.1109/DSN.2002.1028931
Koopman = 0xeb31d82e
)
// Table is a 256-word table representing the polynomial for efficient processing.
type Table [256]uint32
// IEEETable is the table for the IEEE polynomial.
var IEEETable *Table = new(Table)
// MakeTable returns a Table constructed from the specified polynomial.
// The contents of this Table must not be modified.
func MakeTable(poly uint32) *Table {
if poly == IEEE {
return IEEETable
}
panic("todo: hash/crc32.MakeTable")
}
type digest uint32
func (d *digest) Size() int { return Size }
func (d *digest) BlockSize() int { return 1 }
func (d *digest) Reset() { *d = 0 }
func (d *digest) Write(p []byte) (n int, err error) {
*d = digest(zlib.Crc32ZBytes(c.Ulong(*d), p))
return len(p), nil
}
func (d *digest) Sum32() uint32 { return uint32(*d) }
func (d *digest) Sum(in []byte) []byte {
s := d.Sum32()
return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
}
func New(tab *Table) hash.Hash32 {
if tab == IEEETable {
return new(digest)
}
panic("todo: hash/crc32.New")
}
// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum using
// the IEEE polynomial. Its Sum method will lay the value out in
// big-endian byte order. The returned Hash32 also implements
// encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to marshal
// and unmarshal the internal state of the hash.
func NewIEEE() hash.Hash32 { return New(IEEETable) }
// Update returns the result of adding the bytes in p to the crc.
func Update(crc uint32, tab *Table, p []byte) uint32 {
if tab == IEEETable {
return uint32(zlib.Crc32ZBytes(c.Ulong(crc), p))
}
panic("todo: hash/crc32.Update")
}
// Checksum returns the CRC-32 checksum of data
// using the polynomial represented by the Table.
func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
// ChecksumIEEE returns the CRC-32 checksum of data
// using the IEEE polynomial.
func ChecksumIEEE(data []byte) uint32 {
return uint32(zlib.Crc32ZBytes(0, data))
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package abi
// llgo:skipall
import (
"unsafe"
"github.com/goplus/llgo/internal/abi"
)
type InterfaceType = abi.InterfaceType
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
return unsafe.Pointer(x ^ 0)
}

View File

@@ -1,148 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package bytealg
// llgo:skip init CompareString
import (
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/internal/runtime"
)
func IndexByte(b []byte, ch byte) int {
ptr := unsafe.Pointer(unsafe.SliceData(b))
ret := c.Memchr(ptr, c.Int(ch), uintptr(len(b)))
if ret != nil {
return int(uintptr(ret) - uintptr(ptr))
}
return -1
}
func IndexByteString(s string, ch byte) int {
ptr := unsafe.Pointer(unsafe.StringData(s))
ret := c.Memchr(ptr, c.Int(ch), uintptr(len(s)))
if ret != nil {
return int(uintptr(ret) - uintptr(ptr))
}
return -1
}
func Count(b []byte, c byte) (n int) {
for _, x := range b {
if x == c {
n++
}
}
return
}
func CountString(s string, c byte) (n int) {
for i := 0; i < len(s); i++ {
if s[i] == c {
n++
}
}
return
}
// Index returns the index of the first instance of b in a, or -1 if b is not present in a.
// Requires 2 <= len(b) <= MaxLen.
func Index(a, b []byte) int {
for i := 0; i <= len(a)-len(b); i++ {
if equal(a[i:i+len(b)], b) {
return i
}
}
return -1
}
func equal(a, b []byte) bool {
if n := len(a); n == len(b) {
return c.Memcmp(unsafe.Pointer(unsafe.SliceData(a)), unsafe.Pointer(unsafe.SliceData(b)), uintptr(n)) == 0
}
return false
}
// IndexString returns the index of the first instance of b in a, or -1 if b is not present in a.
// Requires 2 <= len(b) <= MaxLen.
func IndexString(a, b string) int {
for i := 0; i <= len(a)-len(b); i++ {
if a[i:i+len(b)] == b {
return i
}
}
return -1
}
// MakeNoZero makes a slice of length and capacity n without zeroing the bytes.
// It is the caller's responsibility to ensure uninitialized bytes
// do not leak to the end user.
func MakeNoZero(n int) (r []byte) {
s := (*sliceHead)(unsafe.Pointer(&r))
s.data = runtime.AllocU(uintptr(n))
s.len = n
s.cap = n
return
}
type sliceHead struct {
data unsafe.Pointer
len int
cap int
}
func LastIndexByte(s []byte, c byte) int {
for i := len(s) - 1; i >= 0; i-- {
if s[i] == c {
return i
}
}
return -1
}
func LastIndexByteString(s string, c byte) int {
for i := len(s) - 1; i >= 0; i-- {
if s[i] == c {
return i
}
}
return -1
}
func CompareString(a, b string) int {
l := len(a)
if len(b) < l {
l = len(b)
}
for i := 0; i < l; i++ {
c1, c2 := a[i], b[i]
if c1 < c2 {
return -1
}
if c1 > c2 {
return +1
}
}
if len(a) < len(b) {
return -1
}
if len(a) > len(b) {
return +1
}
return 0
}

View File

@@ -1 +0,0 @@
package filepathlite

View File

@@ -1,220 +0,0 @@
// Copyright 2018 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 fmtsort provides a general stable ordering mechanism
// for maps, on behalf of the fmt and text/template packages.
// It is not guaranteed to be efficient and works only for types
// that are valid map keys.
package fmtsort
// llgo:skipall
import (
"reflect"
"sort"
)
// Note: Throughout this package we avoid calling reflect.Value.Interface as
// it is not always legal to do so and it's easier to avoid the issue than to face it.
// SortedMap represents a map's keys and values. The keys and values are
// aligned in index order: Value[i] is the value in the map corresponding to Key[i].
type SortedMap struct {
Key []reflect.Value
Value []reflect.Value
}
func (o *SortedMap) Len() int { return len(o.Key) }
func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 }
func (o *SortedMap) Swap(i, j int) {
o.Key[i], o.Key[j] = o.Key[j], o.Key[i]
o.Value[i], o.Value[j] = o.Value[j], o.Value[i]
}
// Sort accepts a map and returns a SortedMap that has the same keys and
// values but in a stable sorted order according to the keys, modulo issues
// raised by unorderable key values such as NaNs.
//
// The ordering rules are more general than with Go's < operator:
//
// - when applicable, nil compares low
// - ints, floats, and strings order by <
// - NaN compares less than non-NaN floats
// - bool compares false before true
// - complex compares real, then imag
// - pointers compare by machine address
// - channel values compare by machine address
// - structs compare each field in turn
// - arrays compare each element in turn.
// Otherwise identical arrays compare by length.
// - interface values compare first by reflect.Type describing the concrete type
// and then by concrete value as described in the previous rules.
func Sort(mapValue reflect.Value) *SortedMap {
if mapValue.Type().Kind() != reflect.Map {
return nil
}
// Note: this code is arranged to not panic even in the presence
// of a concurrent map update. The runtime is responsible for
// yelling loudly if that happens. See issue 33275.
n := mapValue.Len()
key := make([]reflect.Value, 0, n)
value := make([]reflect.Value, 0, n)
iter := mapValue.MapRange()
for iter.Next() {
key = append(key, iter.Key())
value = append(value, iter.Value())
}
sorted := &SortedMap{
Key: key,
Value: value,
}
sort.Stable(sorted)
return sorted
}
// compare compares two values of the same type. It returns -1, 0, 1
// according to whether a > b (1), a == b (0), or a < b (-1).
// If the types differ, it returns -1.
// See the comment on Sort for the comparison rules.
func compare(aVal, bVal reflect.Value) int {
aType, bType := aVal.Type(), bVal.Type()
if aType != bType {
return -1 // No good answer possible, but don't return 0: they're not equal.
}
switch aVal.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
a, b := aVal.Int(), bVal.Int()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
a, b := aVal.Uint(), bVal.Uint()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.String:
a, b := aVal.String(), bVal.String()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Float32, reflect.Float64:
return floatCompare(aVal.Float(), bVal.Float())
case reflect.Complex64, reflect.Complex128:
a, b := aVal.Complex(), bVal.Complex()
if c := floatCompare(real(a), real(b)); c != 0 {
return c
}
return floatCompare(imag(a), imag(b))
case reflect.Bool:
a, b := aVal.Bool(), bVal.Bool()
switch {
case a == b:
return 0
case a:
return 1
default:
return -1
}
case reflect.Pointer, reflect.UnsafePointer:
a, b := aVal.Pointer(), bVal.Pointer()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Chan:
if c, ok := nilCompare(aVal, bVal); ok {
return c
}
ap, bp := aVal.Pointer(), bVal.Pointer()
switch {
case ap < bp:
return -1
case ap > bp:
return 1
default:
return 0
}
case reflect.Struct:
for i := 0; i < aVal.NumField(); i++ {
if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 {
return c
}
}
return 0
case reflect.Array:
for i := 0; i < aVal.Len(); i++ {
if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 {
return c
}
}
return 0
case reflect.Interface:
if c, ok := nilCompare(aVal, bVal); ok {
return c
}
c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
if c != 0 {
return c
}
return compare(aVal.Elem(), bVal.Elem())
default:
// Certain types cannot appear as keys (maps, funcs, slices), but be explicit.
panic("bad type in compare: " + aType.String())
}
}
// nilCompare checks whether either value is nil. If not, the boolean is false.
// If either value is nil, the boolean is true and the integer is the comparison
// value. The comparison is defined to be 0 if both are nil, otherwise the one
// nil value compares low. Both arguments must represent a chan, func,
// interface, map, pointer, or slice.
func nilCompare(aVal, bVal reflect.Value) (int, bool) {
if aVal.IsNil() {
if bVal.IsNil() {
return 0, true
}
return -1, true
}
if bVal.IsNil() {
return 1, true
}
return 0, false
}
// floatCompare compares two floating-point values. NaNs compare low.
func floatCompare(a, b float64) int {
switch {
case isNaN(a):
return -1 // No good answer if b is a NaN so don't bother checking.
case isNaN(b):
return 1
case a < b:
return -1
case a > b:
return 1
}
return 0
}
func isNaN(a float64) bool {
return a != a
}

View File

@@ -1,34 +0,0 @@
// 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.
// Simple conversions to avoid depending on strconv.
// llgo:skipall
package itoa
// Itoa converts val to a decimal string.
func Itoa(val int) string {
if val < 0 {
return "-" + Uitoa(uint(-val))
}
return Uitoa(uint(val))
}
// Uitoa converts val to a decimal string.
func Uitoa(val uint) string {
if val == 0 { // avoid string allocation
return "0"
}
var buf [20]byte // big enough for 64bit value base 10
i := len(buf) - 1
for val >= 10 {
q := val / 10
buf[i] = byte('0' + val - q*10)
i--
val = q
}
// val < 10
buf[i] = byte('0' + val)
return string(buf[i:])
}

View File

@@ -1,19 +0,0 @@
// Copyright 2019 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 oserror defines errors values used in the os package.
//
// These types are defined here to permit the syscall package to reference them.
package oserror
// llgo:skipall
import "errors"
var (
ErrInvalid = errors.New("invalid argument")
ErrPermission = errors.New("permission denied")
ErrExist = errors.New("file already exists")
ErrNotExist = errors.New("file does not exist")
ErrClosed = errors.New("file already closed")
)

View File

@@ -1 +0,0 @@
package race

View File

@@ -1,22 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package reflectlite
// llgo:skipall
import (
_ "unsafe"
)

View File

@@ -1,80 +0,0 @@
// Copyright 2016 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 reflectlite
import (
"unsafe"
)
const (
goarchPtrSize = unsafe.Sizeof(uintptr(0))
)
// Swapper returns a function that swaps the elements in the provided
// slice.
//
// Swapper panics if the provided interface is not a slice.
func Swapper(slice any) func(i, j int) {
v := ValueOf(slice)
if v.Kind() != Slice {
panic(&ValueError{Method: "Swapper", Kind: v.Kind()})
}
// Fast path for slices of size 0 and 1. Nothing to swap.
switch v.Len() {
case 0:
return func(i, j int) { panic("reflect: slice index out of range") }
case 1:
return func(i, j int) {
if i != 0 || j != 0 {
panic("reflect: slice index out of range")
}
}
}
typ := v.Type().Elem().common()
size := typ.Size()
hasPtr := typ.PtrBytes != 0
// Some common & small cases, without using memmove:
if hasPtr {
if size == goarchPtrSize {
ps := *(*[]unsafe.Pointer)(v.ptr)
return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
}
if typ.Kind() == String {
ss := *(*[]string)(v.ptr)
return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
}
} else {
switch size {
case 8:
is := *(*[]int64)(v.ptr)
return func(i, j int) { is[i], is[j] = is[j], is[i] }
case 4:
is := *(*[]int32)(v.ptr)
return func(i, j int) { is[i], is[j] = is[j], is[i] }
case 2:
is := *(*[]int16)(v.ptr)
return func(i, j int) { is[i], is[j] = is[j], is[i] }
case 1:
is := *(*[]int8)(v.ptr)
return func(i, j int) { is[i], is[j] = is[j], is[i] }
}
}
s := (*unsafeheaderSlice)(v.ptr)
tmp := unsafe_New(typ) // swap scratch space
return func(i, j int) {
if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) {
panic("reflect: slice index out of range")
}
val1 := arrayAt(s.Data, i, size, "i < s.Len")
val2 := arrayAt(s.Data, j, size, "j < s.Len")
typedmemmove(typ, tmp, val1)
typedmemmove(typ, val1, val2)
typedmemmove(typ, val2, tmp)
}
}

View File

@@ -1,565 +0,0 @@
// 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 reflectlite implements lightweight version of reflect, not using
// any package except for "runtime", "unsafe", and "internal/abi"
package reflectlite
import (
"unsafe"
"github.com/goplus/llgo/internal/abi"
)
// Type is the representation of a Go type.
//
// Not all methods apply to all kinds of types. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of type before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
//
// Type values are comparable, such as with the == operator,
// so they can be used as map keys.
// Two Type values are equal if they represent identical types.
type Type interface {
// Methods applicable to all types.
// Name returns the type's name within its package for a defined type.
// For other (non-defined) types it returns the empty string.
Name() string
// PkgPath returns a defined type's package path, that is, the import path
// that uniquely identifies the package, such as "encoding/base64".
// If the type was predeclared (string, error) or not defined (*T, struct{},
// []int, or A where A is an alias for a non-defined type), the package path
// will be the empty string.
PkgPath() string
// Size returns the number of bytes needed to store
// a value of the given type; it is analogous to unsafe.Sizeof.
Size() uintptr
// Kind returns the specific kind of this type.
Kind() Kind
// Implements reports whether the type implements the interface type u.
Implements(u Type) bool
// AssignableTo reports whether a value of the type is assignable to type u.
AssignableTo(u Type) bool
// Comparable reports whether values of this type are comparable.
Comparable() bool
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
// guaranteed to be unique among types. To test for type identity,
// compare the Types directly.
String() string
// Elem returns a type's element type.
// It panics if the type's Kind is not Ptr.
Elem() Type
common() *abi.Type
uncommon() *uncommonType
}
/*
* These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go).
* A few are known to ../runtime/type.go to convey to debuggers.
* They are also known to ../runtime/type.go.
*/
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
type Kind = abi.Kind
const Ptr = abi.Pointer
const (
// Import-and-export these constants as necessary
Interface = abi.Interface
Slice = abi.Slice
String = abi.String
Struct = abi.Struct
)
type rtype struct {
*abi.Type
}
// uncommonType is present only for defined types or types with methods
// (if T is a defined type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe a non-defined type with no methods.
type uncommonType = abi.UncommonType
// arrayType represents a fixed array type.
type arrayType = abi.ArrayType
// chanType represents a channel type.
type chanType = abi.ChanType
type funcType = abi.FuncType
type interfaceType = abi.InterfaceType
// mapType represents a map type.
type mapType struct {
rtype
Key *abi.Type // map key type
Elem *abi.Type // map element (value) type
Bucket *abi.Type // internal bucket structure
// function for hashing keys (ptr to key, seed) -> hash
Hasher func(unsafe.Pointer, uintptr) uintptr
KeySize uint8 // size of key slot
ValueSize uint8 // size of value slot
BucketSize uint16 // size of bucket
Flags uint32
}
// ptrType represents a pointer type.
type ptrType = abi.PtrType
// sliceType represents a slice type.
type sliceType = abi.SliceType
// structType represents a struct type.
type structType = abi.StructType
func (t rtype) uncommon() *uncommonType {
return t.Uncommon()
}
func (t rtype) String() string {
return t.Type.String()
}
func (t rtype) common() *abi.Type { return t.Type }
func (t rtype) exportedMethods() []abi.Method {
ut := t.uncommon()
if ut == nil {
return nil
}
return ut.ExportedMethods()
}
func (t rtype) NumMethod() int {
/*
tt := t.Type.InterfaceType()
if tt != nil {
return tt.NumMethod()
}
return len(t.exportedMethods())
*/
panic("todo: reflectlite.rtype.NumMethod")
}
func (t rtype) PkgPath() string {
/*
if t.TFlag&abi.TFlagNamed == 0 {
return ""
}
ut := t.uncommon()
if ut == nil {
return ""
}
return t.nameOff(ut.PkgPath).Name()
*/
panic("todo: reflectlite.rtype.PkgPath")
}
func (t rtype) Name() string {
/*
if !t.HasName() {
return ""
}
s := t.String()
i := len(s) - 1
sqBrackets := 0
for i >= 0 && (s[i] != '.' || sqBrackets != 0) {
switch s[i] {
case ']':
sqBrackets++
case '[':
sqBrackets--
}
i--
}
return s[i+1:]
*/
panic("todo: reflectlite.rtype.Name")
}
func toRType(t *abi.Type) rtype {
return rtype{t}
}
func elem(t *abi.Type) *abi.Type {
et := t.Elem()
if et != nil {
return et
}
panic("reflect: Elem of invalid type " + toRType(t).String())
}
func (t rtype) Elem() Type {
return toType(elem(t.common()))
}
func (t rtype) In(i int) Type {
/*
tt := t.Type.FuncType()
if tt == nil {
panic("reflect: In of non-func type")
}
return toType(tt.InSlice()[i])
*/
panic("todo: reflectlite.rtype.In")
}
func (t rtype) Key() Type {
tt := t.Type.MapType()
if tt == nil {
panic("reflect: Key of non-map type")
}
return toType(tt.Key)
}
func (t rtype) Len() int {
tt := t.Type.ArrayType()
if tt == nil {
panic("reflect: Len of non-array type")
}
return int(tt.Len)
}
func (t rtype) NumField() int {
tt := t.Type.StructType()
if tt == nil {
panic("reflect: NumField of non-struct type")
}
return len(tt.Fields)
}
func (t rtype) NumIn() int {
/*
tt := t.Type.FuncType()
if tt == nil {
panic("reflect: NumIn of non-func type")
}
return int(tt.InCount)
*/
panic("todo: reflectlite.rtype.NumIn")
}
func (t rtype) NumOut() int {
/*
tt := t.Type.FuncType()
if tt == nil {
panic("reflect: NumOut of non-func type")
}
return tt.NumOut()
*/
panic("todo: reflectlite.rtype.NumOut")
}
func (t rtype) Out(i int) Type {
/*
tt := t.Type.FuncType()
if tt == nil {
panic("reflect: Out of non-func type")
}
return toType(tt.OutSlice()[i])
*/
panic("todo: reflectlite.rtype.Out")
}
// add returns p+x.
//
// The whySafe string is ignored, so that the function still inlines
// as efficiently as p+x, but all call sites should use the string to
// record why the addition is safe, which is to say why the addition
// does not cause x to advance to the very end of p's allocation
// and therefore point incorrectly at the next block in memory.
func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
return unsafe.Pointer(uintptr(p) + x)
}
// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i any) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ)
}
func (t rtype) Implements(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.Implements")
}
if u.Kind() != Interface {
panic("reflect: non-interface type passed to Type.Implements")
}
return implements(u.common(), t.common())
}
func (t rtype) AssignableTo(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.AssignableTo")
}
uu := u.common()
tt := t.common()
return directlyAssignable(uu, tt) || implements(uu, tt)
}
func (t rtype) Comparable() bool {
return t.Equal != nil
}
// implements reports whether the type V implements the interface type T.
func implements(T, V *abi.Type) bool {
/*
t := T.InterfaceType()
if t == nil {
return false
}
if len(t.Methods) == 0 {
return true
}
rT := toRType(T)
rV := toRType(V)
// The same algorithm applies in both cases, but the
// method tables for an interface type and a concrete type
// are different, so the code is duplicated.
// In both cases the algorithm is a linear scan over the two
// lists - T's methods and V's methods - simultaneously.
// Since method tables are stored in a unique sorted order
// (alphabetical, with no duplicate method names), the scan
// through V's methods must hit a match for each of T's
// methods along the way, or else V does not implement T.
// This lets us run the scan in overall linear time instead of
// the quadratic time a naive search would require.
// See also ../runtime/iface.go.
if V.Kind() == Interface {
v := (*interfaceType)(unsafe.Pointer(V))
i := 0
for j := 0; j < len(v.Methods); j++ {
tm := &t.Methods[i]
tmName := rT.nameOff(tm.Name)
vm := &v.Methods[j]
vmName := rV.nameOff(vm.Name)
if vmName.Name() == tmName.Name() && rV.typeOff(vm.Typ) == rT.typeOff(tm.Typ) {
if !tmName.IsExported() {
tmPkgPath := pkgPath(tmName)
if tmPkgPath == "" {
tmPkgPath = t.PkgPath.Name()
}
vmPkgPath := pkgPath(vmName)
if vmPkgPath == "" {
vmPkgPath = v.PkgPath.Name()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i++; i >= len(t.Methods) {
return true
}
}
}
return false
}
v := V.Uncommon()
if v == nil {
return false
}
i := 0
vmethods := v.Methods()
for j := 0; j < int(v.Mcount); j++ {
tm := &t.Methods[i]
tmName := rT.nameOff(tm.Name)
vm := vmethods[j]
vmName := rV.nameOff(vm.Name)
if vmName.Name() == tmName.Name() && rV.typeOff(vm.Mtyp) == rT.typeOff(tm.Typ) {
if !tmName.IsExported() {
tmPkgPath := pkgPath(tmName)
if tmPkgPath == "" {
tmPkgPath = t.PkgPath.Name()
}
vmPkgPath := pkgPath(vmName)
if vmPkgPath == "" {
vmPkgPath = rV.nameOff(v.PkgPath).Name()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i++; i >= len(t.Methods) {
return true
}
}
}
return false
*/
panic("todo: reflectlite.implements")
}
// directlyAssignable reports whether a value x of type V can be directly
// assigned (using memmove) to a value of type T.
// https://golang.org/doc/go_spec.html#Assignability
// Ignoring the interface rules (implemented elsewhere)
// and the ideal constant rules (no ideal constants at run time).
func directlyAssignable(T, V *abi.Type) bool {
// x's type V is identical to T?
if T == V {
return true
}
// Otherwise at least one of T and V must not be defined
// and they must have the same kind.
if T.HasName() && V.HasName() || T.Kind() != V.Kind() {
return false
}
// x's type T and V must have identical underlying types.
return haveIdenticalUnderlyingType(T, V, true)
}
func haveIdenticalType(T, V *abi.Type, cmpTags bool) bool {
if cmpTags {
return T == V
}
if toRType(T).Name() != toRType(V).Name() || T.Kind() != V.Kind() {
return false
}
return haveIdenticalUnderlyingType(T, V, false)
}
func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool {
if T == V {
return true
}
kind := T.Kind()
if kind != V.Kind() {
return false
}
// Non-composite types of equal kind have same underlying type
// (the predefined instance of the type).
if abi.Bool <= kind && kind <= abi.Complex128 || kind == abi.String || kind == abi.UnsafePointer {
return true
}
/*
// Composite types.
switch kind {
case abi.Array:
return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case abi.Chan:
// Special case:
// x is a bidirectional channel value, T is a channel type,
// and x's type V and T have identical element types.
if V.ChanDir() == abi.BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) {
return true
}
// Otherwise continue test for identical underlying type.
return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case abi.Func:
t := (*funcType)(unsafe.Pointer(T))
v := (*funcType)(unsafe.Pointer(V))
if t.OutCount != v.OutCount || t.InCount != v.InCount {
return false
}
for i := 0; i < t.NumIn(); i++ {
if !haveIdenticalType(t.In(i), v.In(i), cmpTags) {
return false
}
}
for i := 0; i < t.NumOut(); i++ {
if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) {
return false
}
}
return true
case Interface:
t := (*interfaceType)(unsafe.Pointer(T))
v := (*interfaceType)(unsafe.Pointer(V))
if len(t.Methods) == 0 && len(v.Methods) == 0 {
return true
}
// Might have the same methods but still
// need a run time conversion.
return false
case abi.Map:
return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Ptr, abi.Slice:
return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case abi.Struct:
t := (*structType)(unsafe.Pointer(T))
v := (*structType)(unsafe.Pointer(V))
if len(t.Fields) != len(v.Fields) {
return false
}
if t.PkgPath.Name() != v.PkgPath.Name() {
return false
}
for i := range t.Fields {
tf := &t.Fields[i]
vf := &v.Fields[i]
if tf.Name.Name() != vf.Name.Name() {
return false
}
if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) {
return false
}
if cmpTags && tf.Name.Tag() != vf.Name.Tag() {
return false
}
if tf.Offset != vf.Offset {
return false
}
if tf.Embedded() != vf.Embedded() {
return false
}
}
return true
}
return false
*/
panic("todo: reflectlite.haveIdenticalUnderlyingType")
}
// toType converts from a *rtype to a Type that can be returned
// to the client of package reflect. In gc, the only concern is that
// a nil *rtype must be replaced by a nil Type, but in gccgo this
// function takes care of ensuring that multiple *rtype for the same
// type are coalesced into a single Type.
func toType(t *abi.Type) Type {
if t == nil {
return nil
}
return toRType(t)
}
// ifaceIndir reports whether t is stored indirectly in an interface value.
func ifaceIndir(t *abi.Type) bool {
return t.Kind_&abi.KindDirectIface == 0
}

View File

@@ -1,32 +0,0 @@
// Copyright 2020 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 reflectlite
import (
"unsafe"
)
// unsafeheaderSlice is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
//
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
// data it references will not be garbage collected.
type unsafeheaderSlice struct {
Data unsafe.Pointer
Len int
Cap int
}
// unsafeheaderString is the runtime representation of a string.
// It cannot be used safely or portably and its representation may
// change in a later release.
//
// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the
// data it references will not be garbage collected.
type unsafeheaderString struct {
Data unsafe.Pointer
Len int
}

View File

@@ -1,477 +0,0 @@
// 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 reflectlite
import (
"unsafe"
"github.com/goplus/llgo/internal/abi"
_ "github.com/goplus/llgo/internal/runtime"
)
// Value is the reflection interface to a Go value.
//
// Not all methods apply to all kinds of values. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of value before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run time panic.
//
// The zero Value represents no value.
// Its IsValid method returns false, its Kind method returns Invalid,
// its String method returns "<invalid Value>", and all other methods panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
//
// A Value can be used concurrently by multiple goroutines provided that
// the underlying Go value can be used concurrently for the equivalent
// direct operations.
//
// To compare two Values, compare the results of the Interface method.
// Using == on two Values does not compare the underlying values
// they represent.
type Value struct {
// typ holds the type of the value represented by a Value.
typ *abi.Type
// Pointer-valued data or, if flagIndir is set, pointer to data.
// Valid when either flagIndir is set or typ.pointers() is true.
ptr unsafe.Pointer
// flag holds metadata about the value.
// The lowest bits are flag bits:
// - flagStickyRO: obtained via unexported not embedded field, so read-only
// - flagEmbedRO: obtained via unexported embedded field, so read-only
// - flagIndir: val holds a pointer to the data
// - flagAddr: v.CanAddr is true (implies flagIndir)
// Value cannot represent method values.
// The next five bits give the Kind of the value.
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
// If ifaceIndir(typ), code can assume that flagIndir is set.
flag
// A method value represents a curried method invocation
// like r.Read for some receiver r. The typ+val+flag bits describe
// the receiver r, but the flag's Kind bits say Func (methods are
// functions), and the top bits of the flag give the method number
// in r's type's method table.
}
type flag uintptr
const (
flagKindWidth = 5 // there are 27 kinds
flagKindMask flag = 1<<flagKindWidth - 1
flagStickyRO flag = 1 << 5
flagEmbedRO flag = 1 << 6
flagIndir flag = 1 << 7
flagAddr flag = 1 << 8
flagMethod flag = 1 << 9
flagMethodShift = 10
flagRO flag = flagStickyRO | flagEmbedRO
)
func (f flag) kind() Kind {
return Kind(f & flagKindMask)
}
func (f flag) ro() flag {
if f&flagRO != 0 {
return flagStickyRO
}
return 0
}
// pointer returns the underlying pointer represented by v.
// v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointer
func (v Value) pointer() unsafe.Pointer {
/*
if v.typ.Size() != goarch.PtrSize || !v.typ.Pointers() {
panic("can't call pointer on a non-pointer Value")
}
if v.flag&flagIndir != 0 {
return *(*unsafe.Pointer)(v.ptr)
}
return v.ptr
*/
panic("todo: reflectlite.Value.pointer")
}
// packEface converts v to the empty interface.
func packEface(v Value) any {
t := v.typ
var i any
e := (*emptyInterface)(unsafe.Pointer(&i))
// First, fill in the data portion of the interface.
switch {
case ifaceIndir(t):
if v.flag&flagIndir == 0 {
panic("bad indir")
}
// Value is indirect, and so is the interface we're making.
ptr := v.ptr
if v.flag&flagAddr != 0 {
// TODO: pass safe boolean from valueInterface so
// we don't need to copy if safe==true?
c := unsafe_New(t)
typedmemmove(t, c, ptr)
ptr = c
}
e.word = ptr
case v.flag&flagIndir != 0:
// Value is indirect, but interface is direct. We need
// to load the data at v.ptr into the interface data word.
e.word = *(*unsafe.Pointer)(v.ptr)
default:
// Value is direct, and so is the interface.
e.word = v.ptr
}
// Now, fill in the type portion. We're very careful here not
// to have any operation between the e.word and e.typ assignments
// that would let the garbage collector observe the partially-built
// interface value.
e.typ = t
return i
}
// unpackEface converts the empty interface i to a Value.
func unpackEface(i any) Value {
e := (*emptyInterface)(unsafe.Pointer(&i))
// NOTE: don't read e.word until we know whether it is really a pointer or not.
t := e.typ
if t == nil {
return Value{}
}
f := flag(t.Kind())
if ifaceIndir(t) {
f |= flagIndir
}
return Value{t, e.word, f}
}
// A ValueError occurs when a Value method is invoked on
// a Value that does not support it. Such cases are documented
// in the description of each method.
type ValueError struct {
Method string
Kind Kind
}
func (e *ValueError) Error() string {
if e.Kind == 0 {
return "reflect: call of " + e.Method + " on zero Value"
}
return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
}
// methodName returns the name of the calling method,
// assumed to be two stack frames above.
func methodName() string {
/* TODO(xsw):
pc, _, _, _ := runtime.Caller(2)
f := runtime.FuncForPC(pc)
if f == nil {
return "unknown method"
}
return f.Name()
*/
return "unknown method"
}
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *abi.Type
word unsafe.Pointer
}
// mustBeExported panics if f records that the value was obtained using
// an unexported field.
func (f flag) mustBeExported() {
if f == 0 {
panic(&ValueError{methodName(), 0})
}
if f&flagRO != 0 {
panic("reflect: " + methodName() + " using value obtained using unexported field")
}
}
// mustBeAssignable panics if f records that the value is not assignable,
// which is to say that either it was obtained using an unexported field
// or it is not addressable.
func (f flag) mustBeAssignable() {
if f == 0 {
panic(&ValueError{methodName(), abi.Invalid})
}
// Assignable if addressable and not read-only.
if f&flagRO != 0 {
panic("reflect: " + methodName() + " using value obtained using unexported field")
}
if f&flagAddr == 0 {
panic("reflect: " + methodName() + " using unaddressable value")
}
}
// CanSet reports whether the value of v can be changed.
// A Value can be changed only if it is addressable and was not
// obtained by the use of unexported struct fields.
// If CanSet returns false, calling Set or any type-specific
// setter (e.g., SetBool, SetInt) will panic.
func (v Value) CanSet() bool {
return v.flag&(flagAddr|flagRO) == flagAddr
}
// Elem returns the value that the interface v contains
// or that the pointer v points to.
// It panics if v's Kind is not Interface or Pointer.
// It returns the zero Value if v is nil.
func (v Value) Elem() Value {
/*
k := v.kind()
switch k {
case abi.Interface:
var eface any
if v.typ.NumMethod() == 0 {
eface = *(*any)(v.ptr)
} else {
eface = (any)(*(*interface {
M()
})(v.ptr))
}
x := unpackEface(eface)
if x.flag != 0 {
x.flag |= v.flag.ro()
}
return x
case abi.Pointer:
ptr := v.ptr
if v.flag&flagIndir != 0 {
ptr = *(*unsafe.Pointer)(ptr)
}
// The returned value's address is v's value.
if ptr == nil {
return Value{}
}
tt := (*ptrType)(unsafe.Pointer(v.typ))
typ := tt.Elem
fl := v.flag&flagRO | flagIndir | flagAddr
fl |= flag(typ.Kind())
return Value{typ, ptr, fl}
}
panic(&ValueError{"reflectlite.Value.Elem", v.kind()})
*/
panic("todo: reflectlite.Value.Elem")
}
func valueInterface(v Value) any {
if v.flag == 0 {
panic(&ValueError{"reflectlite.Value.Interface", 0})
}
if v.kind() == abi.Interface {
// Special case: return the element inside the interface.
// Empty interface has one layout, all interfaces with
// methods have a second layout.
if v.numMethod() == 0 {
return *(*any)(v.ptr)
}
return *(*interface {
M()
})(v.ptr)
}
// TODO: pass safe to packEface so we don't need to copy if safe==true?
return packEface(v)
}
// IsNil reports whether its argument v is nil. The argument must be
// a chan, func, interface, map, pointer, or slice value; if it is
// not, IsNil panics. Note that IsNil is not always equivalent to a
// regular comparison with nil in Go. For example, if v was created
// by calling ValueOf with an uninitialized interface variable i,
// i==nil will be true but v.IsNil will panic as v will be the zero
// Value.
func (v Value) IsNil() bool {
k := v.kind()
switch k {
case abi.Chan, abi.Func, abi.Map, abi.Pointer, abi.UnsafePointer:
// if v.flag&flagMethod != 0 {
// return false
// }
ptr := v.ptr
if v.flag&flagIndir != 0 {
ptr = *(*unsafe.Pointer)(ptr)
}
return ptr == nil
case abi.Interface, abi.Slice:
// Both interface and slice are nil if first word is 0.
// Both are always bigger than a word; assume flagIndir.
return *(*unsafe.Pointer)(v.ptr) == nil
}
panic(&ValueError{"reflectlite.Value.IsNil", v.kind()})
}
// IsValid reports whether v represents a value.
// It returns false if v is the zero Value.
// If IsValid returns false, all other methods except String panic.
// Most functions and methods never return an invalid Value.
// If one does, its documentation states the conditions explicitly.
func (v Value) IsValid() bool {
return v.flag != 0
}
// Kind returns v's Kind.
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
func (v Value) Kind() Kind {
return v.kind()
}
/* TODO(xsw):
// implemented in runtime:
func chanlen(unsafe.Pointer) int
func maplen(unsafe.Pointer) int
*/
// Len returns v's length.
// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
func (v Value) Len() int {
k := v.kind()
switch k {
case abi.Slice:
// Slice is bigger than a word; assume flagIndir.
return (*unsafeheaderSlice)(v.ptr).Len
case abi.String:
// String is bigger than a word; assume flagIndir.
return (*unsafeheaderString)(v.ptr).Len
case abi.Array:
tt := (*arrayType)(unsafe.Pointer(v.typ))
return int(tt.Len)
/* TODO(xsw):
case abi.Chan:
return chanlen(v.pointer())
case abi.Map:
return maplen(v.pointer())
*/
}
panic(&ValueError{"reflect.Value.Len", v.kind()})
}
// NumMethod returns the number of exported methods in the value's method set.
func (v Value) numMethod() int {
/*
if v.typ == nil {
panic(&ValueError{"reflectlite.Value.NumMethod", abi.Invalid})
}
return v.typ.NumMethod()
*/
panic("todo: reflectlite.Value.numMethod")
}
// Set assigns x to the value v.
// It panics if CanSet returns false.
// As in Go, x's value must be assignable to v's type.
func (v Value) Set(x Value) {
v.mustBeAssignable()
x.mustBeExported() // do not let unexported x leak
var target unsafe.Pointer
if v.kind() == abi.Interface {
target = v.ptr
}
x = x.assignTo("reflectlite.Set", v.typ, target)
if x.flag&flagIndir != 0 {
typedmemmove(v.typ, v.ptr, x.ptr)
} else {
*(*unsafe.Pointer)(v.ptr) = x.ptr
}
}
// Type returns v's type.
func (v Value) Type() Type {
f := v.flag
if f == 0 {
panic(&ValueError{"reflectlite.Value.Type", abi.Invalid})
}
// Method values not supported.
return toRType(v.typ)
}
/*
* constructors
*/
//go:linkname unsafe_New github.com/goplus/llgo/internal/runtime.New
func unsafe_New(*abi.Type) unsafe.Pointer
// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i any) Value {
if i == nil {
return Value{}
}
return unpackEface(i)
}
// assignTo returns a value v that can be assigned directly to typ.
// It panics if v is not assignable to typ.
// For a conversion to an interface type, target is a suggested scratch space to use.
func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Value {
// if v.flag&flagMethod != 0 {
// v = makeMethodValue(context, v)
// }
switch {
case directlyAssignable(dst, v.typ):
// Overwrite type so that they match.
// Same memory layout, so no harm done.
fl := v.flag&(flagAddr|flagIndir) | v.flag.ro()
fl |= flag(dst.Kind())
return Value{dst, v.ptr, fl}
case implements(dst, v.typ):
if target == nil {
target = unsafe_New(dst)
}
if v.Kind() == abi.Interface && v.IsNil() {
// A nil ReadWriter passed to nil Reader is OK,
// but using ifaceE2I below will panic.
// Avoid the panic by returning a nil dst (e.g., Reader) explicitly.
return Value{dst, nil, flag(abi.Interface)}
}
/* TODO(xsw):
x := valueInterface(v)
if dst.NumMethod() == 0 {
*(*any)(target) = x
} else {
ifaceE2I(dst, x, target)
}
return Value{dst, target, flagIndir | flag(abi.Interface)}
*/
}
// Failed.
// TODO(xsw):
// panic(context + ": value of type " + toRType(v.typ).String() + " is not assignable to type " + toRType(dst).String())
panic("todo: reflectlite.Value.assignTo")
}
// arrayAt returns the i-th element of p,
// an array whose elements are eltSize bytes wide.
// The array pointed at by p must have at least i+1 elements:
// it is invalid (but impossible to check here) to pass i >= len,
// because then the result will point outside the array.
// whySafe must explain why i < len. (Passing "i < len" is fine;
// the benefit is to surface this assumption at the call site.)
func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer {
return add(p, uintptr(i)*eltSize, "i < len")
}
// func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer)
// typedmemmove copies a value of type t to dst from src.
//
//go:linkname typedmemmove github.com/goplus/llgo/internal/runtime.Typedmemmove
func typedmemmove(t *abi.Type, dst, src unsafe.Pointer)

View File

@@ -1 +0,0 @@
package stringslite

View File

@@ -1,20 +0,0 @@
// Copyright 2020 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:build !windows
package execenv
// llgo:skipall
import "syscall"
// Default will return the default environment
// variables based on the process attributes
// provided.
//
// Defaults to syscall.Environ() on all platforms
// other than Windows.
func Default(sys *syscall.SysProcAttr) ([]string, error) {
return syscall.Environ(), nil
}

View File

@@ -1,48 +0,0 @@
// Copyright 2020 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:build windows
package execenv
// llgo:skipall
import (
"internal/syscall/windows"
"syscall"
"unsafe"
)
// Default will return the default environment
// variables based on the process attributes
// provided.
//
// If the process attributes contain a token, then
// the environment variables will be sourced from
// the defaults for that user token, otherwise they
// will be sourced from syscall.Environ().
func Default(sys *syscall.SysProcAttr) (env []string, err error) {
if sys == nil || sys.Token == 0 {
return syscall.Environ(), nil
}
var blockp *uint16
err = windows.CreateEnvironmentBlock(&blockp, sys.Token, false)
if err != nil {
return nil, err
}
defer windows.DestroyEnvironmentBlock(blockp)
const size = unsafe.Sizeof(*blockp)
for *blockp != 0 { // environment block ends with empty string
// find NUL terminator
end := unsafe.Add(unsafe.Pointer(blockp), size)
for *(*uint16)(end) != 0 {
end = unsafe.Add(end, size)
}
entry := unsafe.Slice(blockp, (uintptr(end)-uintptr(unsafe.Pointer(blockp)))/2)
env = append(env, syscall.UTF16ToString(entry))
blockp = (*uint16)(unsafe.Add(end, size))
}
return
}

View File

@@ -1,15 +0,0 @@
// Copyright 2018 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:build js && wasm
package unix
func IsNonblock(fd int) (nonblocking bool, err error) {
return false, nil
}
func HasNonblockFlag(flag int) bool {
return false
}

View File

@@ -1,23 +0,0 @@
// Copyright 2018 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:build unix
package unix
import "github.com/goplus/llgo/c/syscall"
/* TODO(xsw):
func IsNonblock(fd int) (nonblocking bool, err error) {
flag, e1 := Fcntl(fd, syscall.F_GETFL, 0)
if e1 != nil {
return false, e1
}
return flag&syscall.O_NONBLOCK != 0, nil
}
*/
func HasNonblockFlag(flag int) bool {
return flag&syscall.O_NONBLOCK != 0
}

View File

@@ -1,37 +0,0 @@
// 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:build wasip1
package unix
import "github.com/goplus/llgo/c/syscall"
/* TODO(xsw):
import (
"syscall"
_ "unsafe" // for go:linkname
)
func IsNonblock(fd int) (nonblocking bool, err error) {
flags, e1 := fd_fdstat_get_flags(fd)
if e1 != nil {
return false, e1
}
return flags&syscall.FDFLAG_NONBLOCK != 0, nil
}
*/
func HasNonblockFlag(flag int) bool {
return flag&syscall.FDFLAG_NONBLOCK != 0
}
/* TODO(xsw):
// This helper is implemented in the syscall package. It means we don't have
// to redefine the fd_fdstat_get host import or the fdstat struct it
// populates.
//
//-go:linkname fd_fdstat_get_flags syscall.fd_fdstat_get_flags
func fd_fdstat_get_flags(fd int) (uint32, error)
*/

View File

@@ -1,22 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package unix
// llgo:skipall
import (
_ "unsafe"
)

View File

@@ -1,207 +0,0 @@
// 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.
// Pipe adapter to connect code expecting an io.Reader
// with code expecting an io.Writer.
package io
import (
"errors"
"io"
"sync"
)
// onceError is an object that will only store an error once.
type onceError struct {
sync.Mutex // guards following
err error
}
func (a *onceError) Store(err error) {
a.Lock()
defer a.Unlock()
if a.err != nil {
return
}
a.err = err
}
func (a *onceError) Load() error {
a.Lock()
defer a.Unlock()
return a.err
}
// ErrClosedPipe is the error used for read or write operations on a closed pipe.
var ErrClosedPipe = errors.New("io: read/write on closed pipe")
// A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
type pipe struct {
wrMu sync.Mutex // Serializes Write operations
wrCh chan []byte
rdCh chan int
once sync.Once // Protects closing done
done chan struct{}
rerr onceError
werr onceError
}
func (p *pipe) read(b []byte) (n int, err error) {
select {
case <-p.done:
return 0, p.readCloseError()
default:
}
select {
case bw := <-p.wrCh:
nr := copy(b, bw)
p.rdCh <- nr
return nr, nil
case <-p.done:
return 0, p.readCloseError()
}
}
func (p *pipe) closeRead(err error) error {
if err == nil {
err = ErrClosedPipe
}
p.rerr.Store(err)
p.once.Do(func() { close(p.done) })
return nil
}
func (p *pipe) write(b []byte) (n int, err error) {
select {
case <-p.done:
return 0, p.writeCloseError()
default:
p.wrMu.Lock()
defer p.wrMu.Unlock()
}
for once := true; once || len(b) > 0; once = false {
select {
case p.wrCh <- b:
nw := <-p.rdCh
b = b[nw:]
n += nw
case <-p.done:
return n, p.writeCloseError()
}
}
return n, nil
}
func (p *pipe) closeWrite(err error) error {
if err == nil {
err = io.EOF
}
p.werr.Store(err)
p.once.Do(func() { close(p.done) })
return nil
}
// readCloseError is considered internal to the pipe type.
func (p *pipe) readCloseError() error {
rerr := p.rerr.Load()
if werr := p.werr.Load(); rerr == nil && werr != nil {
return werr
}
return ErrClosedPipe
}
// writeCloseError is considered internal to the pipe type.
func (p *pipe) writeCloseError() error {
werr := p.werr.Load()
if rerr := p.rerr.Load(); werr == nil && rerr != nil {
return rerr
}
return ErrClosedPipe
}
// A PipeReader is the read half of a pipe.
type PipeReader struct {
p *pipe
}
// Read implements the standard Read interface:
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
// returned as err; otherwise err is EOF.
func (r *PipeReader) Read(data []byte) (n int, err error) {
return r.p.read(data)
}
// Close closes the reader; subsequent writes to the
// write half of the pipe will return the error ErrClosedPipe.
func (r *PipeReader) Close() error {
return r.CloseWithError(nil)
}
// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
//
// CloseWithError never overwrites the previous error if it exists
// and always returns nil.
func (r *PipeReader) CloseWithError(err error) error {
return r.p.closeRead(err)
}
// A PipeWriter is the write half of a pipe.
type PipeWriter struct {
p *pipe
}
// Write implements the standard Write interface:
// it writes data to the pipe, blocking until one or more readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is ErrClosedPipe.
func (w *PipeWriter) Write(data []byte) (n int, err error) {
return w.p.write(data)
}
// Close closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and EOF.
func (w *PipeWriter) Close() error {
return w.CloseWithError(nil)
}
// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err,
// or EOF if err is nil.
//
// CloseWithError never overwrites the previous error if it exists
// and always returns nil.
func (w *PipeWriter) CloseWithError(err error) error {
return w.p.closeWrite(err)
}
// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
//
// Reads and Writes on the pipe are matched one to one
// except when multiple Reads are needed to consume a single Write.
// That is, each Write to the PipeWriter blocks until it has satisfied
// one or more Reads from the PipeReader that fully consume
// the written data.
// The data is copied directly from the Write to the corresponding
// Read (or Reads); there is no internal buffering.
//
// It is safe to call Read and Write in parallel with each other or with Close.
// Parallel calls to Read and parallel calls to Write are also safe:
// the individual calls will be gated sequentially.
func Pipe() (*PipeReader, *PipeWriter) {
p := &pipe{
wrCh: make(chan []byte, 1),
rdCh: make(chan int, 1),
done: make(chan struct{}, 1),
}
return &PipeReader{p}, &PipeWriter{p}
}

View File

@@ -1 +0,0 @@
package iter

View File

@@ -1,456 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package big
// llgo:skipall
import (
"math/rand"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
// A Word represents a single digit of a multi-precision unsigned integer.
type Word openssl.BN_ULONG
// -----------------------------------------------------------------------------
// TODO(xsw): share ctx
func ctxGet() *openssl.BN_CTX {
return openssl.BN_CTXNew()
}
func ctxPut(ctx *openssl.BN_CTX) {
ctx.Free()
}
// -----------------------------------------------------------------------------
type Int openssl.BIGNUM
// Sign returns:
//
// -1 if x < 0
// 0 if x == 0
// +1 if x > 0
func (x *Int) Sign() int {
a := (*openssl.BIGNUM)(x)
if a.IsNegative() != 0 {
return -1
} else if a.IsZero() != 0 {
return 0
}
return 1
}
// SetInt64 sets z to x and returns z.
func (z *Int) SetInt64(x int64) *Int {
a := (*openssl.BIGNUM)(z)
if x < 0 {
a.SetWord(openssl.BN_ULONG(-x))
a.SetNegative(1)
} else {
a.SetWord(openssl.BN_ULONG(x))
a.SetNegative(0)
}
return z
}
// SetUint64 sets z to x and returns z.
func (z *Int) SetUint64(x uint64) *Int {
a := (*openssl.BIGNUM)(z)
a.SetWord(openssl.BN_ULONG(x))
a.SetNegative(0)
return z
}
// NewInt allocates and returns a new Int set to x.
func NewInt(x int64) *Int {
z := (*Int)(openssl.BNNew())
return z.SetInt64(x)
}
// Set sets z to x and returns z.
func (z *Int) Set(x *Int) *Int {
if z != x {
a := (*openssl.BIGNUM)(z)
b := (*openssl.BIGNUM)(x)
a.Copy(b)
}
return z
}
// Abs sets z to |x| (the absolute value of x) and returns z.
func (z *Int) Abs(x *Int) *Int {
z.Set(x)
a := (*openssl.BIGNUM)(z)
a.SetNegative(0)
return z
}
// Neg sets z to -x and returns z.
func (z *Int) Neg(x *Int) *Int {
z.Set(x)
a := (*openssl.BIGNUM)(z)
if a.IsNegative() != 0 {
a.SetNegative(0)
} else {
a.SetNegative(1)
}
return z
}
// Bits provides raw (unchecked but fast) access to x by returning its
// absolute value as a little-endian Word slice. The result and x share
// the same underlying array.
// Bits is intended to support implementation of missing low-level Int
// functionality outside this package; it should be avoided otherwise.
func (x *Int) Bits() []Word {
panic("todo big.Bits")
}
// SetBits provides raw (unchecked but fast) access to z by setting its
// value to abs, interpreted as a little-endian Word slice, and returning
// z. The result and abs share the same underlying array.
// SetBits is intended to support implementation of missing low-level Int
// functionality outside this package; it should be avoided otherwise.
func (z *Int) SetBits(abs []Word) *Int {
panic("todo big.SetBits")
}
// Add sets z to the sum x+y and returns z.
func (z *Int) Add(x, y *Int) *Int {
(*openssl.BIGNUM)(z).Add((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y))
return z
}
// Sub sets z to the difference x-y and returns z.
func (z *Int) Sub(x, y *Int) *Int {
(*openssl.BIGNUM)(z).Sub((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y))
return z
}
// Mul sets z to the product x*y and returns z.
func (z *Int) Mul(x, y *Int) *Int {
panic("todo big.Mul")
}
// MulRange sets z to the product of all integers
// in the range [a, b] inclusively and returns z.
// If a > b (empty range), the result is 1.
func (z *Int) MulRange(a, b int64) *Int {
panic("todo big.MulRange")
}
// Binomial sets z to the binomial coefficient C(n, k) and returns z.
func (z *Int) Binomial(n, k int64) *Int {
panic("todo big.Binomial")
}
// Quo sets z to the quotient x/y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Quo implements truncated division (like Go); see QuoRem for more details.
func (z *Int) Quo(x, y *Int) *Int {
panic("todo big.Quo")
}
// Rem sets z to the remainder x%y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Rem implements truncated modulus (like Go); see QuoRem for more details.
func (z *Int) Rem(x, y *Int) *Int {
panic("todo big.Rem")
}
// QuoRem sets z to the quotient x/y and r to the remainder x%y
// and returns the pair (z, r) for y != 0.
// If y == 0, a division-by-zero run-time panic occurs.
//
// QuoRem implements T-division and modulus (like Go):
//
// q = x/y with the result truncated to zero
// r = x - y*q
//
// (See Daan Leijen, “Division and Modulus for Computer Scientists”.)
// See DivMod for Euclidean division and modulus (unlike Go).
func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
panic("todo big.QuoRem")
}
// Div sets z to the quotient x/y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Div implements Euclidean division (unlike Go); see DivMod for more details.
func (z *Int) Div(x, y *Int) *Int {
panic("todo big.Div")
}
// Mod sets z to the modulus x%y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
func (z *Int) Mod(x, y *Int) *Int {
panic("todo big.Mod")
}
// DivMod sets z to the quotient x div y and m to the modulus x mod y
// and returns the pair (z, m) for y != 0.
// If y == 0, a division-by-zero run-time panic occurs.
//
// DivMod implements Euclidean division and modulus (unlike Go):
//
// q = x div y such that
// m = x - y*q with 0 <= m < |y|
//
// (See Raymond T. Boute, “The Euclidean definition of the functions
// div and mod”. ACM Transactions on Programming Languages and
// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
// ACM press.)
// See QuoRem for T-division and modulus (like Go).
func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
panic("big.DivMod")
}
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
func (x *Int) Cmp(y *Int) (r int) {
return int((*openssl.BIGNUM)(x).Cmp((*openssl.BIGNUM)(y)))
}
// CmpAbs compares the absolute values of x and y and returns:
//
// -1 if |x| < |y|
// 0 if |x| == |y|
// +1 if |x| > |y|
func (x *Int) CmpAbs(y *Int) int {
return int((*openssl.BIGNUM)(x).Ucmp((*openssl.BIGNUM)(y)))
}
// Int64 returns the int64 representation of x.
// If x cannot be represented in an int64, the result is undefined.
func (x *Int) Int64() int64 {
panic("todo big.Int64")
}
// Uint64 returns the uint64 representation of x.
// If x cannot be represented in a uint64, the result is undefined.
func (x *Int) Uint64() uint64 {
panic("todo big.Uint64")
}
// IsInt64 reports whether x can be represented as an int64.
func (x *Int) IsInt64() bool {
panic("todo big.IsInt64")
}
// IsUint64 reports whether x can be represented as a uint64.
func (x *Int) IsUint64() bool {
panic("todo big.IsUint64")
}
// Float64 returns the float64 value nearest x,
// and an indication of any rounding that occurred.
// TODO(xsw):
/*
func (x *Int) Float64() (float64, Accuracy) {
panic("todo big.Float64")
}*/
// SetString sets z to the value of s, interpreted in the given base,
// and returns z and a boolean indicating success. The entire string
// (not just a prefix) must be valid for success. If SetString fails,
// the value of z is undefined but the returned value is nil.
//
// The base argument must be 0 or a value between 2 and MaxBase.
// For base 0, the number prefix determines the actual base: A prefix of
// “0b” or “0B” selects base 2, “0”, “0o” or “0O” selects base 8,
// and “0x” or “0X” selects base 16. Otherwise, the selected base is 10
// and no prefix is accepted.
//
// For bases <= 36, lower and upper case letters are considered the same:
// The letters 'a' to 'z' and 'A' to 'Z' represent digit values 10 to 35.
// For bases > 36, the upper case letters 'A' to 'Z' represent the digit
// values 36 to 61.
//
// For base 0, an underscore character “_” may appear between a base
// prefix and an adjacent digit, and between successive digits; such
// underscores do not change the value of the number.
// Incorrect placement of underscores is reported as an error if there
// are no other errors. If base != 0, underscores are not recognized
// and act like any other character that is not a valid digit.
func (z *Int) SetString(s string, base int) (*Int, bool) {
panic("todo big.SetString")
}
// SetBytes interprets buf as the bytes of a big-endian unsigned
// integer, sets z to that value, and returns z.
func (z *Int) SetBytes(buf []byte) *Int {
panic("todo big.SetBytes")
}
// Bytes returns the absolute value of x as a big-endian byte slice.
//
// To use a fixed length slice, or a preallocated one, use FillBytes.
func (x *Int) Bytes() []byte {
panic("todo big.Bytes")
}
// FillBytes sets buf to the absolute value of x, storing it as a zero-extended
// big-endian byte slice, and returns buf.
//
// If the absolute value of x doesn't fit in buf, FillBytes will panic.
func (x *Int) FillBytes(buf []byte) []byte {
panic("todo big.FillBytes")
}
// BitLen returns the length of the absolute value of x in bits.
// The bit length of 0 is 0.
func (x *Int) BitLen() int {
panic("todo big.BitLen")
}
// TrailingZeroBits returns the number of consecutive least significant zero
// bits of |x|.
func (x *Int) TrailingZeroBits() uint {
panic("todo big.TrailingZeroBits")
}
// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
// If m == nil or m == 0, z = x**y unless y <= 0 then z = 1. If m != 0, y < 0,
// and x and m are not relatively prime, z is unchanged and nil is returned.
//
// Modular exponentiation of inputs of a particular size is not a
// cryptographically constant-time operation.
func (z *Int) Exp(x, y, m *Int) *Int {
ctx := ctxGet()
mbn := (*openssl.BIGNUM)(m)
if mbn == nil || mbn.IsZero() != 0 {
(*openssl.BIGNUM)(z).Exp((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y), ctx)
} else {
(*openssl.BIGNUM)(z).ModExp((*openssl.BIGNUM)(x), (*openssl.BIGNUM)(y), mbn, ctx)
}
ctxPut(ctx)
return z
}
// GCD sets z to the greatest common divisor of a and b and returns z.
// If x or y are not nil, GCD sets their value such that z = a*x + b*y.
//
// a and b may be positive, zero or negative. (Before Go 1.14 both had
// to be > 0.) Regardless of the signs of a and b, z is always >= 0.
//
// If a == b == 0, GCD sets z = x = y = 0.
//
// If a == 0 and b != 0, GCD sets z = |b|, x = 0, y = sign(b) * 1.
//
// If a != 0 and b == 0, GCD sets z = |a|, x = sign(a) * 1, y = 0.
func (z *Int) GCD(x, y, a, b *Int) *Int {
panic("todo big.GCD")
}
// Rand sets z to a pseudo-random number in [0, n) and returns z.
//
// As this uses the math/rand package, it must not be used for
// security-sensitive work. Use crypto/rand.Int instead.
func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
panic("todo big.Rand")
}
// ModInverse sets z to the multiplicative inverse of g in the ring /n
// and returns z. If g and n are not relatively prime, g has no multiplicative
// inverse in the ring /n. In this case, z is unchanged and the return value
// is nil. If n == 0, a division-by-zero run-time panic occurs.
func (z *Int) ModInverse(g, n *Int) *Int {
panic("todo big.ModInverse")
}
// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
// The y argument must be an odd integer.
func Jacobi(x, y *Int) int {
panic("todo big.Jacobi")
}
// ModSqrt sets z to a square root of x mod p if such a square root exists, and
// returns z. The modulus p must be an odd prime. If x is not a square mod p,
// ModSqrt leaves z unchanged and returns nil. This function panics if p is
// not an odd integer, its behavior is undefined if p is odd but not prime.
func (z *Int) ModSqrt(x, p *Int) *Int {
panic("todo big.ModSqrt")
}
// Lsh sets z = x << n and returns z.
func (z *Int) Lsh(x *Int, n uint) *Int {
a := (*openssl.BIGNUM)(z)
b := (*openssl.BIGNUM)(x)
a.Lshift(b, c.Int(n))
return z
}
// Rsh sets z = x >> n and returns z.
func (z *Int) Rsh(x *Int, n uint) *Int {
a := (*openssl.BIGNUM)(z)
b := (*openssl.BIGNUM)(x)
a.Rshift(b, c.Int(n))
return z
}
// Bit returns the value of the i'th bit of x. That is, it
// returns (x>>i)&1. The bit index i must be >= 0.
func (x *Int) Bit(i int) uint {
panic("todo big.Bit")
}
// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
// That is, if b is 1 SetBit sets z = x | (1 << i);
// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1,
// SetBit will panic.
func (z *Int) SetBit(x *Int, i int, b uint) *Int {
panic("todo big.SetBit")
}
// And sets z = x & y and returns z.
func (z *Int) And(x, y *Int) *Int {
panic("todo big.And")
}
// AndNot sets z = x &^ y and returns z.
func (z *Int) AndNot(x, y *Int) *Int {
panic("todo big.AndNot")
}
// Or sets z = x | y and returns z.
func (z *Int) Or(x, y *Int) *Int {
panic("todo big.Or")
}
// Xor sets z = x ^ y and returns z.
func (z *Int) Xor(x, y *Int) *Int {
panic("todo big.Xor")
}
// Not sets z = ^x and returns z.
func (z *Int) Not(x *Int) *Int {
panic("todo big.Not")
}
// Sqrt sets z to ⌊√x⌋, the largest integer such that z² ≤ x, and returns z.
// It panics if x is negative.
func (z *Int) Sqrt(x *Int) *Int {
panic("todo big.Sqrt")
}
// -----------------------------------------------------------------------------

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package big
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/openssl"
)
/*
// Text returns the string representation of x in the given base.
// Base must be between 2 and 62, inclusive. The result uses the
// lower-case letters 'a' to 'z' for digit values 10 to 35, and
// the upper-case letters 'A' to 'Z' for digit values 36 to 61.
// No prefix (such as "0x") is added to the string. If x is a nil
// pointer it returns "<nil>".
func (x *Int) Text(base int) string {
}
// Append appends the string representation of x, as generated by
// x.Text(base), to buf and returns the extended buffer.
func (x *Int) Append(buf []byte, base int) []byte {
}
*/
// String returns the decimal representation of x as generated by
// x.Text(10).
func (x *Int) String() string {
// TODO(xsw): can optimize it?
cstr := (*openssl.BIGNUM)(x).CStr()
ret := c.GoString(cstr)
openssl.FreeCStr(cstr)
return ret
}
/*
// Format implements fmt.Formatter. It accepts the formats
// 'b' (binary), 'o' (octal with 0 prefix), 'O' (octal with 0o prefix),
// 'd' (decimal), 'x' (lowercase hexadecimal), and
// 'X' (uppercase hexadecimal).
// Also supported are the full suite of package fmt's format
// flags for integral types, including '+' and ' ' for sign
// control, '#' for leading zero in octal and for hexadecimal,
// a leading "0x" or "0X" for "%#x" and "%#X" respectively,
// specification of minimum digits precision, output field
// width, space or zero padding, and '-' for left or right
// justification.
func (x *Int) Format(s fmt.State, ch rune) {
}
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
func (z *Int) Scan(s fmt.ScanState, ch rune) error {
}
*/

View File

@@ -1,86 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmplx
import (
_ "unsafe"
)
const (
LLGoPackage = true
)
// -----------------------------------------------------------------------------
//go:linkname Abs C.cabs
func Abs(z complex128) float64
//go:linkname Acos C.cacos
func Acos(z complex128) complex128
//go:linkname Acosh C.cacosh
func Acosh(z complex128) complex128
//go:linkname Asin C.casin
func Asin(z complex128) complex128
//go:linkname Asinh C.casinh
func Asinh(z complex128) complex128
//go:linkname Atan C.catan
func Atan(z complex128) complex128
//go:linkname Atanh C.catanh
func Atanh(z complex128) complex128
//go:linkname Cos C.ccos
func Cos(z complex128) complex128
//go:linkname Cosh C.ccosh
func Cosh(z complex128) complex128
//go:linkname Exp C.cexp
func Exp(z complex128) complex128
//go:linkname Log C.clog
func Log(z complex128) complex128
//go:linkname Log10 C.clog10
func Log10(z complex128) complex128
//go:linkname Phase C.carg
func Phase(z complex128) float64
//go:linkname Pow C.cpow
func Pow(x, y complex128) complex128
//go:linkname Sin C.csin
func Sin(z complex128) complex128
//go:linkname Sinh C.csinh
func Sinh(z complex128) complex128
//go:linkname Sqrt C.csqrt
func Sqrt(z complex128) complex128
//go:linkname Tan C.ctan
func Tan(z complex128) complex128
//go:linkname Tanh C.ctanh
func Tanh(z complex128) complex128
// -----------------------------------------------------------------------------

View File

@@ -1,202 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package math
// llgo:skip sin cos
import (
_ "unsafe"
"github.com/goplus/llgo/c"
)
const (
LLGoPackage = true
)
//go:linkname Acos C.acos
func Acos(x float64) float64
//go:linkname Acosh C.acosh
func Acosh(x float64) float64
//go:linkname Asin C.asin
func Asin(x float64) float64
//go:linkname Asinh C.asinh
func Asinh(x float64) float64
//go:linkname Atan C.atan
func Atan(x float64) float64
//go:linkname Atan2 C.atan2
func Atan2(y, x float64) float64
//go:linkname Atanh C.atanh
func Atanh(x float64) float64
//go:linkname Cbrt C.cbrt
func Cbrt(x float64) float64
//go:linkname Ceil C.ceil
func Ceil(x float64) float64
//go:linkname Cos C.cos
func Cos(x float64) float64
//go:linkname Cosh C.cosh
func Cosh(x float64) float64
//go:linkname Copysign C.copysign
func Copysign(x, y float64) float64
//go:linkname Erf C.erf
func Erf(x float64) float64
//go:linkname Erfc C.erfc
func Erfc(x float64) float64
//go:linkname Exp C.exp
func Exp(x float64) float64
//go:linkname Exp2 C.exp2
func Exp2(x float64) float64
//go:linkname Expm1 C.expm1
func Expm1(x float64) float64
//go:linkname Dim C.fdim
func Dim(x, y float64) float64
//go:linkname Floor C.floor
func Floor(x float64) float64
//go:linkname FMA C.fma
func FMA(x, y, z float64) float64
//go:linkname Max C.fmax
func Max(x, y float64) float64
//go:linkname Min C.fmin
func Min(x, y float64) float64
//go:linkname Mod C.fmod
func Mod(x, y float64) float64
//go:linkname cFrexp C.frexp
func cFrexp(x float64, exp *c.Int) float64
func Frexp(f float64) (float64, int) {
var exp c.Int
var ret = cFrexp(f, &exp)
return ret, int(exp)
}
//go:linkname Gamma C.gamma
func Gamma(x float64) float64
//go:linkname Hypot C.hypot
func Hypot(x, y float64) float64
//go:linkname cIlogb C.ilogb
func cIlogb(x float64) c.Int
func Ilogb(x float64) int {
return int(cIlogb(x))
}
//go:linkname J0 C.j0
func J0(x float64) float64
//go:linkname J1 C.j1
func J1(x float64) float64
//go:linkname cJn C.jn
func cJn(n c.Int, x float64) float64
func Jn(n int, x float64) float64 {
return cJn(c.Int(n), x)
}
//go:linkname cLdexp C.ldexp
func cLdexp(x float64, exp c.Int) float64
func Ldexp(x float64, exp int) float64 {
return cLdexp(x, c.Int(exp))
}
//-go:linkname cLgamma C.lgamma
//func cLgamma(x float64) float64
//go:linkname Log C.log
func Log(x float64) float64
//go:linkname Log10 C.log10
func Log10(x float64) float64
//go:linkname Log1p C.log1p
func Log1p(x float64) float64
//go:linkname Log2 C.log2
func Log2(x float64) float64
//go:linkname Logb C.logb
func Logb(x float64) float64
//go:linkname cModf C.modf
func cModf(x float64, intpart *float64) float64
func Modf(f float64) (float64, float64) {
var intpart float64
var ret = cModf(f, &intpart)
return intpart, ret
}
//-go:linkname cNan C.nan
//func cNan(tag *c.Char) float64
//go:linkname Nextafter C.nextafter
func Nextafter(x, y float64) float64
//go:linkname Pow C.pow
func Pow(x, y float64) float64
//go:linkname Remainder C.remainder
func Remainder(x, y float64) float64
//go:linkname Round C.round
func Round(x float64) float64
//go:linkname Sin C.sin
func Sin(x float64) float64
//go:linkname Sinh C.sinh
func Sinh(x float64) float64
//go:linkname Sqrt C.sqrt
func Sqrt(x float64) float64
//go:linkname Tan C.tan
func Tan(x float64) float64
//go:linkname Tanh C.tanh
func Tanh(x float64) float64
//-go:linkname Tgamma C.tgamma
//func Tgamma(x float64) float64
//go:linkname Trunc C.trunc
func Trunc(x float64) float64

View File

@@ -1,221 +0,0 @@
// 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 rand
import (
"math"
)
/*
* Exponential distribution
*
* See "The Ziggurat Method for Generating Random Variables"
* (Marsaglia & Tsang, 2000)
* https://www.jstatsoft.org/v05/i08/paper [pdf]
*/
const (
re = 7.69711747013104972
)
// ExpFloat64 returns an exponentially distributed float64 in the range
// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
// (lambda) is 1 and whose mean is 1/lambda (1).
// To produce a distribution with a different rate parameter,
// callers can adjust the output using:
//
// sample = ExpFloat64() / desiredRateParameter
func (r *Rand) ExpFloat64() float64 {
for {
j := r.Uint32()
i := j & 0xFF
x := float64(j) * float64(we[i])
if j < ke[i] {
return x
}
if i == 0 {
return re - math.Log(r.Float64())
}
if fe[i]+float32(r.Float64())*(fe[i-1]-fe[i]) < float32(math.Exp(-x)) {
return x
}
}
}
var ke = [256]uint32{
0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990,
0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8,
0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78,
0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651,
0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca,
0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8,
0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea,
0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba,
0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed,
0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662,
0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3,
0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace,
0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6,
0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7,
0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415,
0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4,
0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36,
0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46,
0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac,
0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245,
0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52,
0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06,
0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0,
0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9,
0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76,
0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516,
0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289,
0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed,
0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb,
0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e,
0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a,
0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1,
0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b,
0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621,
0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d,
0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3,
0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73,
0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88,
0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a,
0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb,
0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176,
0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be,
0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192,
0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed,
0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936,
0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b,
0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4,
0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1,
0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482,
0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023,
0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d,
0xe6da6ecf,
}
var we = [256]float32{
2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11,
3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11,
5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11,
7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11,
9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10,
1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10,
1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10,
1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10,
1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10,
1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10,
1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10,
1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10,
1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10,
1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10,
2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10,
2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10,
2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10,
2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10,
2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10,
2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10,
2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10,
2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10,
2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10,
2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10,
3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10,
3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10,
3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10,
3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10,
3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10,
3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10,
3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10,
3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10,
3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10,
4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10,
4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10,
4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10,
4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10,
4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10,
4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10,
4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10,
4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10,
5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10,
5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10,
5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10,
5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10,
5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10,
5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10,
6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10,
6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10,
6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10,
6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10,
6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10,
7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10,
7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10,
7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10,
8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10,
8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10,
8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10,
9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10,
9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09,
1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09,
1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09,
1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09,
1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09,
}
var fe = [256]float32{
1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933,
0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686,
0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665,
0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967,
0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896,
0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092,
0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386,
0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495,
0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752,
0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325,
0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955,
0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694,
0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218,
0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763,
0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044,
0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796,
0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408,
0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928,
0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393,
0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625,
0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107,
0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878,
0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438,
0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682,
0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852,
0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479,
0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354,
0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494,
0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119,
0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624,
0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574,
0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672,
0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763,
0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816,
0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919,
0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274,
0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195,
0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106,
0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434,
0.062193416, 0.060783047, 0.059384305, 0.057997175,
0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236,
0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623,
0.043502413, 0.042254124, 0.041017443, 0.039792392,
0.038578995, 0.037377283, 0.036187284, 0.035009038,
0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566,
0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421,
0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867,
0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392,
0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414,
0.008780315, 0.007963077, 0.0071633533, 0.006381906,
0.0056196423, 0.0048776558, 0.004157295, 0.0034602648,
0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693,
0.00045413437,
}

View File

@@ -1,156 +0,0 @@
// 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 rand
import (
"math"
)
/*
* Normal distribution
*
* See "The Ziggurat Method for Generating Random Variables"
* (Marsaglia & Tsang, 2000)
* http://www.jstatsoft.org/v05/i08/paper [pdf]
*/
const (
rn = 3.442619855899
)
func absInt32(i int32) uint32 {
if i < 0 {
return uint32(-i)
}
return uint32(i)
}
// NormFloat64 returns a normally distributed float64 in
// the range -math.MaxFloat64 through +math.MaxFloat64 inclusive,
// with standard normal distribution (mean = 0, stddev = 1).
// To produce a different normal distribution, callers can
// adjust the output using:
//
// sample = NormFloat64() * desiredStdDev + desiredMean
func (r *Rand) NormFloat64() float64 {
for {
j := int32(r.Uint32()) // Possibly negative
i := j & 0x7F
x := float64(j) * float64(wn[i])
if absInt32(j) < kn[i] {
// This case should be hit better than 99% of the time.
return x
}
if i == 0 {
// This extra work is only required for the base strip.
for {
x = -math.Log(r.Float64()) * (1.0 / rn)
y := -math.Log(r.Float64())
if y+y >= x*x {
break
}
}
if j > 0 {
return rn + x
}
return -rn - x
}
if fn[i]+float32(r.Float64())*(fn[i-1]-fn[i]) < float32(math.Exp(-.5*x*x)) {
return x
}
}
}
var kn = [128]uint32{
0x76ad2212, 0x0, 0x600f1b53, 0x6ce447a6, 0x725b46a2,
0x7560051d, 0x774921eb, 0x789a25bd, 0x799045c3, 0x7a4bce5d,
0x7adf629f, 0x7b5682a6, 0x7bb8a8c6, 0x7c0ae722, 0x7c50cce7,
0x7c8cec5b, 0x7cc12cd6, 0x7ceefed2, 0x7d177e0b, 0x7d3b8883,
0x7d5bce6c, 0x7d78dd64, 0x7d932886, 0x7dab0e57, 0x7dc0dd30,
0x7dd4d688, 0x7de73185, 0x7df81cea, 0x7e07c0a3, 0x7e163efa,
0x7e23b587, 0x7e303dfd, 0x7e3beec2, 0x7e46db77, 0x7e51155d,
0x7e5aabb3, 0x7e63abf7, 0x7e6c222c, 0x7e741906, 0x7e7b9a18,
0x7e82adfa, 0x7e895c63, 0x7e8fac4b, 0x7e95a3fb, 0x7e9b4924,
0x7ea0a0ef, 0x7ea5b00d, 0x7eaa7ac3, 0x7eaf04f3, 0x7eb3522a,
0x7eb765a5, 0x7ebb4259, 0x7ebeeafd, 0x7ec2620a, 0x7ec5a9c4,
0x7ec8c441, 0x7ecbb365, 0x7ece78ed, 0x7ed11671, 0x7ed38d62,
0x7ed5df12, 0x7ed80cb4, 0x7eda175c, 0x7edc0005, 0x7eddc78e,
0x7edf6ebf, 0x7ee0f647, 0x7ee25ebe, 0x7ee3a8a9, 0x7ee4d473,
0x7ee5e276, 0x7ee6d2f5, 0x7ee7a620, 0x7ee85c10, 0x7ee8f4cd,
0x7ee97047, 0x7ee9ce59, 0x7eea0eca, 0x7eea3147, 0x7eea3568,
0x7eea1aab, 0x7ee9e071, 0x7ee98602, 0x7ee90a88, 0x7ee86d08,
0x7ee7ac6a, 0x7ee6c769, 0x7ee5bc9c, 0x7ee48a67, 0x7ee32efc,
0x7ee1a857, 0x7edff42f, 0x7ede0ffa, 0x7edbf8d9, 0x7ed9ab94,
0x7ed7248d, 0x7ed45fae, 0x7ed1585c, 0x7ece095f, 0x7eca6ccb,
0x7ec67be2, 0x7ec22eee, 0x7ebd7d1a, 0x7eb85c35, 0x7eb2c075,
0x7eac9c20, 0x7ea5df27, 0x7e9e769f, 0x7e964c16, 0x7e8d44ba,
0x7e834033, 0x7e781728, 0x7e6b9933, 0x7e5d8a1a, 0x7e4d9ded,
0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72,
0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
0x7ba90bdc, 0x7a722176, 0x77d664e5,
}
var wn = [128]float32{
1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10,
2.2232431e-10, 2.4244937e-10, 2.601613e-10, 2.7611988e-10,
2.9073963e-10, 3.042997e-10, 3.1699796e-10, 3.289802e-10,
3.4035738e-10, 3.5121603e-10, 3.616251e-10, 3.7164058e-10,
3.8130857e-10, 3.9066758e-10, 3.9975012e-10, 4.08584e-10,
4.1719309e-10, 4.2559822e-10, 4.338176e-10, 4.418672e-10,
4.497613e-10, 4.5751258e-10, 4.651324e-10, 4.7263105e-10,
4.8001775e-10, 4.87301e-10, 4.944885e-10, 5.015873e-10,
5.0860405e-10, 5.155446e-10, 5.2241467e-10, 5.2921934e-10,
5.359635e-10, 5.426517e-10, 5.4928817e-10, 5.5587696e-10,
5.624219e-10, 5.6892646e-10, 5.753941e-10, 5.818282e-10,
5.882317e-10, 5.946077e-10, 6.00959e-10, 6.072884e-10,
6.135985e-10, 6.19892e-10, 6.2617134e-10, 6.3243905e-10,
6.386974e-10, 6.449488e-10, 6.511956e-10, 6.5744005e-10,
6.6368433e-10, 6.699307e-10, 6.7618144e-10, 6.824387e-10,
6.8870465e-10, 6.949815e-10, 7.012715e-10, 7.075768e-10,
7.1389966e-10, 7.202424e-10, 7.266073e-10, 7.329966e-10,
7.394128e-10, 7.4585826e-10, 7.5233547e-10, 7.58847e-10,
7.653954e-10, 7.719835e-10, 7.7861395e-10, 7.852897e-10,
7.920138e-10, 7.987892e-10, 8.0561924e-10, 8.125073e-10,
8.194569e-10, 8.2647167e-10, 8.3355556e-10, 8.407127e-10,
8.479473e-10, 8.55264e-10, 8.6266755e-10, 8.7016316e-10,
8.777562e-10, 8.8545243e-10, 8.932582e-10, 9.0117996e-10,
9.09225e-10, 9.174008e-10, 9.2571584e-10, 9.341788e-10,
9.427997e-10, 9.515889e-10, 9.605579e-10, 9.697193e-10,
9.790869e-10, 9.88676e-10, 9.985036e-10, 1.0085882e-09,
1.0189509e-09, 1.0296151e-09, 1.0406069e-09, 1.0519566e-09,
1.063698e-09, 1.0758702e-09, 1.0885183e-09, 1.1016947e-09,
1.1154611e-09, 1.1298902e-09, 1.1450696e-09, 1.1611052e-09,
1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09,
1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
}
var fn = [128]float32{
1, 0.9635997, 0.9362827, 0.9130436, 0.89228165, 0.87324303,
0.8555006, 0.8387836, 0.8229072, 0.8077383, 0.793177,
0.7791461, 0.7655842, 0.7524416, 0.73967725, 0.7272569,
0.7151515, 0.7033361, 0.69178915, 0.68049186, 0.6694277,
0.658582, 0.6479418, 0.63749546, 0.6272325, 0.6171434,
0.6072195, 0.5974532, 0.58783704, 0.5783647, 0.56903,
0.5598274, 0.5507518, 0.54179835, 0.5329627, 0.52424055,
0.5156282, 0.50712204, 0.49871865, 0.49041483, 0.48220766,
0.4740943, 0.46607214, 0.4581387, 0.45029163, 0.44252872,
0.43484783, 0.427247, 0.41972435, 0.41227803, 0.40490642,
0.39760786, 0.3903808, 0.3832238, 0.37613547, 0.36911446,
0.3621595, 0.35526937, 0.34844297, 0.34167916, 0.33497685,
0.3283351, 0.3217529, 0.3152294, 0.30876362, 0.30235484,
0.29600215, 0.28970486, 0.2834622, 0.2772735, 0.27113807,
0.2650553, 0.25902456, 0.2530453, 0.24711695, 0.241239,
0.23541094, 0.22963232, 0.2239027, 0.21822165, 0.21258877,
0.20700371, 0.20146611, 0.19597565, 0.19053204, 0.18513499,
0.17978427, 0.17447963, 0.1692209, 0.16400786, 0.15884037,
0.15371831, 0.14864157, 0.14361008, 0.13862377, 0.13368265,
0.12878671, 0.12393598, 0.119130544, 0.11437051, 0.10965602,
0.104987256, 0.10036444, 0.095787846, 0.0912578, 0.08677467,
0.0823389, 0.077950984, 0.073611505, 0.06932112, 0.06508058,
0.06089077, 0.056752663, 0.0526674, 0.048636295, 0.044660863,
0.040742867, 0.03688439, 0.033087887, 0.029356318,
0.025693292, 0.022103304, 0.018592102, 0.015167298,
0.011839478, 0.008624485, 0.005548995, 0.0026696292,
}

View File

@@ -1,547 +0,0 @@
// 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 rand implements pseudo-random number generators suitable for tasks
// such as simulation, but it should not be used for security-sensitive work.
//
// Random numbers are generated by a [Source], usually wrapped in a [Rand].
// Both types should be used by a single goroutine at a time: sharing among
// multiple goroutines requires some kind of synchronization.
//
// Top-level functions, such as [Float64] and [Int],
// are safe for concurrent use by multiple goroutines.
//
// This package's outputs might be easily predictable regardless of how it's
// seeded. For random numbers suitable for security-sensitive work, see the
// crypto/rand package.
package rand
// llgo:skipall
import (
"sync"
"sync/atomic"
_ "unsafe" // for go:linkname
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/math/rand"
"github.com/goplus/llgo/c/time"
)
// A Source represents a source of uniformly-distributed
// pseudo-random int64 values in the range [0, 1<<63).
//
// A Source is not safe for concurrent use by multiple goroutines.
type Source interface {
Int63() int64
Seed(seed int64)
}
// A Source64 is a Source that can also generate
// uniformly-distributed pseudo-random uint64 values in
// the range [0, 1<<64) directly.
// If a Rand r's underlying Source s implements Source64,
// then r.Uint64 returns the result of one call to s.Uint64
// instead of making two calls to s.Int63.
type Source64 interface {
Source
Uint64() uint64
}
// NewSource returns a new pseudo-random Source seeded with the given value.
// Unlike the default Source used by top-level functions, this source is not
// safe for concurrent use by multiple goroutines.
// The returned Source implements Source64.
func NewSource(seed int64) Source {
return newSource(seed)
}
func newSource(seed int64) *rngSource {
var rng rngSource
rng.Seed(seed)
return &rng
}
// A Rand is a source of random numbers.
type Rand struct {
src Source
s64 Source64 // non-nil if src is source64
// readVal contains remainder of 63-bit integer used for bytes
// generation during most recent Read call.
// It is saved so next Read call can start where the previous
// one finished.
readVal int64
// readPos indicates the number of low-order bytes of readVal
// that are still valid.
readPos int8
}
// New returns a new Rand that uses random values from src
// to generate other random values.
func New(src Source) *Rand {
s64, _ := src.(Source64)
return &Rand{src: src, s64: s64}
}
// Seed uses the provided seed value to initialize the generator to a deterministic state.
// Seed should not be called concurrently with any other Rand method.
func (r *Rand) Seed(seed int64) {
if lk, ok := r.src.(*lockedSource); ok {
lk.seedPos(seed, &r.readPos)
return
}
r.src.Seed(seed)
r.readPos = 0
}
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
func (r *Rand) Int63() int64 { return r.src.Int63() }
// Uint32 returns a pseudo-random 32-bit value as a uint32.
func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }
// Uint64 returns a pseudo-random 64-bit value as a uint64.
func (r *Rand) Uint64() uint64 {
if r.s64 != nil {
return r.s64.Uint64()
}
return uint64(r.Int63())>>31 | uint64(r.Int63())<<32
}
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }
// Int returns a non-negative pseudo-random int.
func (r *Rand) Int() int {
u := uint(r.Int63())
return int(u << 1 >> 1) // clear sign bit if int == int32
}
// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func (r *Rand) Int63n(n int64) int64 {
if n <= 0 {
panic("invalid argument to Int63n")
}
if n&(n-1) == 0 { // n is power of two, can mask
return r.Int63() & (n - 1)
}
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
v := r.Int63()
for v > max {
v = r.Int63()
}
return v % n
}
// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func (r *Rand) Int31n(n int32) int32 {
if n <= 0 {
panic("invalid argument to Int31n")
}
if n&(n-1) == 0 { // n is power of two, can mask
return r.Int31() & (n - 1)
}
max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
v := r.Int31()
for v > max {
v = r.Int31()
}
return v % n
}
// int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n).
// n must be > 0, but int31n does not check this; the caller must ensure it.
// int31n exists because Int31n is inefficient, but Go 1 compatibility
// requires that the stream of values produced by math/rand remain unchanged.
// int31n can thus only be used internally, by newly introduced APIs.
//
// For implementation details, see:
// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction
// https://lemire.me/blog/2016/06/30/fast-random-shuffling
func (r *Rand) int31n(n int32) int32 {
v := r.Uint32()
prod := uint64(v) * uint64(n)
low := uint32(prod)
if low < uint32(n) {
thresh := uint32(-n) % uint32(n)
for low < thresh {
v = r.Uint32()
prod = uint64(v) * uint64(n)
low = uint32(prod)
}
}
return int32(prod >> 32)
}
// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n).
// It panics if n <= 0.
func (r *Rand) Intn(n int) int {
if n <= 0 {
panic("invalid argument to Intn")
}
if n <= 1<<31-1 {
return int(r.Int31n(int32(n)))
}
return int(r.Int63n(int64(n)))
}
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0).
func (r *Rand) Float64() float64 {
// A clearer, simpler implementation would be:
// return float64(r.Int63n(1<<53)) / (1<<53)
// However, Go 1 shipped with
// return float64(r.Int63()) / (1 << 63)
// and we want to preserve that value stream.
//
// There is one bug in the value stream: r.Int63() may be so close
// to 1<<63 that the division rounds up to 1.0, and we've guaranteed
// that the result is always less than 1.0.
//
// We tried to fix this by mapping 1.0 back to 0.0, but since float64
// values near 0 are much denser than near 1, mapping 1 to 0 caused
// a theoretically significant overshoot in the probability of returning 0.
// Instead of that, if we round up to 1, just try again.
// Getting 1 only happens 1/2⁵³ of the time, so most clients
// will not observe it anyway.
again:
f := float64(r.Int63()) / (1 << 63)
if f == 1 {
goto again // resample; this branch is taken O(never)
}
return f
}
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0).
func (r *Rand) Float32() float32 {
// Same rationale as in Float64: we want to preserve the Go 1 value
// stream except we want to fix it not to return 1.0
// This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64).
again:
f := float32(r.Float64())
if f == 1 {
goto again // resample; this branch is taken O(very rarely)
}
return f
}
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
// in the half-open interval [0,n).
func (r *Rand) Perm(n int) []int {
m := make([]int, n)
// In the following loop, the iteration when i=0 always swaps m[0] with m[0].
// A change to remove this useless iteration is to assign 1 to i in the init
// statement. But Perm also effects r. Making this change will affect
// the final state of r. So this change can't be made for compatibility
// reasons for Go 1.
for i := 0; i < n; i++ {
j := r.Intn(i + 1)
m[i] = m[j]
m[j] = i
}
return m
}
// Shuffle pseudo-randomizes the order of elements.
// n is the number of elements. Shuffle panics if n < 0.
// swap swaps the elements with indexes i and j.
func (r *Rand) Shuffle(n int, swap func(i, j int)) {
if n < 0 {
panic("invalid argument to Shuffle")
}
// Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
// Shuffle really ought not be called with n that doesn't fit in 32 bits.
// Not only will it take a very long time, but with 2³¹! possible permutations,
// there's no way that any PRNG can have a big enough internal state to
// generate even a minuscule percentage of the possible permutations.
// Nevertheless, the right API signature accepts an int n, so handle it as best we can.
i := n - 1
for ; i > 1<<31-1-1; i-- {
j := int(r.Int63n(int64(i + 1)))
swap(i, j)
}
for ; i > 0; i-- {
j := int(r.int31n(int32(i + 1)))
swap(i, j)
}
}
// Read generates len(p) random bytes and writes them into p. It
// always returns len(p) and a nil error.
// Read should not be called concurrently with any other Rand method.
func (r *Rand) Read(p []byte) (n int, err error) {
switch src := r.src.(type) {
case *lockedSource:
return src.read(p, &r.readVal, &r.readPos)
case *fastSource:
return src.read(p, &r.readVal, &r.readPos)
}
return read(p, r.src, &r.readVal, &r.readPos)
}
func read(p []byte, src Source, readVal *int64, readPos *int8) (n int, err error) {
pos := *readPos
val := *readVal
rng, _ := src.(*rngSource)
for n = 0; n < len(p); n++ {
if pos == 0 {
if rng != nil {
val = rng.Int63()
} else {
val = src.Int63()
}
pos = 7
}
p[n] = byte(val)
val >>= 8
pos--
}
*readPos = pos
*readVal = val
return
}
/*
* Top-level convenience functions
*/
// globalRandGenerator is the source of random numbers for the top-level
// convenience functions. When possible it uses the runtime fastrand64
// function to avoid locking. This is not possible if the user called Seed,
// either explicitly or implicitly via GODEBUG=randautoseed=0.
var globalRandGenerator atomic.Pointer[Rand]
// globalRand returns the generator to use for the top-level convenience
// functions.
func globalRand() *Rand {
if r := globalRandGenerator.Load(); r != nil {
return r
}
// This is the first call. Initialize based on GODEBUG.
var r = &Rand{
src: &fastSource{},
s64: &fastSource{},
}
if !globalRandGenerator.CompareAndSwap(nil, r) {
// Two different goroutines called some top-level
// function at the same time. While the results in
// that case are unpredictable, if we just use r here,
// and we are using a seed, we will most likely return
// the same value for both calls. That doesn't seem ideal.
// Just use the first one to get in.
return globalRandGenerator.Load()
}
return r
}
func fastrand64() uint64 {
v1 := uint64(rand.Random())
v2 := uint64(rand.Random())
return v1 ^ (v2 << 32)
}
func init() {
rand.Srandom(c.Uint(time.Time(nil)))
}
// fastSource is an implementation of Source64 that uses the runtime
// fastrand functions.
type fastSource struct {
// The mutex is used to avoid race conditions in Read.
mu sync.Mutex
}
func (*fastSource) Int63() int64 {
return int64(fastrand64() & rngMask)
}
func (*fastSource) Seed(int64) {
panic("internal error: call to fastSource.Seed")
}
func (*fastSource) Uint64() uint64 {
return fastrand64()
}
func (fs *fastSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
fs.mu.Lock()
n, err = read(p, fs, readVal, readPos)
fs.mu.Unlock()
return
}
// Seed uses the provided seed value to initialize the default Source to a
// deterministic state. Seed values that have the same remainder when
// divided by 2³¹-1 generate the same pseudo-random sequence.
// Seed, unlike the Rand.Seed method, is safe for concurrent use.
//
// If Seed is not called, the generator is seeded randomly at program startup.
//
// Prior to Go 1.20, the generator was seeded like Seed(1) at program startup.
// To force the old behavior, call Seed(1) at program startup.
// Alternately, set GODEBUG=randautoseed=0 in the environment
// before making any calls to functions in this package.
//
// Deprecated: As of Go 1.20 there is no reason to call Seed with
// a random value. Programs that call Seed with a known value to get
// a specific sequence of results should use New(NewSource(seed)) to
// obtain a local random generator.
func Seed(seed int64) {
orig := globalRandGenerator.Load()
// If we are already using a lockedSource, we can just re-seed it.
if orig != nil {
if _, ok := orig.src.(*lockedSource); ok {
orig.Seed(seed)
return
}
}
// Otherwise either
// 1) orig == nil, which is the normal case when Seed is the first
// top-level function to be called, or
// 2) orig is already a fastSource, in which case we need to change
// to a lockedSource.
// Either way we do the same thing.
r := New(new(lockedSource))
r.Seed(seed)
if !globalRandGenerator.CompareAndSwap(orig, r) {
// Something changed underfoot. Retry to be safe.
Seed(seed)
}
}
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
// from the default Source.
func Int63() int64 { return globalRand().Int63() }
// Uint32 returns a pseudo-random 32-bit value as a uint32
// from the default Source.
func Uint32() uint32 { return globalRand().Uint32() }
// Uint64 returns a pseudo-random 64-bit value as a uint64
// from the default Source.
func Uint64() uint64 { return globalRand().Uint64() }
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32
// from the default Source.
func Int31() int32 { return globalRand().Int31() }
// Int returns a non-negative pseudo-random int from the default Source.
func Int() int { return globalRand().Int() }
// Int63n returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Int63n(n int64) int64 { return globalRand().Int63n(n) }
// Int31n returns, as an int32, a non-negative pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Int31n(n int32) int32 { return globalRand().Int31n(n) }
// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n)
// from the default Source.
// It panics if n <= 0.
func Intn(n int) int { return globalRand().Intn(n) }
// Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0)
// from the default Source.
func Float64() float64 { return globalRand().Float64() }
// Float32 returns, as a float32, a pseudo-random number in the half-open interval [0.0,1.0)
// from the default Source.
func Float32() float32 { return globalRand().Float32() }
// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers
// in the half-open interval [0,n) from the default Source.
func Perm(n int) []int { return globalRand().Perm(n) }
// Shuffle pseudo-randomizes the order of elements using the default Source.
// n is the number of elements. Shuffle panics if n < 0.
// swap swaps the elements with indexes i and j.
func Shuffle(n int, swap func(i, j int)) { globalRand().Shuffle(n, swap) }
// Read generates len(p) random bytes from the default Source and
// writes them into p. It always returns len(p) and a nil error.
// Read, unlike the Rand.Read method, is safe for concurrent use.
//
// Deprecated: For almost all use cases, crypto/rand.Read is more appropriate.
func Read(p []byte) (n int, err error) { return globalRand().Read(p) }
// NormFloat64 returns a normally distributed float64 in the range
// [-math.MaxFloat64, +math.MaxFloat64] with
// standard normal distribution (mean = 0, stddev = 1)
// from the default Source.
// To produce a different normal distribution, callers can
// adjust the output using:
//
// sample = NormFloat64() * desiredStdDev + desiredMean
func NormFloat64() float64 { return globalRand().NormFloat64() }
// ExpFloat64 returns an exponentially distributed float64 in the range
// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source.
// To produce a distribution with a different rate parameter,
// callers can adjust the output using:
//
// sample = ExpFloat64() / desiredRateParameter
func ExpFloat64() float64 { return globalRand().ExpFloat64() }
type lockedSource struct {
lk sync.Mutex
s *rngSource
}
func (r *lockedSource) Int63() (n int64) {
r.lk.Lock()
n = r.s.Int63()
r.lk.Unlock()
return
}
func (r *lockedSource) Uint64() (n uint64) {
r.lk.Lock()
n = r.s.Uint64()
r.lk.Unlock()
return
}
func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.seed(seed)
r.lk.Unlock()
}
// seedPos implements Seed for a lockedSource without a race condition.
func (r *lockedSource) seedPos(seed int64, readPos *int8) {
r.lk.Lock()
r.seed(seed)
*readPos = 0
r.lk.Unlock()
}
// seed seeds the underlying source.
// The caller must have locked r.lk.
func (r *lockedSource) seed(seed int64) {
if r.s == nil {
r.s = newSource(seed)
} else {
r.s.Seed(seed)
}
}
// read implements Read for a lockedSource without a race condition.
func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
r.lk.Lock()
n, err = read(p, r.s, readVal, readPos)
r.lk.Unlock()
return
}

View File

@@ -1,252 +0,0 @@
// 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 rand
/*
* Uniform distribution
*
* algorithm by
* DP Mitchell and JA Reeds
*/
const (
rngLen = 607
rngTap = 273
rngMax = 1 << 63
rngMask = rngMax - 1
int32max = (1 << 31) - 1
)
var (
// rngCooked used for seeding. See gen_cooked.go for details.
rngCooked [rngLen]int64 = [...]int64{
-4181792142133755926, -4576982950128230565, 1395769623340756751, 5333664234075297259,
-6347679516498800754, 9033628115061424579, 7143218595135194537, 4812947590706362721,
7937252194349799378, 5307299880338848416, 8209348851763925077, -7107630437535961764,
4593015457530856296, 8140875735541888011, -5903942795589686782, -603556388664454774,
-7496297993371156308, 113108499721038619, 4569519971459345583, -4160538177779461077,
-6835753265595711384, -6507240692498089696, 6559392774825876886, 7650093201692370310,
7684323884043752161, -8965504200858744418, -2629915517445760644, 271327514973697897,
-6433985589514657524, 1065192797246149621, 3344507881999356393, -4763574095074709175,
7465081662728599889, 1014950805555097187, -4773931307508785033, -5742262670416273165,
2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048,
-4699774852342421385, 10530508058128498, -589538253572429690, -6598062107225984180,
8660405965245884302, 10162832508971942, -2682657355892958417, 7031802312784620857,
6240911277345944669, 831864355460801054, -1218937899312622917, 2116287251661052151,
2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449,
457351505131524928, -8881176990926596454, -6375600354038175299, -7155351920868399290,
4368649989588021065, 887231587095185257, -3659780529968199312, -2407146836602825512,
5616972787034086048, -751562733459939242, 1686575021641186857, -5177887698780513806,
-4979215821652996885, -1375154703071198421, 5632136521049761902, -8390088894796940536,
-193645528485698615, -5979788902190688516, -4907000935050298721, -285522056888777828,
-2776431630044341707, 1679342092332374735, 6050638460742422078, -2229851317345194226,
-1582494184340482199, 5881353426285907985, 812786550756860885, 4541845584483343330,
-6497901820577766722, 4980675660146853729, -4012602956251539747, -329088717864244987,
-2896929232104691526, 1495812843684243920, -2153620458055647789, 7370257291860230865,
-2466442761497833547, 4706794511633873654, -1398851569026877145, 8549875090542453214,
-9189721207376179652, -7894453601103453165, 7297902601803624459, 1011190183918857495,
-6985347000036920864, 5147159997473910359, -8326859945294252826, 2659470849286379941,
6097729358393448602, -7491646050550022124, -5117116194870963097, -896216826133240300,
-745860416168701406, 5803876044675762232, -787954255994554146, -3234519180203704564,
-4507534739750823898, -1657200065590290694, 505808562678895611, -4153273856159712438,
-8381261370078904295, 572156825025677802, 1791881013492340891, 3393267094866038768,
-5444650186382539299, 2352769483186201278, -7930912453007408350, -325464993179687389,
-3441562999710612272, -6489413242825283295, 5092019688680754699, -227247482082248967,
4234737173186232084, 5027558287275472836, 4635198586344772304, -536033143587636457,
5907508150730407386, -8438615781380831356, 972392927514829904, -3801314342046600696,
-4064951393885491917, -174840358296132583, 2407211146698877100, -1640089820333676239,
3940796514530962282, -5882197405809569433, 3095313889586102949, -1818050141166537098,
5832080132947175283, 7890064875145919662, 8184139210799583195, -8073512175445549678,
-7758774793014564506, -4581724029666783935, 3516491885471466898, -8267083515063118116,
6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916,
1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775,
-5873264506986385449, 6116438694366558490, 2107701075971293812, -7420077970933506541,
2469478054175558874, -1855128755834809824, -5431463669011098282, -9038325065738319171,
-6966276280341336160, 7217693971077460129, -8314322083775271549, 7196649268545224266,
-3585711691453906209, -5267827091426810625, 8057528650917418961, -5084103596553648165,
-2601445448341207749, -7850010900052094367, 6527366231383600011, 3507654575162700890,
9202058512774729859, 1954818376891585542, -2582991129724600103, 8299563319178235687,
-5321504681635821435, 7046310742295574065, -2376176645520785576, -7650733936335907755,
8850422670118399721, 3631909142291992901, 5158881091950831288, -6340413719511654215,
4763258931815816403, 6280052734341785344, -4979582628649810958, 2043464728020827976,
-2678071570832690343, 4562580375758598164, 5495451168795427352, -7485059175264624713,
553004618757816492, 6895160632757959823, -989748114590090637, 7139506338801360852,
-672480814466784139, 5535668688139305547, 2430933853350256242, -3821430778991574732,
-1063731997747047009, -3065878205254005442, 7632066283658143750, 6308328381617103346,
3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476,
-5143583659437639708, 8090302575944624335, 2945117363431356361, -8359047641006034763,
3009039260312620700, -793344576772241777, 401084700045993341, -1968749590416080887,
4707864159563588614, -3583123505891281857, -3240864324164777915, -5908273794572565703,
-3719524458082857382, -5281400669679581926, 8118566580304798074, 3839261274019871296,
7062410411742090847, -8481991033874568140, 6027994129690250817, -6725542042704711878,
-2971981702428546974, -7854441788951256975, 8809096399316380241, 6492004350391900708,
2462145737463489636, -8818543617934476634, -5070345602623085213, -8961586321599299868,
-3758656652254704451, -8630661632476012791, 6764129236657751224, -709716318315418359,
-3403028373052861600, -8838073512170985897, -3999237033416576341, -2920240395515973663,
-2073249475545404416, 368107899140673753, -6108185202296464250, -6307735683270494757,
4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289,
4654329375432538231, -292704475491394206, -3848998599978456535, 7623042350483453954,
7725442901813263321, 9186225467561587250, -5132344747257272453, -6865740430362196008,
2530936820058611833, 1636551876240043639, -3658707362519810009, 1452244145334316253,
-7161729655835084979, -7943791770359481772, 9108481583171221009, -3200093350120725999,
5007630032676973346, 2153168792952589781, 6720334534964750538, -3181825545719981703,
3433922409283786309, 2285479922797300912, 3110614940896576130, -2856812446131932915,
-3804580617188639299, 7163298419643543757, 4891138053923696990, 580618510277907015,
1684034065251686769, 4429514767357295841, -8893025458299325803, -8103734041042601133,
7177515271653460134, 4589042248470800257, -1530083407795771245, 143607045258444228,
246994305896273627, -8356954712051676521, 6473547110565816071, 3092379936208876896,
2058427839513754051, -4089587328327907870, 8785882556301281247, -3074039370013608197,
-637529855400303673, 6137678347805511274, -7152924852417805802, 5708223427705576541,
-3223714144396531304, 4358391411789012426, 325123008708389849, 6837621693887290924,
4843721905315627004, -3212720814705499393, -3825019837890901156, 4602025990114250980,
1044646352569048800, 9106614159853161675, -8394115921626182539, -4304087667751778808,
2681532557646850893, 3681559472488511871, -3915372517896561773, -2889241648411946534,
-6564663803938238204, -8060058171802589521, 581945337509520675, 3648778920718647903,
-4799698790548231394, -7602572252857820065, 220828013409515943, -1072987336855386047,
4287360518296753003, -4633371852008891965, 5513660857261085186, -2258542936462001533,
-8744380348503999773, 8746140185685648781, 228500091334420247, 1356187007457302238,
3019253992034194581, 3152601605678500003, -8793219284148773595, 5559581553696971176,
4916432985369275664, -8559797105120221417, -5802598197927043732, 2868348622579915573,
-7224052902810357288, -5894682518218493085, 2587672709781371173, -7706116723325376475,
3092343956317362483, -5561119517847711700, 972445599196498113, -1558506600978816441,
1708913533482282562, -2305554874185907314, -6005743014309462908, -6653329009633068701,
-483583197311151195, 2488075924621352812, -4529369641467339140, -4663743555056261452,
2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443,
628141331766346752, -4651421219668005332, -7750560848702540400, 7596648026010355826,
-3132152619100351065, 7834161864828164065, 7103445518877254909, 4390861237357459201,
-4780718172614204074, -319889632007444440, 622261699494173647, -3186110786557562560,
-8718967088789066690, -1948156510637662747, -8212195255998774408, -7028621931231314745,
2623071828615234808, -4066058308780939700, -5484966924888173764, -6683604512778046238,
-6756087640505506466, 5256026990536851868, 7841086888628396109, 6640857538655893162,
-8021284697816458310, -7109857044414059830, -1689021141511844405, -4298087301956291063,
-4077748265377282003, -998231156719803476, 2719520354384050532, 9132346697815513771,
4332154495710163773, -2085582442760428892, 6994721091344268833, -2556143461985726874,
-8567931991128098309, 59934747298466858, -3098398008776739403, -265597256199410390,
2332206071942466437, -7522315324568406181, 3154897383618636503, -7585605855467168281,
-6762850759087199275, 197309393502684135, -8579694182469508493, 2543179307861934850,
4350769010207485119, -4468719947444108136, -7207776534213261296, -1224312577878317200,
4287946071480840813, 8362686366770308971, 6486469209321732151, -5605644191012979782,
-1669018511020473564, 4450022655153542367, -7618176296641240059, -3896357471549267421,
-4596796223304447488, -6531150016257070659, -8982326463137525940, -4125325062227681798,
-1306489741394045544, -8338554946557245229, 5329160409530630596, 7790979528857726136,
4955070238059373407, -4304834761432101506, -6215295852904371179, 3007769226071157901,
-6753025801236972788, 8928702772696731736, 7856187920214445904, -4748497451462800923,
7900176660600710914, -7082800908938549136, -6797926979589575837, -6737316883512927978,
4186670094382025798, 1883939007446035042, -414705992779907823, 3734134241178479257,
4065968871360089196, 6953124200385847784, -7917685222115876751, -7585632937840318161,
-5567246375906782599, -5256612402221608788, 3106378204088556331, -2894472214076325998,
4565385105440252958, 1979884289539493806, -6891578849933910383, 3783206694208922581,
8464961209802336085, 2843963751609577687, 3030678195484896323, -4429654462759003204,
4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079,
1042662272908816815, -3666068979732206850, 2647678726283249984, 2144477441549833761,
-3417019821499388721, -2105601033380872185, 5916597177708541638, -8760774321402454447,
8833658097025758785, 5970273481425315300, 563813119381731307, -6455022486202078793,
1598828206250873866, -4016978389451217698, -2988328551145513985, -6071154634840136312,
8469693267274066490, 125672920241807416, -3912292412830714870, -2559617104544284221,
-486523741806024092, -4735332261862713930, 5923302823487327109, -9082480245771672572,
-1808429243461201518, 7990420780896957397, 4317817392807076702, 3625184369705367340,
-6482649271566653105, -3480272027152017464, -3225473396345736649, -368878695502291645,
-3981164001421868007, -8522033136963788610, 7609280429197514109, 3020985755112334161,
-2572049329799262942, 2635195723621160615, 5144520864246028816, -8188285521126945980,
1567242097116389047, 8172389260191636581, -2885551685425483535, -7060359469858316883,
-6480181133964513127, -7317004403633452381, 6011544915663598137, 5932255307352610768,
2241128460406315459, -8327867140638080220, 3094483003111372717, 4583857460292963101,
9079887171656594975, -384082854924064405, -3460631649611717935, 4225072055348026230,
-7385151438465742745, 3801620336801580414, -399845416774701952, -7446754431269675473,
7899055018877642622, 5421679761463003041, 5521102963086275121, -4975092593295409910,
8735487530905098534, -7462844945281082830, -2080886987197029914, -1000715163927557685,
-4253840471931071485, -5828896094657903328, 6424174453260338141, 359248545074932887,
-5949720754023045210, -2426265837057637212, 3030918217665093212, -9077771202237461772,
-3186796180789149575, 740416251634527158, -2142944401404840226, 6951781370868335478,
399922722363687927, -8928469722407522623, -1378421100515597285, -8343051178220066766,
-3030716356046100229, -8811767350470065420, 9026808440365124461, 6440783557497587732,
4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687,
-7316147128802486205, 7381039757301768559, 6157238513393239656, -1473377804940618233,
8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835,
7169176924412769570, -1281305539061572506, -7865612307799218120, 2278447439451174845,
3625338785743880657, 6477479539006708521, 8976185375579272206, -3712000482142939688,
1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045,
6346751753565857109, -8982212049534145501, -6127578587196093755, -245039190118465649,
-6320577374581628592, 7208698530190629697, 7276901792339343736, -7490986807540332668,
4133292154170828382, 2918308698224194548, -7703910638917631350, -3929437324238184044,
-4300543082831323144, -6344160503358350167, 5896236396443472108, -758328221503023383,
-1894351639983151068, -307900319840287220, -6278469401177312761, -2171292963361310674,
8382142935188824023, 9103922860780351547, 4152330101494654406,
}
)
type rngSource struct {
tap int // index into vec
feed int // index into vec
vec [rngLen]int64 // current feedback register
}
// seed rng x[n+1] = 48271 * x[n] mod (2**31 - 1)
func seedrand(x int32) int32 {
const (
A = 48271
Q = 44488
R = 3399
)
hi := x / Q
lo := x % Q
x = A*lo - R*hi
if x < 0 {
x += int32max
}
return x
}
// Seed uses the provided seed value to initialize the generator to a deterministic state.
func (rng *rngSource) Seed(seed int64) {
rng.tap = 0
rng.feed = rngLen - rngTap
seed = seed % int32max
if seed < 0 {
seed += int32max
}
if seed == 0 {
seed = 89482311
}
x := int32(seed)
for i := -20; i < rngLen; i++ {
x = seedrand(x)
if i >= 0 {
var u int64
u = int64(x) << 40
x = seedrand(x)
u ^= int64(x) << 20
x = seedrand(x)
u ^= int64(x)
u ^= rngCooked[i]
rng.vec[i] = u
}
}
}
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
func (rng *rngSource) Int63() int64 {
return int64(rng.Uint64() & rngMask)
}
// Uint64 returns a non-negative pseudo-random 64-bit integer as a uint64.
func (rng *rngSource) Uint64() uint64 {
rng.tap--
if rng.tap < 0 {
rng.tap += rngLen
}
rng.feed--
if rng.feed < 0 {
rng.feed += rngLen
}
x := rng.vec[rng.feed] + rng.vec[rng.tap]
rng.vec[rng.feed] = x
return uint64(x)
}

View File

@@ -1,77 +0,0 @@
// 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.
// W.Hormann, G.Derflinger:
// "Rejection-Inversion to Generate Variates
// from Monotone Discrete Distributions"
// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz
package rand
import "math"
// A Zipf generates Zipf distributed variates.
type Zipf struct {
r *Rand
imax float64
v float64
q float64
s float64
oneminusQ float64
oneminusQinv float64
hxm float64
hx0minusHxm float64
}
func (z *Zipf) h(x float64) float64 {
return math.Exp(z.oneminusQ*math.Log(z.v+x)) * z.oneminusQinv
}
func (z *Zipf) hinv(x float64) float64 {
return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v
}
// NewZipf returns a Zipf variate generator.
// The generator generates values k ∈ [0, imax]
// such that P(k) is proportional to (v + k) ** (-s).
// Requirements: s > 1 and v >= 1.
func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
z := new(Zipf)
if s <= 1.0 || v < 1 {
return nil
}
z.r = r
z.imax = float64(imax)
z.v = v
z.q = s
z.oneminusQ = 1.0 - z.q
z.oneminusQinv = 1.0 / z.oneminusQ
z.hxm = z.h(z.imax + 0.5)
z.hx0minusHxm = z.h(0.5) - math.Exp(math.Log(z.v)*(-z.q)) - z.hxm
z.s = 1 - z.hinv(z.h(1.5)-math.Exp(-z.q*math.Log(z.v+1.0)))
return z
}
// Uint64 returns a value drawn from the Zipf distribution described
// by the Zipf object.
func (z *Zipf) Uint64() uint64 {
if z == nil {
panic("rand: nil Zipf")
}
k := 0.0
for {
r := z.r.Float64() // r on [0,1]
ur := z.hxm + r*z.hx0minusHxm
x := z.hinv(ur)
k = math.Floor(x + 0.5)
if k-x <= z.s {
break
}
if ur >= z.h(k+0.5)-math.Exp(-math.Log(k+z.v)*z.q) {
break
}
}
return uint64(k)
}

View File

@@ -1,159 +0,0 @@
// Copyright 2010 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.
// General environment variables.
package os
import (
"syscall"
)
// Expand replaces ${var} or $var in the string based on the mapping function.
// For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv).
func Expand(s string, mapping func(string) string) string {
var buf []byte
// ${} is all ASCII, so bytes are fine for this operation.
i := 0
for j := 0; j < len(s); j++ {
if s[j] == '$' && j+1 < len(s) {
if buf == nil {
buf = make([]byte, 0, 2*len(s))
}
buf = append(buf, s[i:j]...)
name, w := getShellName(s[j+1:])
if name == "" && w > 0 {
// Encountered invalid syntax; eat the
// characters.
} else if name == "" {
// Valid syntax, but $ was not followed by a
// name. Leave the dollar character untouched.
buf = append(buf, s[j])
} else {
buf = append(buf, mapping(name)...)
}
j += w
i = j + 1
}
}
if buf == nil {
return s
}
return string(buf) + s[i:]
}
// ExpandEnv replaces ${var} or $var in the string according to the values
// of the current environment variables. References to undefined
// variables are replaced by the empty string.
func ExpandEnv(s string) string {
return Expand(s, Getenv)
}
// isShellSpecialVar reports whether the character identifies a special
// shell variable such as $*.
func isShellSpecialVar(c uint8) bool {
switch c {
case '*', '#', '$', '@', '!', '?', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return true
}
return false
}
// isAlphaNum reports whether the byte is an ASCII letter, number, or underscore.
func isAlphaNum(c uint8) bool {
return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
}
// getShellName returns the name that begins the string and the number of bytes
// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
// expansion and two more bytes are needed than the length of the name.
func getShellName(s string) (string, int) {
switch {
case s[0] == '{':
if len(s) > 2 && isShellSpecialVar(s[1]) && s[2] == '}' {
return s[1:2], 3
}
// Scan to closing brace
for i := 1; i < len(s); i++ {
if s[i] == '}' {
if i == 1 {
return "", 2 // Bad syntax; eat "${}"
}
return s[1:i], i + 1
}
}
return "", 1 // Bad syntax; eat "${"
case isShellSpecialVar(s[0]):
return s[0:1], 1
}
// Scan alphanumerics.
var i int
for i = 0; i < len(s) && isAlphaNum(s[i]); i++ {
}
return s[:i], i
}
// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
// To distinguish between an empty value and an unset value, use LookupEnv.
func Getenv(key string) string {
v, _ := syscall.Getenv(key)
return v
}
/* TODO(xsw):
func Getenv(key string) string {
return c.GoString(os.Getenv(c.AllocaCStr(key)))
}
*/
// LookupEnv retrieves the value of the environment variable named
// by the key. If the variable is present in the environment the
// value (which may be empty) is returned and the boolean is true.
// Otherwise the returned value will be empty and the boolean will
// be false.
func LookupEnv(key string) (string, bool) {
return syscall.Getenv(key)
}
// Setenv sets the value of the environment variable named by the key.
// It returns an error, if any.
func Setenv(key, value string) error {
err := syscall.Setenv(key, value)
if err != nil {
return NewSyscallError("setenv", err)
}
return nil
}
/* TODO(xsw):
func Setenv(key, value string) error {
ret := os.Setenv(c.AllocaCStr(key), c.AllocaCStr(value), 1)
if ret == 0 {
return nil
}
return &SyscallError{"setenv", syscall.Errno(ret)}
}
*/
// Unsetenv unsets a single environment variable.
func Unsetenv(key string) error {
return syscall.Unsetenv(key)
}
/* TODO(xsw):
func Unsetenv(key string) error {
ret := os.Unsetenv(c.AllocaCStr(key))
if ret == 0 {
return nil
}
return syscall.Errno(ret)
}
*/
// Environ returns a copy of strings representing the environment,
// in the form "key=value".
func Environ() []string {
return syscall.Environ()
}

View File

@@ -1,144 +0,0 @@
// 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 os
import (
"io/fs"
"syscall"
)
// Portable analogs of some common system call errors.
//
// Errors returned from this package may be tested against these errors
// with errors.Is.
var (
// ErrInvalid indicates an invalid argument.
// Methods on File will return this error when the receiver is nil.
ErrInvalid = fs.ErrInvalid // "invalid argument"
ErrPermission = fs.ErrPermission // "permission denied"
ErrExist = fs.ErrExist // "file already exists"
ErrNotExist = fs.ErrNotExist // "file does not exist"
ErrClosed = fs.ErrClosed // "file already closed"
// TODO(xsw):
// ErrNoDeadline = errNoDeadline() // "file type does not support deadline"
// ErrDeadlineExceeded = errDeadlineExceeded() // "i/o timeout"
)
// func errNoDeadline() error { return poll.ErrNoDeadline }
// errDeadlineExceeded returns the value for os.ErrDeadlineExceeded.
// This error comes from the internal/poll package, which is also
// used by package net. Doing it this way ensures that the net
// package will return os.ErrDeadlineExceeded for an exceeded deadline,
// as documented by net.Conn.SetDeadline, without requiring any extra
// work in the net package and without requiring the internal/poll
// package to import os (which it can't, because that would be circular).
// func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded }
type timeout interface {
Timeout() bool
}
// PathError records an error and the operation and file path that caused it.
type PathError = fs.PathError
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
Err error
}
func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
func (e *SyscallError) Unwrap() error { return e.Err }
// Timeout reports whether this error represents a timeout.
func (e *SyscallError) Timeout() bool {
t, ok := e.Err.(timeout)
return ok && t.Timeout()
}
// NewSyscallError returns, as an error, a new SyscallError
// with the given system call name and error details.
// As a convenience, if err is nil, NewSyscallError returns nil.
func NewSyscallError(syscall string, err error) error {
if err == nil {
return nil
}
return &SyscallError{syscall, err}
}
// IsExist returns a boolean indicating whether the error is known to report
// that a file or directory already exists. It is satisfied by ErrExist 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.ErrExist).
func IsExist(err error) bool {
return underlyingErrorIs(err, ErrExist)
}
// 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).
func IsNotExist(err error) bool {
return underlyingErrorIs(err, ErrNotExist)
}
// IsPermission returns a boolean indicating whether the error is known to
// report that permission is denied. It is satisfied by ErrPermission 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.ErrPermission).
func IsPermission(err error) bool {
return underlyingErrorIs(err, ErrPermission)
}
// IsTimeout returns a boolean indicating whether the error is known
// to report that a timeout occurred.
//
// This function predates errors.Is, and the notion of whether an
// error indicates a timeout can be ambiguous. For example, the Unix
// error EWOULDBLOCK sometimes indicates a timeout and sometimes does not.
// New code should use errors.Is with a value appropriate to the call
// returning the error, such as os.ErrDeadlineExceeded.
func IsTimeout(err error) bool {
terr, ok := underlyingError(err).(timeout)
return ok && terr.Timeout()
}
type syscallErrorType = syscall.Errno
func underlyingErrorIs(err, target error) bool {
// Note that this function is not errors.Is:
// underlyingError only unwraps the specific error-wrapping types
// that it historically did, not all errors implementing Unwrap().
err = underlyingError(err)
if err == target {
return true
}
// To preserve prior behavior, only examine syscall errors.
e, ok := err.(syscallErrorType)
return ok && e.Is(target)
}
// underlyingError returns the underlying error for known os error types.
func underlyingError(err error) error {
switch err := err.(type) {
case *PathError:
return err.Err
case *LinkError:
return err.Err
case *SyscallError:
return err.Err
}
return err
}

View File

@@ -1,172 +0,0 @@
// 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 os
import (
"errors"
"runtime"
"sync"
"sync/atomic"
"syscall"
"time"
)
// ErrProcessDone indicates a Process has finished.
var ErrProcessDone = errors.New("os: process already finished")
// Process stores the information about a process created by StartProcess.
type Process struct {
Pid int
handle uintptr // handle is accessed atomically on Windows
isdone atomic.Bool // process has been successfully waited on
sigMu sync.RWMutex // avoid race between wait and signal
}
func newProcess(pid int, handle uintptr) *Process {
p := &Process{Pid: pid, handle: handle}
runtime.SetFinalizer(p, (*Process).Release)
return p
}
func (p *Process) setDone() {
p.isdone.Store(true)
}
func (p *Process) done() bool {
return p.isdone.Load()
}
// ProcAttr holds the attributes that will be applied to a new process
// started by StartProcess.
type ProcAttr struct {
// If Dir is non-empty, the child changes into the directory before
// creating the process.
Dir string
// If Env is non-nil, it gives the environment variables for the
// new process in the form returned by Environ.
// If it is nil, the result of Environ will be used.
Env []string
// Files specifies the open files inherited by the new process. The
// first three entries correspond to standard input, standard output, and
// standard error. An implementation may support additional entries,
// depending on the underlying operating system. A nil entry corresponds
// to that file being closed when the process starts.
// On Unix systems, StartProcess will change these File values
// to blocking mode, which means that SetDeadline will stop working
// and calling Close will not interrupt a Read or Write.
Files []*File
// Operating system-specific process creation attributes.
// Note that setting this field means that your program
// may not execute properly or even compile on some
// operating systems.
Sys *syscall.SysProcAttr
}
// A Signal represents an operating system signal.
// The usual underlying implementation is operating system-dependent:
// on Unix it is syscall.Signal.
type Signal interface {
String() string
Signal() // to distinguish from other Stringers
}
// FindProcess looks for a running process by its pid.
//
// The Process it returns can be used to obtain information
// about the underlying operating system process.
//
// On Unix systems, FindProcess always succeeds and returns a Process
// for the given pid, regardless of whether the process exists. To test whether
// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports
// an error.
func FindProcess(pid int) (*Process, error) {
return findProcess(pid)
}
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr. The argv slice will become os.Args in the
// new process, so it normally starts with the program name.
//
// If the calling goroutine has locked the operating system thread
// with runtime.LockOSThread and modified any inheritable OS-level
// thread state (for example, Linux or Plan 9 name spaces), the new
// process will inherit the caller's thread state.
//
// StartProcess is a low-level interface. The os/exec package provides
// higher-level interfaces.
//
// If there is an error, it will be of type *PathError.
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
return startProcess(name, argv, attr)
}
// Release releases any resources associated with the Process p,
// rendering it unusable in the future.
// Release only needs to be called if Wait is not.
func (p *Process) Release() error {
return p.release()
}
// Kill causes the Process to exit immediately. Kill does not wait until
// the Process has actually exited. This only kills the Process itself,
// not any other processes it may have started.
func (p *Process) Kill() error {
return p.kill()
}
// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
// On most operating systems, the Process must be a child
// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
return p.wait()
}
// Signal sends a signal to the Process.
// Sending Interrupt on Windows is not implemented.
func (p *Process) Signal(sig Signal) error {
return p.signal(sig)
}
// UserTime returns the user CPU time of the exited process and its children.
func (p *ProcessState) UserTime() time.Duration {
return p.userTime()
}
// SystemTime returns the system CPU time of the exited process and its children.
func (p *ProcessState) SystemTime() time.Duration {
return p.systemTime()
}
// Exited reports whether the program has exited.
// On Unix systems this reports true if the program exited due to calling exit,
// but false if the program terminated due to a signal.
func (p *ProcessState) Exited() bool {
return p.exited()
}
// Success reports whether the program exited successfully,
// such as with exit status 0 on Unix.
func (p *ProcessState) Success() bool {
return p.success()
}
// Sys returns system-dependent exit information about
// the process. Convert it to the appropriate underlying
// type, such as syscall.WaitStatus on Unix, to access its contents.
func (p *ProcessState) Sys() any {
return p.sys()
}
// SysUsage returns system-dependent resource usage information about
// the exited process. Convert it to the appropriate underlying
// type, such as *syscall.Rusage on Unix, to access its contents.
// (On Unix, *syscall.Rusage matches struct rusage as defined in the
// getrusage(2) manual page.)
func (p *ProcessState) SysUsage() any {
return p.sysUsage()
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +0,0 @@
// Copyright 2019 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 exec
import "io/fs"
// skipStdinCopyError optionally specifies a function which reports
// whether the provided stdin copy error should be ignored.
func skipStdinCopyError(err error) bool {
// Ignore hungup errors copying to stdin if the program
// completed successfully otherwise.
// See Issue 35753.
pe, ok := err.(*fs.PathError)
return ok &&
pe.Op == "write" && pe.Path == "|1" &&
pe.Err.Error() == "i/o on hungup channel"
}

View File

@@ -1,24 +0,0 @@
// Copyright 2015 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:build !plan9 && !windows
package exec
import (
"io/fs"
"syscall"
)
// skipStdinCopyError optionally specifies a function which reports
// whether the provided stdin copy error should be ignored.
func skipStdinCopyError(err error) bool {
// Ignore EPIPE errors copying to stdin if the program
// completed successfully otherwise.
// See Issue 9173.
pe, ok := err.(*fs.PathError)
return ok &&
pe.Op == "write" && pe.Path == "|1" &&
pe.Err == syscall.EPIPE
}

View File

@@ -1,23 +0,0 @@
// Copyright 2017 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 exec
import (
"io/fs"
"syscall"
)
// skipStdinCopyError optionally specifies a function which reports
// whether the provided stdin copy error should be ignored.
func skipStdinCopyError(err error) bool {
// Ignore ERROR_BROKEN_PIPE and ERROR_NO_DATA errors copying
// to stdin if the program completed successfully otherwise.
// See Issue 20445.
const _ERROR_NO_DATA = syscall.Errno(0xe8)
pe, ok := err.(*fs.PathError)
return ok &&
pe.Op == "write" && pe.Path == "|1" &&
(pe.Err == syscall.ERROR_BROKEN_PIPE || pe.Err == _ERROR_NO_DATA)
}

View File

@@ -1,66 +0,0 @@
// Copyright 2011 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 exec
import (
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
var ErrNotFound = errors.New("executable file not found in $path")
func findExecutable(file string) error {
d, err := os.Stat(file)
if err != nil {
return err
}
if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
return nil
}
return fs.ErrPermission
}
// LookPath searches for an executable named file in the
// directories named by the path environment variable.
// If file begins with "/", "#", "./", or "../", it is tried
// directly and the path is not consulted.
// On success, the result is an absolute path.
//
// In older versions of Go, LookPath could return a path relative to the current directory.
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
// errors.Is(err, ErrDot). See the package documentation for more details.
func LookPath(file string) (string, error) {
// skip the path lookup for these prefixes
skip := []string{"/", "#", "./", "../"}
for _, p := range skip {
if strings.HasPrefix(file, p) {
err := findExecutable(file)
if err == nil {
return file, nil
}
return "", &Error{file, err}
}
}
path := os.Getenv("path")
for _, dir := range filepath.SplitList(path) {
path := filepath.Join(dir, file)
if err := findExecutable(path); err == nil {
if !filepath.IsAbs(path) {
if execerrdot.Value() != "0" {
return path, &Error{file, ErrDot}
}
execerrdot.IncNonDefault()
}
return path, nil
}
}
return "", &Error{file, ErrNotFound}
}

View File

@@ -1,84 +0,0 @@
// Copyright 2010 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:build unix
package exec
import (
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
"syscall"
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
var ErrNotFound = errors.New("executable file not found in $PATH")
func findExecutable(file string) error {
d, err := os.Stat(file)
if err != nil {
return err
}
m := d.Mode()
if m.IsDir() {
return syscall.EISDIR
}
err = unixEaccess(file, unix_X_OK)
// ENOSYS means Eaccess is not available or not implemented.
// EPERM can be returned by Linux containers employing seccomp.
// In both cases, fall back to checking the permission bits.
if err == nil || (err != syscall.ENOSYS && err != syscall.EPERM) {
return err
}
if m&0111 != 0 {
return nil
}
return fs.ErrPermission
}
// LookPath searches for an executable named file in the
// directories named by the PATH environment variable.
// If file contains a slash, it is tried directly and the PATH is not consulted.
// Otherwise, on success, the result is an absolute path.
//
// In older versions of Go, LookPath could return a path relative to the current directory.
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
// errors.Is(err, ErrDot). See the package documentation for more details.
func LookPath(file string) (string, error) {
// NOTE(rsc): I wish we could use the Plan 9 behavior here
// (only bypass the path if file begins with / or ./ or ../)
// but that would not match all the Unix shells.
if strings.Contains(file, "/") {
err := findExecutable(file)
if err == nil {
return file, nil
}
return "", &Error{file, err}
}
path := os.Getenv("PATH")
for _, dir := range filepath.SplitList(path) {
if dir == "" {
// Unix shell semantics: path element "" means "."
dir = "."
}
path := filepath.Join(dir, file)
if err := findExecutable(path); err == nil {
if !filepath.IsAbs(path) {
/* TODO(xsw):
if execerrdot.Value() != "0" {
return path, &Error{file, ErrDot}
}
execerrdot.IncNonDefault()
*/
panic("todo: exec.LookPath: !filepath.IsAbs(path)")
}
return path, nil
}
}
return "", &Error{file, ErrNotFound}
}

View File

@@ -1,23 +0,0 @@
// Copyright 2018 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:build wasm
package exec
import (
"errors"
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
var ErrNotFound = errors.New("executable file not found in $PATH")
// LookPath searches for an executable named file in the
// directories named by the PATH environment variable.
// If file contains a slash, it is tried directly and the PATH is not consulted.
// The result may be an absolute path or a path relative to the current directory.
func LookPath(file string) (string, error) {
// Wasm can not execute processes, so act as if there are no executables at all.
return "", &Error{file, ErrNotFound}
}

View File

@@ -1,145 +0,0 @@
// Copyright 2010 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 exec
import (
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
"syscall"
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
var ErrNotFound = errors.New("executable file not found in %PATH%")
func chkStat(file string) error {
d, err := os.Stat(file)
if err != nil {
return err
}
if d.IsDir() {
return fs.ErrPermission
}
return nil
}
func hasExt(file string) bool {
i := strings.LastIndex(file, ".")
if i < 0 {
return false
}
return strings.LastIndexAny(file, `:\/`) < i
}
func findExecutable(file string, exts []string) (string, error) {
if len(exts) == 0 {
return file, chkStat(file)
}
if hasExt(file) {
if chkStat(file) == nil {
return file, nil
}
}
for _, e := range exts {
if f := file + e; chkStat(f) == nil {
return f, nil
}
}
return "", fs.ErrNotExist
}
// LookPath searches for an executable named file in the
// directories named by the PATH environment variable.
// LookPath also uses PATHEXT environment variable to match
// a suitable candidate.
// If file contains a slash, it is tried directly and the PATH is not consulted.
// Otherwise, on success, the result is an absolute path.
//
// In older versions of Go, LookPath could return a path relative to the current directory.
// As of Go 1.19, LookPath will instead return that path along with an error satisfying
// errors.Is(err, ErrDot). See the package documentation for more details.
func LookPath(file string) (string, error) {
var exts []string
x := os.Getenv(`PATHEXT`)
if x != "" {
for _, e := range strings.Split(strings.ToLower(x), `;`) {
if e == "" {
continue
}
if e[0] != '.' {
e = "." + e
}
exts = append(exts, e)
}
} else {
exts = []string{".com", ".exe", ".bat", ".cmd"}
}
if strings.ContainsAny(file, `:\/`) {
f, err := findExecutable(file, exts)
if err == nil {
return f, nil
}
return "", &Error{file, err}
}
// On Windows, creating the NoDefaultCurrentDirectoryInExePath
// environment variable (with any value or no value!) signals that
// path lookups should skip the current directory.
// In theory we are supposed to call NeedCurrentDirectoryForExePathW
// "as the registry location of this environment variable can change"
// but that seems exceedingly unlikely: it would break all users who
// have configured their environment this way!
// https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-needcurrentdirectoryforexepathw
// See also go.dev/issue/43947.
var (
dotf string
dotErr error
)
if _, found := syscall.Getenv("NoDefaultCurrentDirectoryInExePath"); !found {
if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
if execerrdot.Value() == "0" {
execerrdot.IncNonDefault()
return f, nil
}
dotf, dotErr = f, &Error{file, ErrDot}
}
}
path := os.Getenv("path")
for _, dir := range filepath.SplitList(path) {
if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
if dotErr != nil {
// https://go.dev/issue/53536: if we resolved a relative path implicitly,
// and it is the same executable that would be resolved from the explicit %PATH%,
// prefer the explicit name for the executable (and, likely, no error) instead
// of the equivalent implicit name with ErrDot.
//
// Otherwise, return the ErrDot for the implicit path as soon as we find
// out that the explicit one doesn't match.
dotfi, dotfiErr := os.Lstat(dotf)
fi, fiErr := os.Lstat(f)
if dotfiErr != nil || fiErr != nil || !os.SameFile(dotfi, fi) {
return dotf, dotErr
}
}
if !filepath.IsAbs(f) {
if execerrdot.Value() != "0" {
return f, &Error{file, ErrDot}
}
execerrdot.IncNonDefault()
}
return f, nil
}
}
if dotErr != nil {
return dotf, dotErr
}
return "", &Error{file, ErrNotFound}
}

View File

@@ -1,13 +0,0 @@
// 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.
//go:build unix
package exec
const (
unix_R_OK = 0x4
unix_W_OK = 0x2
unix_X_OK = 0x1
)

View File

@@ -1,15 +0,0 @@
// 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 exec
import (
"syscall"
"github.com/goplus/llgo/c/syscall/unix"
)
func unixEaccess(path string, mode uint32) error {
return syscall.Faccessat(unix.AT_FDCWD, path, mode, unix.AT_EACCESS)
}

View File

@@ -1,13 +0,0 @@
// 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.
//go:build unix && !linux
package exec
import "syscall"
func unixEaccess(path string, mode uint32) error {
return syscall.ENOSYS
}

View File

@@ -1,149 +0,0 @@
// 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 os
import (
"internal/itoa"
"runtime"
"syscall"
"time"
)
// The only signal values guaranteed to be present in the os package
// on all systems are Interrupt (send the process an interrupt) and
// Kill (force the process to exit). Interrupt is not implemented on
// Windows; using it with os.Process.Signal will return an error.
var (
Interrupt Signal = syscall.Note("interrupt")
Kill Signal = syscall.Note("kill")
)
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
Sys: attr.Sys,
}
sysattr.Files = make([]uintptr, 0, len(attr.Files))
for _, f := range attr.Files {
sysattr.Files = append(sysattr.Files, f.Fd())
}
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if e != nil {
return nil, &PathError{Op: "fork/exec", Path: name, Err: e}
}
return newProcess(pid, h), nil
}
func (p *Process) writeProcFile(file string, data string) error {
f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0)
if e != nil {
return e
}
defer f.Close()
_, e = f.Write([]byte(data))
return e
}
func (p *Process) signal(sig Signal) error {
if p.done() {
return ErrProcessDone
}
if e := p.writeProcFile("note", sig.String()); e != nil {
return NewSyscallError("signal", e)
}
return nil
}
func (p *Process) kill() error {
return p.signal(Kill)
}
func (p *Process) wait() (ps *ProcessState, err error) {
var waitmsg syscall.Waitmsg
if p.Pid == -1 {
return nil, ErrInvalid
}
err = syscall.WaitProcess(p.Pid, &waitmsg)
if err != nil {
return nil, NewSyscallError("wait", err)
}
p.setDone()
ps = &ProcessState{
pid: waitmsg.Pid,
status: &waitmsg,
}
return ps, nil
}
func (p *Process) release() error {
// NOOP for Plan 9.
p.Pid = -1
// no need for a finalizer anymore
runtime.SetFinalizer(p, nil)
return nil
}
func findProcess(pid int) (p *Process, err error) {
// NOOP for Plan 9.
return newProcess(pid, 0), nil
}
// ProcessState stores information about a process, as reported by Wait.
type ProcessState struct {
pid int // The process's id.
status *syscall.Waitmsg // System-dependent status info.
}
// Pid returns the process id of the exited process.
func (p *ProcessState) Pid() int {
return p.pid
}
func (p *ProcessState) exited() bool {
return p.status.Exited()
}
func (p *ProcessState) success() bool {
return p.status.ExitStatus() == 0
}
func (p *ProcessState) sys() any {
return p.status
}
func (p *ProcessState) sysUsage() any {
return p.status
}
func (p *ProcessState) userTime() time.Duration {
return time.Duration(p.status.Time[0]) * time.Millisecond
}
func (p *ProcessState) systemTime() time.Duration {
return time.Duration(p.status.Time[1]) * time.Millisecond
}
func (p *ProcessState) String() string {
if p == nil {
return "<nil>"
}
return "exit status: " + p.status.Msg
}
// ExitCode returns the exit code of the exited process, or -1
// if the process hasn't exited or was terminated by a signal.
func (p *ProcessState) ExitCode() int {
// return -1 if the process hasn't started.
if p == nil {
return -1
}
return p.status.ExitStatus()
}

View File

@@ -1,138 +0,0 @@
// 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.
//go:build unix || (js && wasm) || wasip1 || windows
package os
import (
"runtime"
"syscall"
"github.com/goplus/llgo/internal/lib/internal/itoa"
"github.com/goplus/llgo/internal/lib/internal/syscall/execenv"
)
// The only signal values guaranteed to be present in the os package on all
// systems are os.Interrupt (send the process an interrupt) and os.Kill (force
// the process to exit). On Windows, sending os.Interrupt to a process with
// os.Process.Signal is not implemented; it will return an error instead of
// sending a signal.
var (
Interrupt Signal = syscall.SIGINT
Kill Signal = syscall.SIGKILL
)
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
// If there is no SysProcAttr (ie. no Chroot or changed
// UID/GID), double-check existence of the directory we want
// to chdir into. We can make the error clearer this way.
if attr != nil && attr.Sys == nil && attr.Dir != "" {
if _, err := Stat(attr.Dir); err != nil {
pe := err.(*PathError)
pe.Op = "chdir"
return nil, pe
}
}
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
Sys: attr.Sys,
}
if sysattr.Env == nil {
sysattr.Env, err = execenv.Default(sysattr.Sys)
if err != nil {
return nil, err
}
}
sysattr.Files = make([]uintptr, 0, len(attr.Files))
for _, f := range attr.Files {
sysattr.Files = append(sysattr.Files, f.Fd())
}
pid, h, e := syscall.StartProcess(name, argv, sysattr)
// TODO(xsw):
// Make sure we don't run the finalizers of attr.Files.
// runtime.KeepAlive(attr)
if e != nil {
return nil, &PathError{Op: "fork/exec", Path: name, Err: e}
}
return newProcess(pid, h), nil
}
func (p *Process) kill() error {
return p.Signal(Kill)
}
// ProcessState stores information about a process, as reported by Wait.
type ProcessState struct {
pid int // The process's id.
status syscall.WaitStatus // System-dependent status info.
rusage *syscall.Rusage
}
// Pid returns the process id of the exited process.
func (p *ProcessState) Pid() int {
return p.pid
}
func (p *ProcessState) exited() bool {
return p.status.Exited()
}
func (p *ProcessState) success() bool {
return p.status.ExitStatus() == 0
}
func (p *ProcessState) sys() any {
return p.status
}
func (p *ProcessState) sysUsage() any {
return p.rusage
}
func (p *ProcessState) String() string {
if p == nil {
return "<nil>"
}
status := p.Sys().(syscall.WaitStatus)
res := ""
switch {
case status.Exited():
code := status.ExitStatus()
if runtime.GOOS == "windows" && uint(code) >= 1<<16 { // windows uses large hex numbers
res = "exit status " + uitox(uint(code))
} else { // unix systems use small decimal integers
res = "exit status " + itoa.Itoa(code) // unix
}
case status.Signaled():
res = "signal: " + status.Signal().String()
case status.Stopped():
res = "stop signal: " + status.StopSignal().String()
if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
res += " (trap " + itoa.Itoa(status.TrapCause()) + ")"
}
case status.Continued():
res = "continued"
}
if status.CoreDump() {
res += " (core dumped)"
}
return res
}
// ExitCode returns the exit code of the exited process, or -1
// if the process hasn't exited or was terminated by a signal.
func (p *ProcessState) ExitCode() int {
// return -1 if the process hasn't started.
if p == nil {
return -1
}
return p.status.ExitStatus()
}

View File

@@ -1,106 +0,0 @@
// 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.
//go:build unix || (js && wasm) || wasip1
package os
import (
"errors"
"runtime"
"syscall"
"time"
)
func (p *Process) wait() (ps *ProcessState, err error) {
if p.Pid == -1 {
return nil, syscall.EINVAL
}
// If we can block until Wait4 will succeed immediately, do so.
ready, err := p.blockUntilWaitable()
if err != nil {
return nil, err
}
if ready {
// Mark the process done now, before the call to Wait4,
// so that Process.signal will not send a signal.
p.setDone()
// Acquire a write lock on sigMu to wait for any
// active call to the signal method to complete.
p.sigMu.Lock()
p.sigMu.Unlock()
}
var (
status syscall.WaitStatus
rusage syscall.Rusage
pid1 int
e error
)
for {
pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage)
if e != syscall.EINTR {
break
}
}
if e != nil {
return nil, NewSyscallError("wait", e)
}
if pid1 != 0 {
p.setDone()
}
ps = &ProcessState{
pid: pid1,
status: status,
rusage: &rusage,
}
return ps, nil
}
func (p *Process) signal(sig Signal) error {
if p.Pid == -1 {
return errors.New("os: process already released")
}
if p.Pid == 0 {
return errors.New("os: process not initialized")
}
p.sigMu.RLock()
defer p.sigMu.RUnlock()
if p.done() {
return ErrProcessDone
}
s, ok := sig.(syscall.Signal)
if !ok {
return errors.New("os: unsupported signal type")
}
if e := syscall.Kill(p.Pid, s); e != nil {
if e == syscall.ESRCH {
return ErrProcessDone
}
return e
}
return nil
}
func (p *Process) release() error {
// NOOP for unix.
p.Pid = -1
// no need for a finalizer anymore
runtime.SetFinalizer(p, nil)
return nil
}
func findProcess(pid int) (p *Process, err error) {
// NOOP for unix.
return newProcess(pid, 0), nil
}
func (p *ProcessState) userTime() time.Duration {
return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond
}
func (p *ProcessState) systemTime() time.Duration {
return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond
}

View File

@@ -1,183 +0,0 @@
// 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 os
import (
"internal/syscall/windows"
"runtime"
"sync/atomic"
"syscall"
"time"
)
func (p *Process) wait() (ps *ProcessState, err error) {
/* TODO(xsw):
handle := atomic.LoadUintptr(&p.handle)
s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE)
switch s {
case syscall.WAIT_OBJECT_0:
break
case syscall.WAIT_FAILED:
return nil, NewSyscallError("WaitForSingleObject", e)
default:
return nil, errors.New("os: unexpected result from WaitForSingleObject")
}
var ec uint32
e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec)
if e != nil {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
var u syscall.Rusage
e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
if e != nil {
return nil, NewSyscallError("GetProcessTimes", e)
}
p.setDone()
// NOTE(brainman): It seems that sometimes process is not dead
// when WaitForSingleObject returns. But we do not know any
// other way to wait for it. Sleeping for a while seems to do
// the trick sometimes.
// See https://golang.org/issue/25965 for details.
defer time.Sleep(5 * time.Millisecond)
defer p.Release()
return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
*/
panic("todo: os.Process.wait")
}
func (p *Process) signal(sig Signal) error {
handle := atomic.LoadUintptr(&p.handle)
if handle == uintptr(syscall.InvalidHandle) {
return syscall.EINVAL
}
if p.done() {
return ErrProcessDone
}
if sig == Kill {
var terminationHandle syscall.Handle
e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0)
if e != nil {
return NewSyscallError("DuplicateHandle", e)
}
runtime.KeepAlive(p)
defer syscall.CloseHandle(terminationHandle)
e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1)
return NewSyscallError("TerminateProcess", e)
}
// TODO(rsc): Handle Interrupt too?
return syscall.Errno(syscall.EWINDOWS)
}
func (p *Process) release() error {
handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle))
if handle == uintptr(syscall.InvalidHandle) {
return syscall.EINVAL
}
e := syscall.CloseHandle(syscall.Handle(handle))
if e != nil {
return NewSyscallError("CloseHandle", e)
}
// no need for a finalizer anymore
runtime.SetFinalizer(p, nil)
return nil
}
func findProcess(pid int) (p *Process, err error) {
const da = syscall.STANDARD_RIGHTS_READ |
syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
h, e := syscall.OpenProcess(da, false, uint32(pid))
if e != nil {
return nil, NewSyscallError("OpenProcess", e)
}
return newProcess(pid, uintptr(h)), nil
}
func init() {
cmd := windows.UTF16PtrToString(syscall.GetCommandLine())
if len(cmd) == 0 {
arg0, _ := Executable()
Args = []string{arg0}
} else {
Args = commandLineToArgv(cmd)
}
}
// appendBSBytes appends n '\\' bytes to b and returns the resulting slice.
func appendBSBytes(b []byte, n int) []byte {
for ; n > 0; n-- {
b = append(b, '\\')
}
return b
}
// readNextArg splits command line string cmd into next
// argument and command line remainder.
func readNextArg(cmd string) (arg []byte, rest string) {
var b []byte
var inquote bool
var nslash int
for ; len(cmd) > 0; cmd = cmd[1:] {
c := cmd[0]
switch c {
case ' ', '\t':
if !inquote {
return appendBSBytes(b, nslash), cmd[1:]
}
case '"':
b = appendBSBytes(b, nslash/2)
if nslash%2 == 0 {
// use "Prior to 2008" rule from
// http://daviddeley.com/autohotkey/parameters/parameters.htm
// section 5.2 to deal with double double quotes
if inquote && len(cmd) > 1 && cmd[1] == '"' {
b = append(b, c)
cmd = cmd[1:]
}
inquote = !inquote
} else {
b = append(b, c)
}
nslash = 0
continue
case '\\':
nslash++
continue
}
b = appendBSBytes(b, nslash)
nslash = 0
b = append(b, c)
}
return appendBSBytes(b, nslash), ""
}
// commandLineToArgv splits a command line into individual argument
// strings, following the Windows conventions documented
// at http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
func commandLineToArgv(cmd string) []string {
var args []string
for len(cmd) > 0 {
if cmd[0] == ' ' || cmd[0] == '\t' {
cmd = cmd[1:]
continue
}
var arg []byte
arg, cmd = readNextArg(cmd)
args = append(args, string(arg))
}
return args
}
func ftToDuration(ft *syscall.Filetime) time.Duration {
n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
return time.Duration(n*100) * time.Nanosecond
}
func (p *ProcessState) userTime() time.Duration {
return ftToDuration(&p.rusage.UserTime)
}
func (p *ProcessState) systemTime() time.Duration {
return ftToDuration(&p.rusage.KernelTime)
}

View File

@@ -1,530 +0,0 @@
// 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 os
import (
"errors"
"io"
"syscall"
"time"
)
// Name returns the name of the file as presented to Open.
func (f *File) Name() string { return f.name }
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
// standard output, and standard error file descriptors.
//
// Note that the Go runtime writes to standard error for panics and crashes;
// closing Stderr may cause those messages to go elsewhere, perhaps
// to a file opened later.
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
// Flags to OpenFile wrapping those of the underlying system. Not all
// flags may be implemented on a given system.
const (
// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
O_RDONLY int = syscall.O_RDONLY // open the file read-only.
O_WRONLY int = syscall.O_WRONLY // open the file write-only.
O_RDWR int = syscall.O_RDWR // open the file read-write.
// The remaining values may be or'ed in to control behavior.
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist.
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.
)
// Seek whence values.
//
// Deprecated: Use io.SeekStart, io.SeekCurrent, and io.SeekEnd.
const (
SEEK_SET int = 0 // seek relative to the origin of the file
SEEK_CUR int = 1 // seek relative to the current offset
SEEK_END int = 2 // seek relative to the end
)
// Read reads up to len(b) bytes from the File and stores them in b.
// It returns the number of bytes read and any error encountered.
// At end of file, Read returns 0, io.EOF.
func (f *File) Read(b []byte) (n int, err error) {
if err := f.checkValid("read"); err != nil {
return 0, err
}
n, e := f.read(b)
return n, f.wrapErr("read", e)
}
// ReadAt reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// ReadAt always returns a non-nil error when n < len(b).
// At end of file, that error is io.EOF.
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
/*
if err := f.checkValid("read"); err != nil {
return 0, err
}
if off < 0 {
return 0, &PathError{Op: "readat", Path: f.name, Err: errors.New("negative offset")}
}
for len(b) > 0 {
m, e := f.pread(b, off)
if e != nil {
err = f.wrapErr("read", e)
break
}
n += m
b = b[m:]
off += int64(m)
}
return
*/
panic("todo: os.File.ReadAt")
}
// ReadFrom implements io.ReaderFrom.
func (f *File) ReadFrom(r io.Reader) (n int64, err error) {
/*
if err := f.checkValid("write"); err != nil {
return 0, err
}
n, handled, e := f.readFrom(r)
if !handled {
return genericReadFrom(f, r) // without wrapping
}
return n, f.wrapErr("write", e)
*/
panic("todo: os.File.ReadFrom")
}
func genericReadFrom(f *File, r io.Reader) (int64, error) {
return io.Copy(fileWithoutReadFrom{f}, r)
}
// fileWithoutReadFrom implements all the methods of *File other
// than ReadFrom. This is used to permit ReadFrom to call io.Copy
// without leading to a recursive call to ReadFrom.
type fileWithoutReadFrom struct {
*File
}
// This ReadFrom method hides the *File ReadFrom method.
func (fileWithoutReadFrom) ReadFrom(fileWithoutReadFrom) {
panic("unreachable")
}
// Write writes len(b) bytes from b to the File.
// It returns the number of bytes written and an error, if any.
// Write returns a non-nil error when n != len(b).
func (f *File) Write(b []byte) (n int, err error) {
if err := f.checkValid("write"); err != nil {
return 0, err
}
n, e := f.write(b)
// TODO(xsw):
// epipecheck(f, e)
if e != nil {
err = f.wrapErr("write", e)
} else if n != len(b) {
err = io.ErrShortWrite
}
return n, err
}
var errWriteAtInAppendMode = errors.New("os: invalid use of WriteAt on file opened with O_APPEND")
// WriteAt writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
// WriteAt returns a non-nil error when n != len(b).
//
// If file was opened with the O_APPEND flag, WriteAt returns an error.
func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
/*
if err := f.checkValid("write"); err != nil {
return 0, err
}
if f.appendMode {
return 0, errWriteAtInAppendMode
}
if off < 0 {
return 0, &PathError{Op: "writeat", Path: f.name, Err: errors.New("negative offset")}
}
for len(b) > 0 {
m, e := f.pwrite(b, off)
if e != nil {
err = f.wrapErr("write", e)
break
}
n += m
b = b[m:]
off += int64(m)
}
return
*/
panic("todo: os.(*File).WriteAt")
}
// Seek sets the offset for the next Read or Write on file to offset, interpreted
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
// The behavior of Seek on a file opened with O_APPEND is not specified.
func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
/*
if err := f.checkValid("seek"); err != nil {
return 0, err
}
r, e := f.seek(offset, whence)
if e == nil && f.dirinfo != nil && r != 0 {
e = syscall.EISDIR
}
if e != nil {
return 0, f.wrapErr("seek", e)
}
return r, nil
*/
panic("todo: os.(*File).Seek")
}
// WriteString is like Write, but writes the contents of string s rather than
// a slice of bytes.
func (f *File) WriteString(s string) (n int, err error) {
/*
b := unsafe.Slice(unsafe.StringData(s), len(s))
return f.Write(b)
*/
panic("todo: os.(*File).WriteString")
}
// setStickyBit adds ModeSticky to the permission bits of path, non atomic.
func setStickyBit(name string) error {
fi, err := Stat(name)
if err != nil {
return err
}
return Chmod(name, fi.Mode()|ModeSticky)
}
// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
// Create creates or truncates the named file. If the file already exists,
// it is truncated. If the file does not exist, it is created with mode 0666
// (before umask). If successful, methods on the returned File can
// be used for I/O; the associated file descriptor has mode O_RDWR.
// If there is an error, it will be of type *PathError.
func Create(name string) (*File, error) {
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}
// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.). If the file does not exist, and the O_CREATE flag
// is passed, it is created with mode perm (before umask). If successful,
// methods on the returned File can be used for I/O.
// If there is an error, it will be of type *PathError.
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
f, err := openFileNolog(name, flag, perm)
if err != nil {
return nil, err
}
f.appendMode = flag&O_APPEND != 0
return f, nil
}
/*
// lstat is overridden in tests.
var lstat = Lstat
// Many functions in package syscall return a count of -1 instead of 0.
// Using fixCount(call()) instead of call() corrects the count.
func fixCount(n int, err error) (int, error) {
if n < 0 {
n = 0
}
return n, err
}
*/
// TODO(xsw):
// checkWrapErr is the test hook to enable checking unexpected wrapped errors of poll.ErrFileClosing.
// It is set to true in the export_test.go for tests (including fuzz tests).
// var checkWrapErr = false
// wrapErr wraps an error that occurred during an operation on an open file.
// It passes io.EOF through unchanged, otherwise converts
// poll.ErrFileClosing to ErrClosed and wraps the error in a PathError.
func (f *File) wrapErr(op string, err error) error {
if err == nil || err == io.EOF {
return err
}
/* TODO(xsw):
if err == poll.ErrFileClosing {
err = ErrClosed
} else if checkWrapErr && errors.Is(err, poll.ErrFileClosing) {
panic("unexpected error wrapping poll.ErrFileClosing: " + err.Error())
}
*/
return &PathError{Op: op, Path: f.name, Err: err}
}
// TempDir returns the default directory to use for temporary files.
//
// On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
// On Windows, it uses GetTempPath, returning the first non-empty
// value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
// On Plan 9, it returns /tmp.
//
// The directory is neither guaranteed to exist nor have accessible
// permissions.
func TempDir() string {
return tempDir()
}
// Chmod changes the mode of the file to mode.
// If there is an error, it will be of type *PathError.
func (f *File) Chmod(mode FileMode) error { return f.chmod(mode) }
// SetDeadline sets the read and write deadlines for a File.
// It is equivalent to calling both SetReadDeadline and SetWriteDeadline.
//
// Only some kinds of files support setting a deadline. Calls to SetDeadline
// for files that do not support deadlines will return ErrNoDeadline.
// On most systems ordinary files do not support deadlines, but pipes do.
//
// A deadline is an absolute time after which I/O operations fail with an
// error instead of blocking. The deadline applies to all future and pending
// I/O, not just the immediately following call to Read or Write.
// After a deadline has been exceeded, the connection can be refreshed
// by setting a deadline in the future.
//
// If the deadline is exceeded a call to Read or Write or to other I/O
// methods will return an error that wraps ErrDeadlineExceeded.
// This can be tested using errors.Is(err, os.ErrDeadlineExceeded).
// That error implements the Timeout method, and calling the Timeout
// method will return true, but there are other possible errors for which
// the Timeout will return true even if the deadline has not been exceeded.
//
// An idle timeout can be implemented by repeatedly extending
// the deadline after successful Read or Write calls.
//
// A zero value for t means I/O operations will not time out.
func (f *File) SetDeadline(t time.Time) error {
return f.setDeadline(t)
}
// SetReadDeadline sets the deadline for future Read calls and any
// currently-blocked Read call.
// A zero value for t means Read will not time out.
// Not all files support setting deadlines; see SetDeadline.
func (f *File) SetReadDeadline(t time.Time) error {
return f.setReadDeadline(t)
}
// SetWriteDeadline sets the deadline for any future Write calls and any
// currently-blocked Write call.
// Even if Write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
// Not all files support setting deadlines; see SetDeadline.
func (f *File) SetWriteDeadline(t time.Time) error {
return f.setWriteDeadline(t)
}
// SyscallConn returns a raw file.
// This implements the syscall.Conn interface.
func (f *File) SyscallConn() (syscall.RawConn, error) {
/*
if err := f.checkValid("SyscallConn"); err != nil {
return nil, err
}
return newRawConn(f)
*/
panic("todo: os.(*File).SyscallConn")
}
/* TODO(xsw):
// DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
//
// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
// operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the
// same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside
// the /prefix tree, then using DirFS does not stop the access any more than using
// os.Open does. Additionally, the root of the fs.FS returned for a relative path,
// DirFS("prefix"), will be affected by later calls to Chdir. DirFS is therefore not
// a general substitute for a chroot-style security mechanism when the directory tree
// contains arbitrary content.
//
// The directory dir must not be "".
//
// The result implements [io/fs.StatFS], [io/fs.ReadFileFS] and
// [io/fs.ReadDirFS].
func DirFS(dir string) fs.FS {
return dirFS(dir)
}
// containsAny reports whether any bytes in chars are within s.
func containsAny(s, chars string) bool {
for i := 0; i < len(s); i++ {
for j := 0; j < len(chars); j++ {
if s[i] == chars[j] {
return true
}
}
}
return false
}
type dirFS string
func (dir dirFS) Open(name string) (fs.File, error) {
fullname, err := dir.join(name)
if err != nil {
return nil, &PathError{Op: "stat", Path: name, Err: err}
}
f, err := Open(fullname)
if err != nil {
// DirFS takes a string appropriate for GOOS,
// while the name argument here is always slash separated.
// dir.join will have mixed the two; undo that for
// error reporting.
err.(*PathError).Path = name
return nil, err
}
return f, nil
}
// The ReadFile method calls the [ReadFile] function for the file
// with the given name in the directory. The function provides
// robust handling for small files and special file systems.
// Through this method, dirFS implements [io/fs.ReadFileFS].
func (dir dirFS) ReadFile(name string) ([]byte, error) {
fullname, err := dir.join(name)
if err != nil {
return nil, &PathError{Op: "readfile", Path: name, Err: err}
}
return ReadFile(fullname)
}
// ReadDir reads the named directory, returning all its directory entries sorted
// by filename. Through this method, dirFS implements [io/fs.ReadDirFS].
func (dir dirFS) ReadDir(name string) ([]DirEntry, error) {
fullname, err := dir.join(name)
if err != nil {
return nil, &PathError{Op: "readdir", Path: name, Err: err}
}
return ReadDir(fullname)
}
func (dir dirFS) Stat(name string) (fs.FileInfo, error) {
fullname, err := dir.join(name)
if err != nil {
return nil, &PathError{Op: "stat", Path: name, Err: err}
}
f, err := Stat(fullname)
if err != nil {
// See comment in dirFS.Open.
err.(*PathError).Path = name
return nil, err
}
return f, nil
}
// join returns the path for name in dir.
func (dir dirFS) join(name string) (string, error) {
if dir == "" {
return "", errors.New("os: DirFS with empty root")
}
if !fs.ValidPath(name) {
return "", ErrInvalid
}
name, err := safefilepath.FromFS(name)
if err != nil {
return "", ErrInvalid
}
if IsPathSeparator(dir[len(dir)-1]) {
return string(dir) + name, nil
}
return string(dir) + string(PathSeparator) + name, nil
}
*/
// ReadFile reads the named file and returns the contents.
// A successful call returns err == nil, not err == EOF.
// Because ReadFile reads the whole file, it does not treat an EOF from Read
// as an error to be reported.
func ReadFile(name string) ([]byte, error) {
f, err := Open(name)
if err != nil {
return nil, err
}
defer f.Close()
var size int
if info, err := f.Stat(); err == nil {
size64 := info.Size()
if int64(int(size64)) == size64 {
size = int(size64)
}
}
size++ // one byte for final read at EOF
// If a file claims a small size, read at least 512 bytes.
// In particular, files in Linux's /proc claim size 0 but
// then do not work right if read in small pieces,
// so an initial read of 1 byte would not work correctly.
if size < 512 {
size = 512
}
data := make([]byte, 0, size)
for {
if len(data) >= cap(data) {
d := append(data[:cap(data)], 0)
data = d[:len(data)]
}
n, err := f.Read(data[len(data):cap(data)])
data = data[:len(data)+n]
if err != nil {
if err == io.EOF {
err = nil
}
return data, err
}
}
}
// WriteFile writes data to the named file, creating it if necessary.
// If the file does not exist, WriteFile creates it with permissions perm (before umask);
// otherwise WriteFile truncates it before writing, without changing permissions.
// Since WriteFile requires multiple system calls to complete, a failure mid-operation
// can leave the file in a partially written state.
func WriteFile(name string, data []byte, perm FileMode) error {
f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
if err != nil {
return err
}
_, err = f.Write(data)
if err1 := f.Close(); err1 != nil && err == nil {
err = err1
}
return err
}

View File

@@ -1,240 +0,0 @@
// 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.
//go:build unix || (js && wasm) || wasip1 || windows
package os
import (
"syscall"
"time"
)
// Close closes the File, rendering it unusable for I/O.
// On files that support SetDeadline, any pending I/O operations will
// be canceled and return immediately with an ErrClosed error.
// Close will return an error if it has already been called.
func (f *File) Close() error {
if f == nil {
return ErrInvalid
}
return f.close()
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to nil.
func (f *File) pread(b []byte, off int64) (n int, err error) {
/*
n, err = f.pfd.Pread(b, off)
runtime.KeepAlive(f)
return n, err
*/
panic("todo: os.(*File).pread")
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
func (f *File) pwrite(b []byte, off int64) (n int, err error) {
/*
n, err = f.pfd.Pwrite(b, off)
runtime.KeepAlive(f)
return n, err
*/
panic("todo: os.(*File).pwrite")
}
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
func syscallMode(i FileMode) (o uint32) {
o |= uint32(i.Perm())
if i&ModeSetuid != 0 {
o |= syscall.S_ISUID
}
if i&ModeSetgid != 0 {
o |= syscall.S_ISGID
}
if i&ModeSticky != 0 {
o |= syscall.S_ISVTX
}
// No mapping for Go's ModeTemporary (plan9 only).
return
}
/* TODO(xsw):
// See docs in file.go:Chmod.
func chmod(name string, mode FileMode) error {
longName := fixLongPath(name)
e := ignoringEINTR(func() error {
return syscall.Chmod(longName, syscallMode(mode))
})
if e != nil {
return &PathError{Op: "chmod", Path: name, Err: e}
}
return nil
}
*/
// See docs in file.go:(*File).Chmod.
func (f *File) chmod(mode FileMode) error {
/*
if err := f.checkValid("chmod"); err != nil {
return err
}
if e := f.pfd.Fchmod(syscallMode(mode)); e != nil {
return f.wrapErr("chmod", e)
}
return nil
*/
panic("todo: os.(*File).chmod")
}
// Chown changes the numeric uid and gid of the named file.
// If there is an error, it will be of type *PathError.
//
// On Windows, it always returns the syscall.EWINDOWS error, wrapped
// in *PathError.
func (f *File) Chown(uid, gid int) error {
/*
if err := f.checkValid("chown"); err != nil {
return err
}
if e := f.pfd.Fchown(uid, gid); e != nil {
return f.wrapErr("chown", e)
}
return nil
*/
panic("todo: os.(*File).Chown")
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
// If there is an error, it will be of type *PathError.
func (f *File) Truncate(size int64) error {
/*
if err := f.checkValid("truncate"); err != nil {
return err
}
if e := f.pfd.Ftruncate(size); e != nil {
return f.wrapErr("truncate", e)
}
return nil
*/
panic("todo: os.(*File).Truncate")
}
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (f *File) Sync() error {
/*
if err := f.checkValid("sync"); err != nil {
return err
}
if e := f.pfd.Fsync(); e != nil {
return f.wrapErr("sync", e)
}
return nil
*/
panic("todo: os.(*File).Sync")
}
/*
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
// A zero time.Time value will leave the corresponding file time unchanged.
//
// The underlying filesystem may truncate or round the values to a
// less precise time unit.
// If there is an error, it will be of type *PathError.
func Chtimes(name string, atime time.Time, mtime time.Time) error {
var utimes [2]syscall.Timespec
set := func(i int, t time.Time) {
if t.IsZero() {
utimes[i] = syscall.Timespec{Sec: _UTIME_OMIT, Nsec: _UTIME_OMIT}
} else {
utimes[i] = syscall.NsecToTimespec(t.UnixNano())
}
}
set(0, atime)
set(1, mtime)
if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil {
return &PathError{Op: "chtimes", Path: name, Err: e}
}
return nil
}
*/
// Chdir changes the current working directory to the file,
// which must be a directory.
// If there is an error, it will be of type *PathError.
func (f *File) Chdir() error {
/*
if err := f.checkValid("chdir"); err != nil {
return err
}
if e := f.pfd.Fchdir(); e != nil {
return f.wrapErr("chdir", e)
}
return nil
*/
panic("todo: os.(*File).Chdir")
}
// setDeadline sets the read and write deadline.
func (f *File) setDeadline(t time.Time) error {
/*
if err := f.checkValid("SetDeadline"); err != nil {
return err
}
return f.pfd.SetDeadline(t)
*/
panic("todo: os.(*File).setDeadline")
}
// setReadDeadline sets the read deadline.
func (f *File) setReadDeadline(t time.Time) error {
/*
if err := f.checkValid("SetReadDeadline"); err != nil {
return err
}
return f.pfd.SetReadDeadline(t)
*/
panic("todo: os.(*File).setReadDeadline")
}
// setWriteDeadline sets the write deadline.
func (f *File) setWriteDeadline(t time.Time) error {
/*
if err := f.checkValid("SetWriteDeadline"); err != nil {
return err
}
return f.pfd.SetWriteDeadline(t)
*/
panic("todo: os.(*File).setWriteDeadline")
}
// checkValid checks whether f is valid for use.
// If not, it returns an appropriate error, perhaps incorporating the operation name op.
func (f *File) checkValid(op string) error {
if f == nil {
return ErrInvalid
}
return nil
}
// ignoringEINTR makes a function call and repeats it if it returns an
// EINTR error. This appears to be required even though we install all
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
// Also #20400 and #36644 are issues in which a signal handler is
// installed without setting SA_RESTART. None of these are the common case,
// but there are enough of them that it seems that we can't avoid
// an EINTR loop.
func ignoringEINTR(fn func() error) error {
for {
err := fn()
if err != syscall.EINTR {
return err
}
}
}

View File

@@ -1,334 +0,0 @@
// 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.
//go:build unix || (js && wasm) || wasip1
package os
import (
"runtime"
"syscall"
"github.com/goplus/llgo/internal/lib/internal/syscall/unix"
)
// Fd returns the integer Unix file descriptor referencing the open file.
// If f is closed, the file descriptor becomes invalid.
// If f is garbage collected, a finalizer may close the file descriptor,
// making it invalid; see runtime.SetFinalizer for more information on when
// a finalizer might be run. On Unix systems this will cause the SetDeadline
// methods to stop working.
// Because file descriptors can be reused, the returned file descriptor may
// only be closed through the Close method of f, or by its finalizer during
// garbage collection. Otherwise, during garbage collection the finalizer
// may close an unrelated file descriptor with the same (reused) number.
//
// As an alternative, see the f.SyscallConn method.
func (f *File) Fd() uintptr {
if f == nil {
return ^(uintptr(0))
}
return f.fd
}
func NewFile(fd uintptr, name string) *File {
return &File{fd: fd, name: name}
}
/* TODO(xsw):
// NewFile returns a new File with the given file descriptor and
// name. The returned value will be nil if fd is not a valid file
// descriptor. On Unix systems, if the file descriptor is in
// non-blocking mode, NewFile will attempt to return a pollable File
// (one for which the SetDeadline methods work).
//
// After passing it to NewFile, fd may become invalid under the same
// conditions described in the comments of the Fd method, and the same
// constraints apply.
func NewFile(fd uintptr, name string) *File {
fdi := int(fd)
if fdi < 0 {
return nil
}
kind := kindNewFile
appendMode := false
if flags, err := unix.Fcntl(fdi, syscall.F_GETFL, 0); err == nil {
if unix.HasNonblockFlag(flags) {
kind = kindNonBlock
}
appendMode = flags&syscall.O_APPEND != 0
}
f := newFile(fdi, name, kind)
f.appendMode = appendMode
return f
}
// net_newUnixFile is a hidden entry point called by net.conn.File.
// This is used so that a nonblocking network connection will become
// blocking if code calls the Fd method. We don't want that for direct
// calls to NewFile: passing a nonblocking descriptor to NewFile should
// remain nonblocking if you get it back using Fd. But for net.conn.File
// the call to NewFile is hidden from the user. Historically in that case
// the Fd method has returned a blocking descriptor, and we want to
// retain that behavior because existing code expects it and depends on it.
//
//-go:linkname net_newUnixFile net.newUnixFile
func net_newUnixFile(fd int, name string) *File {
if fd < 0 {
panic("invalid FD")
}
f := newFile(fd, name, kindNonBlock)
f.nonblock = true // tell Fd to return blocking descriptor
return f
}
*/
// newFileKind describes the kind of file to newFile.
type newFileKind int
const (
// kindNewFile means that the descriptor was passed to us via NewFile.
kindNewFile newFileKind = iota
// kindOpenFile means that the descriptor was opened using
// Open, Create, or OpenFile (without O_NONBLOCK).
kindOpenFile
// kindPipe means that the descriptor was opened using Pipe.
kindPipe
// kindNonBlock means that the descriptor is already in
// non-blocking mode.
kindNonBlock
// kindNoPoll means that we should not put the descriptor into
// non-blocking mode, because we know it is not a pipe or FIFO.
// Used by openFdAt for directories.
kindNoPoll
)
// newFile is like NewFile, but if called from OpenFile or Pipe
// (as passed in the kind parameter) it tries to add the file to
// the runtime poller.
func newFile(fd int, name string, kind newFileKind) *File {
f := &File{
fd: uintptr(fd),
name: name,
stdoutOrErr: fd == 1 || fd == 2,
}
/* TODO(xsw):
pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock
// If the caller passed a non-blocking filedes (kindNonBlock),
// we assume they know what they are doing so we allow it to be
// used with kqueue.
if kind == kindOpenFile {
switch runtime.GOOS {
case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd":
var st syscall.Stat_t
err := ignoringEINTR(func() error {
return syscall.Fstat(fd, &st)
})
typ := st.Mode & syscall.S_IFMT
// Don't try to use kqueue with regular files on *BSDs.
// On FreeBSD a regular file is always
// reported as ready for writing.
// On Dragonfly, NetBSD and OpenBSD the fd is signaled
// only once as ready (both read and write).
// Issue 19093.
// Also don't add directories to the netpoller.
if err == nil && (typ == syscall.S_IFREG || typ == syscall.S_IFDIR) {
pollable = false
}
// In addition to the behavior described above for regular files,
// on Darwin, kqueue does not work properly with fifos:
// closing the last writer does not cause a kqueue event
// for any readers. See issue #24164.
if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && typ == syscall.S_IFIFO {
pollable = false
}
}
}
clearNonBlock := false
if pollable {
if kind == kindNonBlock {
// The descriptor is already in non-blocking mode.
// We only set f.nonblock if we put the file into
// non-blocking mode.
} else if err := syscall.SetNonblock(fd, true); err == nil {
f.nonblock = true
clearNonBlock = true
} else {
pollable = false
}
}
// An error here indicates a failure to register
// with the netpoll system. That can happen for
// a file descriptor that is not supported by
// epoll/kqueue; for example, disk files on
// Linux systems. We assume that any real error
// will show up in later I/O.
// We do restore the blocking behavior if it was set by us.
if pollErr := f.pfd.Init("file", pollable); pollErr != nil && clearNonBlock {
if err := syscall.SetNonblock(fd, false); err == nil {
f.nonblock = false
}
}
runtime.SetFinalizer(f.file, (*file).close)
*/
return f
}
// TODO(xsw):
// func sigpipe() // implemented in package runtime
// epipecheck raises SIGPIPE if we get an EPIPE error on standard
// output or standard error. See the SIGPIPE docs in os/signal, and
// issue 11845.
func epipecheck(file *File, e error) {
/* TODO(xsw):
if e == syscall.EPIPE && file.stdoutOrErr {
sigpipe()
}
*/
panic("todo: os.epipecheck")
}
// DevNull is the name of the operating system's “null device.”
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
const DevNull = "/dev/null"
// openFileNolog is the Unix implementation of OpenFile.
// Changes here should be reflected in openFdAt, if relevant.
func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
setSticky := false
if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
if _, err := Stat(name); IsNotExist(err) {
setSticky = true
}
}
var r int
for {
var e error
r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
if e == nil {
break
}
// We have to check EINTR here, per issues 11180 and 39237.
if e == syscall.EINTR {
continue
}
return nil, &PathError{Op: "open", Path: name, Err: e}
}
// open(2) itself won't handle the sticky bit on *BSD and Solaris
if setSticky {
setStickyBit(name)
}
// There's a race here with fork/exec, which we are
// content to live with. See ../syscall/exec_unix.go.
if !supportsCloseOnExec {
syscall.CloseOnExec(r)
}
kind := kindOpenFile
if unix.HasNonblockFlag(flag) {
kind = kindNonBlock
panic("todo: os.openFileNolog: unix.HasNonblockFlag")
}
f := newFile(r, name, kind)
return f, nil
}
func (file *File) close() error {
return syscall.Close(int(file.fd))
/* TODO(xsw):
if file.dirinfo != nil {
file.dirinfo.close()
file.dirinfo = nil
}
var err error
if e := file.pfd.Close(); e != nil {
if e == poll.ErrFileClosing {
e = ErrClosed
}
err = &PathError{Op: "close", Path: file.name, Err: e}
}
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
return err
*/
}
func tempDir() string {
dir := Getenv("TMPDIR")
if dir == "" {
if runtime.GOOS == "android" {
dir = "/data/local/tmp"
} else {
dir = "/tmp"
}
}
return dir
}
type unixDirent struct {
parent string
name string
typ FileMode
info FileInfo
}
func (d *unixDirent) Name() string { return d.name }
func (d *unixDirent) IsDir() bool { return d.typ.IsDir() }
func (d *unixDirent) Type() FileMode { return d.typ }
func (d *unixDirent) Info() (FileInfo, error) {
/* TODO(xsw):
if d.info != nil {
return d.info, nil
}
return lstat(d.parent + "/" + d.name)
*/
panic("todo: os.unixDirent.Info")
}
func (d *unixDirent) String() string {
/* TODO(xsw):
return fs.FormatDirEntry(d)
*/
panic("todo: os.unixDirent.String")
}
/* TODO(xsw):
func newUnixDirent(parent, name string, typ FileMode) (DirEntry, error) {
ude := &unixDirent{
parent: parent,
name: name,
typ: typ,
}
if typ != ^FileMode(0) && !testingForceReadDirLstat {
return ude, nil
}
info, err := lstat(parent + "/" + name)
if err != nil {
return nil, err
}
ude.typ = info.Mode().Type()
ude.info = info
return ude, nil
}
*/

View File

@@ -1,464 +0,0 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package os
// llgo:skipall
import (
"errors"
"runtime"
"syscall"
_ "unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/os"
)
const (
LLGoPackage = true
)
// LinkError records an error during a link or symlink or rename
// system call and the paths that caused it.
type LinkError struct {
Op string
Old string
New string
Err error
}
func (e *LinkError) Error() string {
return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
}
func (e *LinkError) Unwrap() error {
return e.Err
}
func toPathErr(op, path string, errno c.Int) error {
return &PathError{Op: op, Path: path, Err: syscall.Errno(errno)}
}
func Chdir(dir string) error {
ret := os.Chdir(c.AllocaCStr(dir))
if ret == 0 {
return nil
}
return toPathErr("chdir", dir, ret)
}
/* TODO(xsw):
// Chdir changes the current working directory to the named directory.
// If there is an error, it will be of type *PathError.
func Chdir(dir string) error {
if e := syscall.Chdir(dir); e != nil {
testlog.Open(dir) // observe likely non-existent directory
return &PathError{Op: "chdir", Path: dir, Err: e}
}
if log := testlog.Logger(); log != nil {
wd, err := Getwd()
if err == nil {
log.Chdir(wd)
}
}
return nil
}
*/
func Chmod(name string, mode FileMode) error {
ret := os.Chmod(c.AllocaCStr(name), os.ModeT(syscallMode(mode)))
if ret == 0 {
return nil
}
return toPathErr("chmod", name, ret)
}
/* TODO(xsw):
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
// If there is an error, it will be of type *PathError.
//
// A different subset of the mode bits are used, depending on the
// operating system.
//
// On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and
// ModeSticky are used.
//
// On Windows, only the 0200 bit (owner writable) of mode is used; it
// controls whether the file's read-only attribute is set or cleared.
// The other bits are currently unused. For compatibility with Go 1.12
// and earlier, use a non-zero mode. Use mode 0400 for a read-only
// file and 0600 for a readable+writable file.
//
// On Plan 9, the mode's permission bits, ModeAppend, ModeExclusive,
// and ModeTemporary are used.
func Chmod(name string, mode FileMode) error { return chmod(name, mode) }
*/
func Chown(name string, uid, gid int) error {
ret := os.Chown(c.AllocaCStr(name), os.UidT(uid), os.GidT(gid))
if ret == 0 {
return nil
}
return toPathErr("chown", name, ret)
}
/* TODO(xsw):
// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
// A uid or gid of -1 means to not change that value.
// If there is an error, it will be of type *PathError.
//
// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or
// EPLAN9 error, wrapped in *PathError.
func Chown(name string, uid, gid int) error {
e := ignoringEINTR(func() error {
return syscall.Chown(name, uid, gid)
})
if e != nil {
return &PathError{Op: "chown", Path: name, Err: e}
}
return nil
}
*/
// TODO(xsw):
// func Chtimes(name string, atime time.Time, mtime time.Time) error
//go:linkname Clearenv C.clearenv
func Clearenv()
// TODO(xsw):
// func DirFS(dir string) fs.FS
// func Executable() (string, error)
// TODO(xsw):
// func Expand(s string, mapping func(string) string) string
// func ExpandEnv(s string) string
func Getegid() int {
return int(os.Getegid())
}
func Geteuid() int {
return int(os.Geteuid())
}
func Getgid() int {
return int(os.Getgid())
}
// TODO(xsw):
// func Getgroups() ([]int, error)
// func Getpagesize() int
func Getpid() int {
return int(os.Getpid())
}
func Getppid() int {
return int(os.Getppid())
}
func Getuid() int {
return int(os.Getuid())
}
func Getwd() (dir string, err error) {
wd := os.Getcwd(c.Alloca(os.PATH_MAX), os.PATH_MAX)
if wd != nil {
return c.GoString(wd), nil
}
return "", syscall.Errno(os.Errno())
}
// TODO(xsw):
// func Hostname() (name string, err error)
// func IsExist(err error) bool
// func IsNotExist(err error) bool
// func IsPermission(err error) bool
// func IsTimeout(err error) bool
func Lchown(name string, uid, gid int) error {
ret := os.Lchown(c.AllocaCStr(name), os.UidT(uid), os.GidT(gid))
if ret == 0 {
return nil
}
return toPathErr("lchown", name, ret)
}
/* TODO(xsw):
// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
// If there is an error, it will be of type *PathError.
//
// On Windows, it always returns the syscall.EWINDOWS error, wrapped
// in *PathError.
func Lchown(name string, uid, gid int) error {
e := ignoringEINTR(func() error {
return syscall.Lchown(name, uid, gid)
})
if e != nil {
return &PathError{Op: "lchown", Path: name, Err: e}
}
return nil
}
*/
func Link(oldname, newname string) error {
ret := os.Link(c.AllocaCStr(oldname), c.AllocaCStr(newname))
if ret == 0 {
return nil
}
return &LinkError{"link", oldname, newname, syscall.Errno(ret)}
}
// TODO(xsw):
// func LookupEnv(key string) (string, bool)
func Mkdir(name string, perm FileMode) error {
ret := os.Mkdir(c.AllocaCStr(name), os.ModeT(syscallMode(perm)))
if ret == 0 {
return nil
}
return toPathErr("mkdir", name, ret)
}
/* TODO(xsw):
// Mkdir creates a new directory with the specified name and permission
// bits (before umask).
// If there is an error, it will be of type *PathError.
func Mkdir(name string, perm FileMode) error {
longName := fixLongPath(name)
e := ignoringEINTR(func() error {
return syscall.Mkdir(longName, syscallMode(perm))
})
if e != nil {
return &PathError{Op: "mkdir", Path: name, Err: e}
}
// mkdir(2) itself won't handle the sticky bit on *BSD and Solaris
if !supportsCreateWithStickyBit && perm&ModeSticky != 0 {
e = setStickyBit(name)
if e != nil {
Remove(name)
return e
}
}
return nil
}
*/
// TODO(xsw):
// func NewSyscallError(syscall string, err error) error
// func ReadFile(name string) ([]byte, error)
func Readlink(name string) (string, error) {
ptr := c.Alloca(os.PATH_MAX)
ret := os.Readlink(c.AllocaCStr(name), ptr, os.PATH_MAX)
if ret < os.PATH_MAX {
return c.GoString((*c.Char)(ptr), ret), nil
}
panic("todo: buffer too small")
}
func Remove(name string) error {
ret := os.Remove(c.AllocaCStr(name))
if ret == 0 {
return nil
}
return toPathErr("remove", name, ret)
}
// TODO(xsw):
// func RemoveAll(path string) error
func Rename(oldpath, newpath string) error {
ret := os.Rename(c.AllocaCStr(oldpath), c.AllocaCStr(newpath))
if ret == 0 {
return nil
}
return &LinkError{"rename", oldpath, newpath, syscall.Errno(ret)}
}
/* TODO(xsw):
// Rename renames (moves) oldpath to newpath.
// If newpath already exists and is not a directory, Rename replaces it.
// OS-specific restrictions may apply when oldpath and newpath are in different directories.
// Even within the same directory, on non-Unix platforms Rename is not an atomic operation.
// If there is an error, it will be of type *LinkError.
func Rename(oldpath, newpath string) error {
return rename(oldpath, newpath)
}
*/
// TODO(xsw):
// func SameFile(fi1, fi2 FileInfo) bool
func Symlink(oldname, newname string) error {
ret := os.Symlink(c.AllocaCStr(oldname), c.AllocaCStr(newname))
if ret == 0 {
return nil
}
return &LinkError{"symlink", oldname, newname, syscall.Errno(ret)}
}
func Truncate(name string, size int64) error {
ret := os.Truncate(c.AllocaCStr(name), os.OffT(size))
if ret == 0 {
return nil
}
return toPathErr("truncate", name, ret)
}
// UserCacheDir returns the default root directory to use for user-specific
// cached data. Users should create their own application-specific subdirectory
// within this one and use that.
//
// On Unix systems, it returns $XDG_CACHE_HOME as specified by
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if
// non-empty, else $HOME/.cache.
// On Darwin, it returns $HOME/Library/Caches.
// On Windows, it returns %LocalAppData%.
// On Plan 9, it returns $home/lib/cache.
//
// If the location cannot be determined (for example, $HOME is not defined),
// then it will return an error.
func UserCacheDir() (string, error) {
var dir string
switch runtime.GOOS {
case "windows":
dir = Getenv("LocalAppData")
if dir == "" {
return "", errors.New("%LocalAppData% is not defined")
}
case "darwin", "ios":
dir = Getenv("HOME")
if dir == "" {
return "", errors.New("$HOME is not defined")
}
dir += "/Library/Caches"
case "plan9":
dir = Getenv("home")
if dir == "" {
return "", errors.New("$home is not defined")
}
dir += "/lib/cache"
default: // Unix
dir = Getenv("XDG_CACHE_HOME")
if dir == "" {
dir = Getenv("HOME")
if dir == "" {
return "", errors.New("neither $XDG_CACHE_HOME nor $HOME are defined")
}
dir += "/.cache"
}
}
return dir, nil
}
// UserConfigDir returns the default root directory to use for user-specific
// configuration data. Users should create their own application-specific
// subdirectory within this one and use that.
//
// On Unix systems, it returns $XDG_CONFIG_HOME as specified by
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if
// non-empty, else $HOME/.config.
// On Darwin, it returns $HOME/Library/Application Support.
// On Windows, it returns %AppData%.
// On Plan 9, it returns $home/lib.
//
// If the location cannot be determined (for example, $HOME is not defined),
// then it will return an error.
func UserConfigDir() (string, error) {
var dir string
switch runtime.GOOS {
case "windows":
dir = Getenv("AppData")
if dir == "" {
return "", errors.New("%AppData% is not defined")
}
case "darwin", "ios":
dir = Getenv("HOME")
if dir == "" {
return "", errors.New("$HOME is not defined")
}
dir += "/Library/Application Support"
case "plan9":
dir = Getenv("home")
if dir == "" {
return "", errors.New("$home is not defined")
}
dir += "/lib"
default: // Unix
dir = Getenv("XDG_CONFIG_HOME")
if dir == "" {
dir = Getenv("HOME")
if dir == "" {
return "", errors.New("neither $XDG_CONFIG_HOME nor $HOME are defined")
}
dir += "/.config"
}
}
return dir, nil
}
// UserHomeDir returns the current user's home directory.
//
// On Unix, including macOS, it returns the $HOME environment variable.
// On Windows, it returns %USERPROFILE%.
// On Plan 9, it returns the $home environment variable.
//
// If the expected variable is not set in the environment, UserHomeDir
// returns either a platform-specific default value or a non-nil error.
func UserHomeDir() (string, error) {
env, enverr := "HOME", "$HOME"
switch runtime.GOOS {
case "windows":
env, enverr = "USERPROFILE", "%userprofile%"
case "plan9":
env, enverr = "home", "$home"
}
if v := Getenv(env); v != "" {
return v, nil
}
// On some geese the home directory is not always defined.
switch runtime.GOOS {
case "android":
return "/sdcard", nil
case "ios":
return "/", nil
}
return "", errors.New(enverr + " is not defined")
}
// TODO(xsw):
// func WriteFile(name string, data []byte, perm FileMode) error

View File

@@ -1,55 +0,0 @@
package os
import (
"syscall"
)
// MkdirAll creates a directory named path,
// along with any necessary parents, and returns nil,
// or else returns an error.
// The permission bits perm (before umask) are used for all
// directories that MkdirAll creates.
// If path is already a directory, MkdirAll does nothing
// and returns nil.
func MkdirAll(path string, perm FileMode) error {
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := Stat(path)
if err == nil {
if dir.IsDir() {
return nil
}
return &PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
}
// Slow path: make sure parent exists and then call Mkdir for path.
i := len(path)
for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
i--
}
j := i
for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
j--
}
if j > 1 {
// Create parent.
err = MkdirAll(fixRootDirectory(path[:j-1]), perm)
if err != nil {
return err
}
}
// Parent now exists; invoke Mkdir and use its result.
err = Mkdir(path, perm)
if err != nil {
// Handle arguments like "foo/." by
// double-checking that directory doesn't exist.
dir, err1 := Lstat(path)
if err1 == nil && dir.IsDir() {
return nil
}
return err
}
return nil
}

View File

@@ -1,19 +0,0 @@
// Copyright 2011 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 os
const (
PathSeparator = '/' // OS-specific path separator
PathListSeparator = '\000' // OS-specific path list separator
)
// IsPathSeparator reports whether c is a directory separator character.
func IsPathSeparator(c uint8) bool {
return PathSeparator == c
}
func fixRootDirectory(p string) string {
return p
}

View File

@@ -1,75 +0,0 @@
// Copyright 2011 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:build unix || (js && wasm) || wasip1
package os
const (
PathSeparator = '/' // OS-specific path separator
PathListSeparator = ':' // OS-specific path list separator
)
// IsPathSeparator reports whether c is a directory separator character.
func IsPathSeparator(c uint8) bool {
return PathSeparator == c
}
// basename removes trailing slashes and the leading directory name from path name.
func basename(name string) string {
i := len(name) - 1
// Remove trailing slashes
for ; i > 0 && name[i] == '/'; i-- {
name = name[:i]
}
// Remove leading directory name
for i--; i >= 0; i-- {
if name[i] == '/' {
name = name[i+1:]
break
}
}
return name
}
// splitPath returns the base name and parent directory.
func splitPath(path string) (string, string) {
// if no better parent is found, the path is relative from "here"
dirname := "."
// Remove all but one leading slash.
for len(path) > 1 && path[0] == '/' && path[1] == '/' {
path = path[1:]
}
i := len(path) - 1
// Remove trailing slashes.
for ; i > 0 && path[i] == '/'; i-- {
path = path[:i]
}
// if no slashes in path, base is path
basename := path
// Remove leading directory path
for i--; i >= 0; i-- {
if path[i] == '/' {
if i == 0 {
dirname = path[:1]
} else {
dirname = path[:i]
}
basename = path[i+1:]
break
}
}
return dirname, basename
}
func fixRootDirectory(p string) string {
return p
}

View File

@@ -1,227 +0,0 @@
// Copyright 2011 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 os
const (
PathSeparator = '\\' // OS-specific path separator
PathListSeparator = ';' // OS-specific path list separator
)
// IsPathSeparator reports whether c is a directory separator character.
func IsPathSeparator(c uint8) bool {
// NOTE: Windows accepts / as path separator.
return c == '\\' || c == '/'
}
// basename removes trailing slashes and the leading
// directory name and drive letter from path name.
func basename(name string) string {
// Remove drive letter
if len(name) == 2 && name[1] == ':' {
name = "."
} else if len(name) > 2 && name[1] == ':' {
name = name[2:]
}
i := len(name) - 1
// Remove trailing slashes
for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
name = name[:i]
}
// Remove leading directory name
for i--; i >= 0; i-- {
if name[i] == '/' || name[i] == '\\' {
name = name[i+1:]
break
}
}
return name
}
func isAbs(path string) (b bool) {
v := volumeName(path)
if v == "" {
return false
}
path = path[len(v):]
if path == "" {
return false
}
return IsPathSeparator(path[0])
}
func volumeName(path string) (v string) {
if len(path) < 2 {
return ""
}
// with drive letter
c := path[0]
if path[1] == ':' &&
('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
'A' <= c && c <= 'Z') {
return path[:2]
}
// is it UNC
if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
!IsPathSeparator(path[2]) && path[2] != '.' {
// first, leading `\\` and next shouldn't be `\`. its server name.
for n := 3; n < l-1; n++ {
// second, next '\' shouldn't be repeated.
if IsPathSeparator(path[n]) {
n++
// third, following something characters. its share name.
if !IsPathSeparator(path[n]) {
if path[n] == '.' {
break
}
for ; n < l; n++ {
if IsPathSeparator(path[n]) {
break
}
}
return path[:n]
}
break
}
}
}
return ""
}
func fromSlash(path string) string {
// Replace each '/' with '\\' if present
var pathbuf []byte
var lastSlash int
for i, b := range path {
if b == '/' {
if pathbuf == nil {
pathbuf = make([]byte, len(path))
}
copy(pathbuf[lastSlash:], path[lastSlash:i])
pathbuf[i] = '\\'
lastSlash = i + 1
}
}
if pathbuf == nil {
return path
}
copy(pathbuf[lastSlash:], path[lastSlash:])
return string(pathbuf)
}
func dirname(path string) string {
vol := volumeName(path)
i := len(path) - 1
for i >= len(vol) && !IsPathSeparator(path[i]) {
i--
}
dir := path[len(vol) : i+1]
last := len(dir) - 1
if last > 0 && IsPathSeparator(dir[last]) {
dir = dir[:last]
}
if dir == "" {
dir = "."
}
return vol + dir
}
// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS
// supports opting into proper long path handling without the need for fixups.
var canUseLongPaths bool
// fixLongPath returns the extended-length (\\?\-prefixed) form of
// path when needed, in order to avoid the default 260 character file
// path limit imposed by Windows. If path is not easily converted to
// the extended-length form (for example, if path is a relative path
// or contains .. elements), or is short enough, fixLongPath returns
// path unmodified.
//
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
func fixLongPath(path string) string {
if canUseLongPaths {
return path
}
// Do nothing (and don't allocate) if the path is "short".
// Empirically (at least on the Windows Server 2013 builder),
// the kernel is arbitrarily okay with < 248 bytes. That
// matches what the docs above say:
// "When using an API to create a directory, the specified
// path cannot be so long that you cannot append an 8.3 file
// name (that is, the directory name cannot exceed MAX_PATH
// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
//
// The MSDN docs appear to say that a normal path that is 248 bytes long
// will work; empirically the path must be less then 248 bytes long.
if len(path) < 248 {
// Don't fix. (This is how Go 1.7 and earlier worked,
// not automatically generating the \\?\ form)
return path
}
// The extended form begins with \\?\, as in
// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
// The extended form disables evaluation of . and .. path
// elements and disables the interpretation of / as equivalent
// to \. The conversion here rewrites / to \ and elides
// . elements as well as trailing or duplicate separators. For
// simplicity it avoids the conversion entirely for relative
// paths or paths containing .. elements. For now,
// \\server\share paths are not converted to
// \\?\UNC\server\share paths because the rules for doing so
// are less well-specified.
if len(path) >= 2 && path[:2] == `\\` {
// Don't canonicalize UNC paths.
return path
}
if !isAbs(path) {
// Relative path
return path
}
const prefix = `\\?`
pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
copy(pathbuf, prefix)
n := len(path)
r, w := 0, len(prefix)
for r < n {
switch {
case IsPathSeparator(path[r]):
// empty block
r++
case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])):
// /./
r++
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])):
// /../ is currently unhandled
return path
default:
pathbuf[w] = '\\'
w++
for ; r < n && !IsPathSeparator(path[r]); r++ {
pathbuf[w] = path[r]
w++
}
}
}
// A drive's root directory needs a trailing \
if w == len(`\\?\c:`) {
pathbuf[w] = '\\'
w++
}
return string(pathbuf[:w])
}
// fixRootDirectory fixes a reference to a drive's root directory to
// have the required trailing slash.
func fixRootDirectory(p string) string {
if len(p) == len(`\\?\c:`) {
if IsPathSeparator(p[0]) && IsPathSeparator(p[1]) && p[2] == '?' && IsPathSeparator(p[3]) && p[5] == ':' {
return p + `\`
}
}
return p
}

View File

@@ -1,22 +0,0 @@
// Copyright 2017 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:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
package os
import "syscall"
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
// It returns the files and an error, if any.
func Pipe() (r *File, w *File, err error) {
var p [2]int
e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC)
if e != nil {
return nil, nil, NewSyscallError("pipe2", e)
}
return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil
}

View File

@@ -1,28 +0,0 @@
// 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.
//go:build aix || darwin
package os
import "syscall"
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
// It returns the files and an error, if any.
func Pipe() (r *File, w *File, err error) {
var p [2]int
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
if e != nil {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.CloseOnExec(p[0])
syscall.CloseOnExec(p[1])
syscall.ForkLock.RUnlock()
return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil
}

View File

@@ -1,16 +0,0 @@
// 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:build wasm
package os
import "syscall"
// Pipe returns a connected pair of Files; reads from r return bytes written to w.
// It returns the files and an error, if any.
func Pipe() (r *File, w *File, err error) {
// Neither GOOS=js nor GOOS=wasip1 have pipes.
return nil, nil, NewSyscallError("pipe", syscall.ENOSYS)
}

View File

@@ -1,65 +0,0 @@
// 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.
// Process etc.
package os
import (
"runtime"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/os"
)
// Args hold the command-line arguments, starting with the program name.
var Args []string
func init() {
if runtime.GOOS == "windows" {
// TODO(xsw): check windows implementation
// Initialized in exec_windows.go.
return
}
Args = runtimeArgs(int(c.Argc), c.Argv)
}
func runtimeArgs(argc int, argv **c.Char) []string {
args := make([]string, argc)
for i := 0; i < argc; i++ {
arg := *c.Advance(argv, i)
args[i] = unsafe.String((*byte)(unsafe.Pointer(arg)), c.Strlen(arg))
}
return args
}
// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
//
// On Windows, it returns syscall.EWINDOWS. See the os/user package
// for a possible alternative.
func Getgroups() ([]int, error) {
/* TODO(xsw):
gids, e := syscall.Getgroups()
return gids, NewSyscallError("getgroups", e)
*/
panic("todo: os.Getgroups")
}
// Exit causes the current program to exit with the given status code.
// Conventionally, code zero indicates success, non-zero an error.
// The program terminates immediately; deferred functions are not run.
//
// For portability, the status code should be in the range [0, 125].
func Exit(code int) {
// Inform the runtime that os.Exit is being called. If -race is
// enabled, this will give race detector a chance to fail the
// program (racy programs do not have the right to finish
// successfully). If coverage is enabled, then this call will
// enable us to write out a coverage data file.
// TODO(xsw):
// runtime_beforeExit(code)
os.Exit(c.Int(code))
}

View File

@@ -1,19 +0,0 @@
// Copyright 2017 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 os
// Stat returns a FileInfo describing the named file.
// If there is an error, it will be of type *PathError.
func Stat(name string) (FileInfo, error) {
return statNolog(name)
}
// Lstat returns a FileInfo describing the named file.
// If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link.
// If there is an error, it will be of type *PathError.
func Lstat(name string) (FileInfo, error) {
return lstatNolog(name)
}

View File

@@ -1,43 +0,0 @@
// 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 os
import (
"time"
"github.com/goplus/llgo/c/syscall"
)
func fillFileStatFromSys(fs *fileStat, name string) {
fs.name = basename(name)
fs.size = fs.sys.Size
fs.modTime = time.Unix(fs.sys.Mtimespec.Unix())
fs.mode = FileMode(fs.sys.Mode & 0777)
switch fs.sys.Mode & syscall.S_IFMT {
case syscall.S_IFBLK, syscall.S_IFWHT:
fs.mode |= ModeDevice
case syscall.S_IFCHR:
fs.mode |= ModeDevice | ModeCharDevice
case syscall.S_IFDIR:
fs.mode |= ModeDir
case syscall.S_IFIFO:
fs.mode |= ModeNamedPipe
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
// nothing to do
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
if fs.sys.Mode&syscall.S_ISGID != 0 {
fs.mode |= ModeSetgid
}
if fs.sys.Mode&syscall.S_ISUID != 0 {
fs.mode |= ModeSetuid
}
if fs.sys.Mode&syscall.S_ISVTX != 0 {
fs.mode |= ModeSticky
}
}

View File

@@ -1,42 +0,0 @@
// 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 os
import (
"syscall"
"time"
)
func fillFileStatFromSys(fs *fileStat, name string) {
fs.name = basename(name)
fs.size = fs.sys.Size
fs.modTime = time.Unix(fs.sys.Mtim.Unix())
fs.mode = FileMode(fs.sys.Mode & 0777)
switch fs.sys.Mode & syscall.S_IFMT {
case syscall.S_IFBLK:
fs.mode |= ModeDevice
case syscall.S_IFCHR:
fs.mode |= ModeDevice | ModeCharDevice
case syscall.S_IFDIR:
fs.mode |= ModeDir
case syscall.S_IFIFO:
fs.mode |= ModeNamedPipe
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
// nothing to do
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
if fs.sys.Mode&syscall.S_ISGID != 0 {
fs.mode |= ModeSetgid
}
if fs.sys.Mode&syscall.S_ISUID != 0 {
fs.mode |= ModeSetuid
}
if fs.sys.Mode&syscall.S_ISVTX != 0 {
fs.mode |= ModeSticky
}
}

View File

@@ -1,54 +0,0 @@
// Copyright 2016 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:build unix || (js && wasm) || wasip1
package os
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/os"
"github.com/goplus/llgo/internal/lib/syscall"
)
// Stat returns the FileInfo structure describing file.
// If there is an error, it will be of type *PathError.
func (f *File) Stat() (FileInfo, error) {
if f == nil {
return nil, ErrInvalid
}
var fs fileStat
err := os.Fstat(c.Int(f.fd), &fs.sys)
if err != 0 {
return nil, &PathError{Op: "stat", Path: f.name, Err: syscall.Errno(err)}
}
fillFileStatFromSys(&fs, f.name)
return &fs, nil
}
// statNolog stats a file with no test logging.
func statNolog(name string) (FileInfo, error) {
var fs fileStat
err := ignoringEINTR(func() error {
return syscall.Stat(name, &fs.sys)
})
if err != nil {
return nil, &PathError{Op: "stat", Path: name, Err: err}
}
fillFileStatFromSys(&fs, name)
return &fs, nil
}
// lstatNolog lstats a file with no test logging.
func lstatNolog(name string) (FileInfo, error) {
var fs fileStat
err := ignoringEINTR(func() error {
return syscall.Lstat(name, &fs.sys)
})
if err != nil {
return nil, &PathError{Op: "lstat", Path: name, Err: err}
}
fillFileStatFromSys(&fs, name)
return &fs, nil
}

View File

@@ -1,11 +0,0 @@
// Copyright 2014 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:build aix || darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd || solaris || wasip1
package os
// According to sticky(8), neither open(2) nor mkdir(2) will create
// a file with the sticky bit set.
const supportsCreateWithStickyBit = false

View File

@@ -1,9 +0,0 @@
// Copyright 2014 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:build !aix && !darwin && !dragonfly && !freebsd && !js && !netbsd && !openbsd && !solaris && !wasip1
package os
const supportsCreateWithStickyBit = true

View File

@@ -1,39 +0,0 @@
// 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.
// Simple conversions to avoid depending on strconv.
package os
// itox converts val (an int) to a hexadecimal string.
func itox(val int) string {
if val < 0 {
return "-" + uitox(uint(-val))
}
return uitox(uint(val))
}
const hex = "0123456789abcdef"
// uitox converts val (a uint) to a hexadecimal string.
func uitox(val uint) string {
if val == 0 { // avoid string allocation
return "0x0"
}
var buf [20]byte // big enough for 64bit value base 16 + 0x
i := len(buf) - 1
for val >= 16 {
q := val / 16
buf[i] = hex[val%16]
i--
val = q
}
// val < 16
buf[i] = hex[val%16]
i--
buf[i] = 'x'
i--
buf[i] = '0'
return string(buf[i:])
}

View File

@@ -1,11 +0,0 @@
// Copyright 2018 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:build js && wasm
package os
// supportsCloseOnExec reports whether the platform supports the
// O_CLOEXEC flag.
const supportsCloseOnExec = false

View File

@@ -1,14 +0,0 @@
// Copyright 2014 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:build unix
package os
// supportsCloseOnExec reports whether the platform supports the
// O_CLOEXEC flag.
// On Darwin, the O_CLOEXEC flag was introduced in OS X 10.7 (Darwin 11.0.0).
// See https://support.apple.com/kb/HT1633.
// On FreeBSD, the O_CLOEXEC flag was introduced in version 8.3.
const supportsCloseOnExec = true

View File

@@ -1,11 +0,0 @@
// 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:build wasip1
package os
// supportsCloseOnExec reports whether the platform supports the
// O_CLOEXEC flag.
const supportsCloseOnExec = false

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