-
Notifications
You must be signed in to change notification settings - Fork 153
/
importer.go
102 lines (90 loc) · 2.8 KB
/
importer.go
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
package runtime
import (
"context"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/internal/errors"
"github.com/influxdata/flux/interpreter"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/values"
)
var (
// list of packages included in the prelude.
// Packages must be listed in import order
PreludeList = []string{
"internal/boolean",
"universe",
"influxdata/influxdb",
}
)
type importer struct {
r *runtime
pkgs map[string]*interpreter.Package
}
func (imp *importer) Import(path string) (semantic.MonoType, error) {
p, err := imp.ImportPackageObject(path)
if err != nil {
return semantic.MonoType{}, err
}
return p.Type(), nil
}
func (imp *importer) ImportPackageObject(path string) (*interpreter.Package, error) {
// If this package has been imported previously, return the import now.
if p, ok := imp.pkgs[path]; ok {
if p == nil {
return nil, errors.Newf(codes.Invalid, "detected cyclical import for package path %q", path)
}
return p, nil
}
// Mark down that we are currently evaluating this package
// so that we can detect a circular import.
if imp.pkgs == nil {
imp.pkgs = make(map[string]*interpreter.Package)
}
imp.pkgs[path] = nil
// If this package is part of the prelude, fill in a fake
// empty package to resolve cyclical imports.
for _, ppath := range PreludeList {
if ppath == path {
imp.pkgs[path] = interpreter.NewPackage(path)
break
}
}
// Find the package for the given import path.
semPkg, ok := imp.r.pkgs[path]
if !ok {
return nil, errors.Newf(codes.Invalid, "invalid import path %s", path)
}
// Construct the prelude scope from the prelude paths.
// If we are importing part of the prelude, we do not
// include it as part of the prelude and will stop
// including values as soon as we hit the prelude.
// This allows us to import all previous paths when loading
// the prelude, but avoid a circular import.
scope, err := imp.r.newScopeFor(path, imp)
if err != nil {
return nil, err
}
// Run the interpreter on the package to construct the values
// created by the package. Pass in the previously initialized
// packages as importable packages as we evaluate these in order.
itrp := interpreter.NewInterpreter(nil, nil)
if _, err := itrp.Eval(context.Background(), semPkg, scope, imp); err != nil {
return nil, err
}
obj := newObjectFromScope(scope)
imp.pkgs[path] = interpreter.NewPackageWithValues(itrp.PackageName(), path, obj)
return imp.pkgs[path], nil
}
func newObjectFromScope(scope values.Scope) values.Object {
obj, _ := values.BuildObject(func(set values.ObjectSetter) error {
scope.LocalRange(func(k string, v values.Value) {
// Packages should not expose the packages they import.
if _, ok := v.(values.Package); ok {
return
}
set(k, v)
})
return nil
})
return obj
}