-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathpackage.go
More file actions
169 lines (149 loc) · 3.72 KB
/
Copy pathpackage.go
File metadata and controls
169 lines (149 loc) · 3.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
* Copyright (c) 2022 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 ixgo
import (
"go/constant"
"go/token"
"go/types"
"log"
"reflect"
"sort"
"sync"
"github.com/goplus/ixgo/alias"
)
var (
registerPkgs = make(map[string]pkgLoad)
registerPatchs = make(map[string][]interface{})
)
// PackageList return all register packages
func PackageList() (list []string) {
for pkg := range registerPkgs {
list = append(list, pkg)
}
sort.Strings(list)
return
}
// LookupPackage lookup register pkgs
func LookupPackage(name string) (pkg *Package, ok bool) {
if pload, ok := registerPkgs[name]; ok {
return pload.Package(), true
}
return
}
type pkgLoad interface {
Package() *Package
}
type baseLoad struct {
pkg *Package
}
func (p *baseLoad) Package() *Package {
return p.pkg
}
type lazyLoad struct {
load func() *Package
}
func (p *lazyLoad) Package() *Package {
return p.load()
}
// RegisterPackage register a pkg.
func RegisterPackage(pkg *Package) {
if p, ok := registerPkgs[pkg.Path]; ok {
p.Package().merge(pkg)
return
}
registerPkgs[pkg.Path] = &baseLoad{pkg: pkg}
}
// RegisterPackageLazy registers a pkg with lazy initialization.
func RegisterPackageLazy(pkg string, load func() *Package) {
if p, ok := registerPkgs[pkg]; ok {
p.Package().merge(load())
return
}
registerPkgs[pkg] = &lazyLoad{load: sync.OnceValue(load)}
}
// RegisterPatch register pkg with "pkg@patch"
func RegisterPatch(pkg string, src ...interface{}) {
registerPatchs[pkg] = append(registerPatchs[pkg], src...)
}
type TypedConst struct {
Typ reflect.Type
Value constant.Value
}
type UntypedConst struct {
Typ string
Value constant.Value
}
type Package struct {
Interfaces map[string]reflect.Type
NamedTypes map[string]reflect.Type
AliasTypes map[string]reflect.Type
Vars map[string]reflect.Value
Funcs map[string]reflect.Value
TypedConsts map[string]TypedConst
UntypedConsts map[string]UntypedConst
Deps map[string]string // path -> name
Alias map[string]alias.Type
Name string
Path string
Source string
Import func(fset *token.FileSet, pkgs map[string]*types.Package) (*types.Package, error)
}
// merge same package
func (p *Package) merge(same *Package) {
for k, v := range same.Interfaces {
p.Interfaces[k] = v
}
for k, v := range same.NamedTypes {
p.NamedTypes[k] = v
}
for k, v := range same.Vars {
p.Vars[k] = v
}
for k, v := range same.Funcs {
p.Funcs[k] = v
}
for k, v := range same.UntypedConsts {
p.UntypedConsts[k] = v
}
if same.Alias != nil {
if p.Alias == nil {
p.Alias = make(map[string]alias.Type)
}
for k, v := range same.Alias {
p.Alias[k] = v
}
}
if p.Import == nil && same.Import != nil {
p.Import = same.Import
}
}
var (
externValues sync.Map // map[string]reflect.Value
)
// RegisterExternal is register external variable address or func
func RegisterExternal(key string, i interface{}) {
if i == nil {
externValues.Delete(key)
return
}
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Func, reflect.Ptr:
externValues.Store(key, v)
default:
log.Printf("register external must variable address or func. not %v\n", v.Kind())
}
}