-
Notifications
You must be signed in to change notification settings - Fork 7
/
struct_selectors.go
140 lines (123 loc) 路 3.78 KB
/
struct_selectors.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
129
130
131
132
133
134
135
136
137
138
139
140
package desugarer
import (
"errors"
"fmt"
"sync/atomic"
"github.com/nevalang/neva/internal/compiler"
src "github.com/nevalang/neva/internal/compiler/sourcecode"
"github.com/nevalang/neva/internal/compiler/sourcecode/core"
ts "github.com/nevalang/neva/internal/compiler/sourcecode/typesystem"
)
var (
ErrEmptySenderSide = errors.New("Unable to desugar sender side with struct selectors because it's empty.")
ErrOutportAddrNotFound = errors.New("Outport addr not found")
ErrTypeNotStruct = errors.New("Type not struct")
ErrStructFieldNotFound = errors.New("Struct field not found")
)
type handleStructSelectorsResult struct {
connToReplace src.Connection
connToInsert src.Connection
constToInsertName string
constToInsert src.Const
nodeToInsert src.Node
nodeToInsertName string
}
var selectorNodeRef = core.EntityRef{
Pkg: "builtin",
Name: "Field",
}
var virtualSelectorsCount atomic.Uint64
func (d Desugarer) desugarStructSelectors( //nolint:funlen
normConn src.NormalConnection,
) (handleStructSelectorsResult, *compiler.Error) {
senderSide := normConn.SenderSide
constCounter := virtualConstCount.Load()
virtualConstCount.Store(constCounter + 1)
constName := fmt.Sprintf("__const__%d", constCounter)
counter := virtualSelectorsCount.Load()
virtualSelectorsCount.Store(counter + 1)
nodeName := fmt.Sprintf("__field__%d", counter)
selectorNode := src.Node{
Directives: map[src.Directive][]string{
compiler.BindDirective: {constName},
},
EntityRef: selectorNodeRef,
}
// original connection must be replaced with two new connections, this is the first one
connToReplace := src.Connection{
Normal: &src.NormalConnection{
SenderSide: src.ConnectionSenderSide{
// preserve original sender
PortAddr: senderSide.PortAddr,
Const: senderSide.Const,
// but remove selectors in desugared version
Selectors: nil,
},
ReceiverSide: src.ConnectionReceiverSide{
Receivers: []src.ConnectionReceiver{
{
PortAddr: src.PortAddr{
Node: nodeName, // point it to created selector node
Port: "msg",
},
},
},
// don't forget sometimes we have both struct selectors and deferred connections
DeferredConnections: normConn.ReceiverSide.DeferredConnections,
},
},
}
// and this is the second
connToInsert := src.Connection{
Normal: &src.NormalConnection{
SenderSide: src.ConnectionSenderSide{
PortAddr: &src.PortAddr{
Node: nodeName, // created node received data from original sender and is now sending it further
Port: "msg",
},
Selectors: nil, // no selectors in desugared version
},
ReceiverSide: normConn.ReceiverSide, // preserve original receivers
},
}
constWithCfgMsg := d.createConstWithCfgMsgForSelectorNode(senderSide)
return handleStructSelectorsResult{
connToReplace: connToReplace,
connToInsert: connToInsert,
constToInsertName: constName,
constToInsert: constWithCfgMsg,
nodeToInsertName: nodeName,
nodeToInsert: selectorNode,
}, nil
}
// list<str>
var (
strTypeExpr = ts.Expr{
Inst: &ts.InstExpr{
Ref: core.EntityRef{Pkg: "builtin", Name: "string"},
},
}
pathConstTypeExpr = ts.Expr{
Inst: &ts.InstExpr{
Ref: core.EntityRef{Pkg: "builtin", Name: "list"},
Args: []ts.Expr{strTypeExpr},
},
}
)
func (Desugarer) createConstWithCfgMsgForSelectorNode(senderSide src.ConnectionSenderSide) src.Const {
constToInsert := src.Const{
Message: &src.Message{
TypeExpr: pathConstTypeExpr,
List: make([]src.Const, 0, len(senderSide.Selectors)),
},
}
for _, selector := range senderSide.Selectors {
constToInsert.Message.List = append(constToInsert.Message.List, src.Const{
Message: &src.Message{
TypeExpr: strTypeExpr,
Str: compiler.Pointer(selector),
},
})
}
return constToInsert
}