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  }