github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/desugarer/struct_selectors.go (about) 1 package desugarer 2 3 import ( 4 "errors" 5 "fmt" 6 "sync/atomic" 7 8 "github.com/nevalang/neva/internal/compiler" 9 src "github.com/nevalang/neva/internal/compiler/sourcecode" 10 "github.com/nevalang/neva/internal/compiler/sourcecode/core" 11 ts "github.com/nevalang/neva/internal/compiler/sourcecode/typesystem" 12 ) 13 14 var ( 15 ErrEmptySenderSide = errors.New("Unable to desugar sender side with struct selectors because it's empty.") 16 ErrOutportAddrNotFound = errors.New("Outport addr not found") 17 ErrTypeNotStruct = errors.New("Type not struct") 18 ErrStructFieldNotFound = errors.New("Struct field not found") 19 ) 20 21 type handleStructSelectorsResult struct { 22 connToReplace src.Connection 23 connToInsert src.Connection 24 constToInsertName string 25 constToInsert src.Const 26 nodeToInsert src.Node 27 nodeToInsertName string 28 } 29 30 var selectorNodeRef = core.EntityRef{ 31 Pkg: "builtin", 32 Name: "Field", 33 } 34 35 var virtualSelectorsCount atomic.Uint64 36 37 func (d Desugarer) desugarStructSelectors( //nolint:funlen 38 normConn src.NormalConnection, 39 ) (handleStructSelectorsResult, *compiler.Error) { 40 senderSide := normConn.SenderSide 41 42 constCounter := virtualConstCount.Load() 43 virtualConstCount.Store(constCounter + 1) 44 constName := fmt.Sprintf("__const__%d", constCounter) 45 46 counter := virtualSelectorsCount.Load() 47 virtualSelectorsCount.Store(counter + 1) 48 nodeName := fmt.Sprintf("__field__%d", counter) 49 50 selectorNode := src.Node{ 51 Directives: map[src.Directive][]string{ 52 compiler.BindDirective: {constName}, 53 }, 54 EntityRef: selectorNodeRef, 55 } 56 57 // original connection must be replaced with two new connections, this is the first one 58 connToReplace := src.Connection{ 59 Normal: &src.NormalConnection{ 60 SenderSide: src.ConnectionSenderSide{ 61 // preserve original sender 62 PortAddr: senderSide.PortAddr, 63 Const: senderSide.Const, 64 // but remove selectors in desugared version 65 Selectors: nil, 66 }, 67 ReceiverSide: src.ConnectionReceiverSide{ 68 Receivers: []src.ConnectionReceiver{ 69 { 70 PortAddr: src.PortAddr{ 71 Node: nodeName, // point it to created selector node 72 Port: "msg", 73 }, 74 }, 75 }, 76 // don't forget sometimes we have both struct selectors and deferred connections 77 DeferredConnections: normConn.ReceiverSide.DeferredConnections, 78 }, 79 }, 80 } 81 82 // and this is the second 83 connToInsert := src.Connection{ 84 Normal: &src.NormalConnection{ 85 SenderSide: src.ConnectionSenderSide{ 86 PortAddr: &src.PortAddr{ 87 Node: nodeName, // created node received data from original sender and is now sending it further 88 Port: "msg", 89 }, 90 Selectors: nil, // no selectors in desugared version 91 }, 92 ReceiverSide: normConn.ReceiverSide, // preserve original receivers 93 }, 94 } 95 96 constWithCfgMsg := d.createConstWithCfgMsgForSelectorNode(senderSide) 97 98 return handleStructSelectorsResult{ 99 connToReplace: connToReplace, 100 connToInsert: connToInsert, 101 constToInsertName: constName, 102 constToInsert: constWithCfgMsg, 103 nodeToInsertName: nodeName, 104 nodeToInsert: selectorNode, 105 }, nil 106 } 107 108 // list<str> 109 var ( 110 strTypeExpr = ts.Expr{ 111 Inst: &ts.InstExpr{ 112 Ref: core.EntityRef{Pkg: "builtin", Name: "string"}, 113 }, 114 } 115 116 pathConstTypeExpr = ts.Expr{ 117 Inst: &ts.InstExpr{ 118 Ref: core.EntityRef{Pkg: "builtin", Name: "list"}, 119 Args: []ts.Expr{strTypeExpr}, 120 }, 121 } 122 ) 123 124 func (Desugarer) createConstWithCfgMsgForSelectorNode(senderSide src.ConnectionSenderSide) src.Const { 125 constToInsert := src.Const{ 126 Message: &src.Message{ 127 TypeExpr: pathConstTypeExpr, 128 List: make([]src.Const, 0, len(senderSide.Selectors)), 129 }, 130 } 131 for _, selector := range senderSide.Selectors { 132 constToInsert.Message.List = append(constToInsert.Message.List, src.Const{ 133 Message: &src.Message{ 134 TypeExpr: strTypeExpr, 135 Str: compiler.Pointer(selector), 136 }, 137 }) 138 } 139 return constToInsert 140 }