-
Notifications
You must be signed in to change notification settings - Fork 18
/
emitter_func_store.go
128 lines (113 loc) · 4.34 KB
/
emitter_func_store.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
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
// Copyright 2019 The Scriggo 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 compiler
import (
"reflect"
"github.com/open2b/scriggo/ast"
"github.com/open2b/scriggo/internal/runtime"
)
// A functionStore holds information about functions defined in Scriggo and
// predefined functions during the emission.
type functionStore struct {
// emitter is a reference to the current emitter.
emitter *emitter
// availableScriggoFuncs holds a list of Scriggo compiled functions that are
// available to be called or evaluated as expressions. The functions stored
// in availableScriggoFuncs are not added nor to Functions or Predefined if
// they are not used in the Scriggo code.
availableScriggoFuncs map[*ast.Package]map[string]*runtime.Function
// scriggoFuncIndexes holds the indexes of the Scriggo functions that have
// been added to Functions because they are referenced in the Scriggo code.
scriggoFuncIndexes map[*runtime.Function]map[*runtime.Function]int8
// predefFuncIndexes holds the indexes of the predefined functions that have
// been added to Predefined because they are referenced in the Scriggo code.
predefFuncIndexes map[*runtime.Function]map[reflect.Value]int8
}
// newFunctionStore returns a new functionStore.
func newFunctionStore(emitter *emitter) *functionStore {
return &functionStore{
emitter: emitter,
availableScriggoFuncs: map[*ast.Package]map[string]*runtime.Function{},
scriggoFuncIndexes: map[*runtime.Function]map[*runtime.Function]int8{},
predefFuncIndexes: map[*runtime.Function]map[reflect.Value]int8{},
}
}
// makeAvailableScriggoFn makes available the given function with the given name
// in the pkg package, ensuring that such function can be later retrieved if it
// is referenced in the Scriggo compiled code.
func (fs *functionStore) makeAvailableScriggoFn(pkg *ast.Package, name string, fn *runtime.Function) {
if fs.availableScriggoFuncs[pkg] == nil {
fs.availableScriggoFuncs[pkg] = map[string]*runtime.Function{}
}
fs.availableScriggoFuncs[pkg][name] = fn
}
// availableScriggoFn returns the Scriggo function with the given name available
// in the pkg package. If not available then false is returned.
func (fs *functionStore) availableScriggoFn(pkg *ast.Package, name string) (*runtime.Function, bool) {
fn, ok := fs.availableScriggoFuncs[pkg][name]
return fn, ok
}
// scriggoFnIndex returns the index of the given Scriggo function inside the
// Functions slice of the current function. If fun is not present in such slice
// it is added by this call.
func (fs *functionStore) scriggoFnIndex(fn *runtime.Function) int8 {
currFn := fs.emitter.fb.fn
if fs.scriggoFuncIndexes[currFn] == nil {
fs.scriggoFuncIndexes[currFn] = map[*runtime.Function]int8{}
}
if index, ok := fs.scriggoFuncIndexes[currFn][fn]; ok {
return index
}
index := int8(len(currFn.Functions))
currFn.Functions = append(currFn.Functions, fn)
fs.scriggoFuncIndexes[currFn][fn] = index
return index
}
// predefFunc returns the index of the predefined function 'contained' in fn if
// there's one, else returns 0 and false.
func (fs *functionStore) predefFunc(fn ast.Expression, allowMethod bool) (int8, bool) {
ti := fs.emitter.ti(fn)
if (ti == nil) || (!ti.IsNative()) {
return 0, false
}
if !allowMethod && ti.MethodType != noMethod {
return 0, false
}
if ti.Type.Kind() != reflect.Func {
return 0, false
}
if ti.Addressable() {
return 0, false
}
var name string
switch fn := fn.(type) {
case *ast.Identifier:
name = fn.Name
case *ast.Selector:
switch fn.Expr.(type) {
case *ast.Identifier:
name = fn.Ident
}
default:
// return 0, false // TODO
}
// Add the function to the Predefined slice, or get the index if already
// present.
fnRv := ti.value.(reflect.Value)
currFn := fs.emitter.fb.fn
if fs.predefFuncIndexes[currFn] == nil {
fs.predefFuncIndexes[currFn] = map[reflect.Value]int8{}
}
if index, ok := fs.predefFuncIndexes[currFn][fnRv]; ok {
return index, true
}
f := newNativeFunction(ti.NativePackageName, name, fnRv.Interface())
index := int8(len(currFn.NativeFunctions))
currFn.NativeFunctions = append(currFn.NativeFunctions, f)
if fs.predefFuncIndexes[currFn] == nil {
fs.predefFuncIndexes[currFn] = map[reflect.Value]int8{}
}
fs.predefFuncIndexes[currFn][fnRv] = index
return index, true
}