github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/desugarer/defer_connections.go (about) 1 package desugarer 2 3 import ( 4 "fmt" 5 "maps" 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 "github.com/nevalang/neva/internal/compiler/sourcecode/typesystem" 12 ts "github.com/nevalang/neva/internal/compiler/sourcecode/typesystem" 13 ) 14 15 var virtualBlockerNode = src.Node{ 16 EntityRef: core.EntityRef{ 17 Pkg: "builtin", 18 Name: "Lock", 19 }, 20 TypeArgs: []typesystem.Expr{ 21 ts.Expr{ 22 Inst: &typesystem.InstExpr{ 23 Ref: core.EntityRef{Pkg: "builtin", Name: "any"}, 24 }, 25 }, 26 }, 27 } 28 29 type handleThenConnectionsResult struct { 30 connsToInsert []src.Connection 31 connToReplace src.Connection 32 constsToInsert map[string]src.Const 33 nodesToInsert map[string]src.Node 34 nodesPortsUsed nodePortsMap // (probably?) to generate "Del" instances where needed 35 } 36 37 var virtualBlockersCounter atomic.Uint64 38 39 func (d Desugarer) handleDeferredConnections( //nolint:funlen 40 origConn src.NormalConnection, 41 nodes map[string]src.Node, 42 scope src.Scope, 43 ) (handleThenConnectionsResult, *compiler.Error) { 44 originalSender := origConn.SenderSide 45 deferredConnections := origConn.ReceiverSide.DeferredConnections 46 47 // recursively desugar every deferred connections 48 handleNetResult, err := d.handleNetwork( 49 deferredConnections, 50 nodes, 51 scope, 52 ) 53 if err != nil { 54 return handleThenConnectionsResult{}, nil 55 } 56 57 // we want to return nodes created in recursive calls 58 // as well as the onces created by us in this call 59 virtualNodes := maps.Clone(handleNetResult.virtualNodes) 60 61 // we going to replace all desugared deferreded connections with set of our connections 62 virtualConns := make([]src.Connection, 0, len(handleNetResult.desugaredConnections)) 63 64 // for every deferred connection we must do 4 things 65 // 1) create virtual "blocker" node 66 // 2) create connection from original sender to blocker:sig 67 // 3) create connection from deferred sender to blocker:data 68 // 4) create connection from blocker:data to every receiver in deferred connection 69 70 // we gonna collect receivers for first connection instead of 71 // creating several separate connections because that won't work 72 receiversForOriginalSender := make([]src.ConnectionReceiver, 0, len(handleNetResult.desugaredConnections)) 73 74 for _, desugaredThenConn := range handleNetResult.desugaredConnections { 75 deferredConnection := desugaredThenConn.Normal 76 77 // 1) create and add virtual blocker node 78 counter := virtualBlockersCounter.Load() 79 virtualBlockersCounter.Store(counter + 1) 80 virtualBlockerName := fmt.Sprintf("__lock__%d", counter) 81 virtualNodes[virtualBlockerName] = virtualBlockerNode 82 83 // 2) create connection from original sender to blocker:sig 84 receiversForOriginalSender = append( 85 receiversForOriginalSender, 86 src.ConnectionReceiver{ 87 PortAddr: src.PortAddr{ 88 Node: virtualBlockerName, 89 Port: "sig", 90 }, 91 }, 92 ) 93 94 virtualConns = append(virtualConns, 95 // 3) create connection from deferred sender to blocker:data 96 src.Connection{ 97 Normal: &src.NormalConnection{ 98 SenderSide: deferredConnection.SenderSide, 99 ReceiverSide: src.ConnectionReceiverSide{ 100 Receivers: []src.ConnectionReceiver{ 101 { 102 PortAddr: src.PortAddr{ 103 Node: virtualBlockerName, 104 Port: "data", 105 }, 106 }, 107 }, 108 }, 109 }, 110 }, 111 // 4) create connection from blocker:data to every receiver in deferred connection 112 src.Connection{ 113 Normal: &src.NormalConnection{ 114 SenderSide: src.ConnectionSenderSide{ 115 PortAddr: &src.PortAddr{ 116 Node: virtualBlockerName, 117 Port: "data", 118 }, 119 }, 120 ReceiverSide: src.ConnectionReceiverSide{ 121 Receivers: deferredConnection.ReceiverSide.Receivers, 122 }, 123 }, 124 }, 125 ) 126 } 127 128 // don't forget to append normal original sender receivers 129 // there are connections with both deferred connections and normal receivers 130 receiversForOriginalSender = append( 131 receiversForOriginalSender, 132 origConn.ReceiverSide.Receivers..., 133 ) 134 135 // don't forget to append first connection 136 connToReplace := src.Connection{ 137 Normal: &src.NormalConnection{ 138 SenderSide: originalSender, 139 ReceiverSide: src.ConnectionReceiverSide{ 140 Receivers: receiversForOriginalSender, 141 }, 142 }, 143 } 144 145 return handleThenConnectionsResult{ 146 nodesToInsert: virtualNodes, 147 connsToInsert: virtualConns, 148 constsToInsert: handleNetResult.virtualConstants, 149 nodesPortsUsed: handleNetResult.usedNodePorts, 150 connToReplace: connToReplace, 151 }, nil 152 }