github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/desugarer/component.go (about)

     1  package desugarer
     2  
     3  import (
     4  	"errors"
     5  	"maps"
     6  	"slices"
     7  
     8  	"github.com/nevalang/neva/internal/compiler"
     9  	src "github.com/nevalang/neva/internal/compiler/sourcecode"
    10  )
    11  
    12  var ErrConstSenderEntityKind = errors.New(
    13  	"Entity that is used as a const reference in component's network must be of kind constant",
    14  )
    15  
    16  type handleComponentResult struct {
    17  	desugaredComponent src.Component         // desugared component to replace
    18  	virtualEntities    map[string]src.Entity //nolint:lll // sometimes after desugaring component we need to insert some entities to the file
    19  }
    20  
    21  func (d Desugarer) handleComponent( //nolint:funlen
    22  	component src.Component,
    23  	scope src.Scope,
    24  ) (handleComponentResult, *compiler.Error) {
    25  	if len(component.Net) == 0 && len(component.Nodes) == 0 {
    26  		return handleComponentResult{desugaredComponent: component}, nil
    27  	}
    28  
    29  	virtualEntities := map[string]src.Entity{}
    30  
    31  	desugaredNodes, virtConnsForNodes, err := d.handleNodes(
    32  		component,
    33  		scope,
    34  		virtualEntities,
    35  	)
    36  	if err != nil {
    37  		return handleComponentResult{}, err
    38  	}
    39  
    40  	netToDesugar := append(virtConnsForNodes, component.Net...)
    41  	handleNetResult, err := d.handleNetwork(
    42  		netToDesugar,
    43  		desugaredNodes,
    44  		scope,
    45  	)
    46  	if err != nil {
    47  		return handleComponentResult{}, err
    48  	}
    49  
    50  	desugaredNetwork := slices.Clone(handleNetResult.desugaredConnections)
    51  
    52  	// add virtual constants created by network handler to virtual entities
    53  	for name, constant := range handleNetResult.virtualConstants {
    54  		virtualEntities[name] = src.Entity{
    55  			Kind:  src.ConstEntity,
    56  			Const: constant,
    57  		}
    58  	}
    59  
    60  	// merge real nodes with virtual ones created by network handler
    61  	maps.Copy(desugaredNodes, handleNetResult.virtualNodes)
    62  
    63  	// create virtual destructor nodes and connections to handle unused outports
    64  	unusedOutports := d.findUnusedOutports(
    65  		component,
    66  		scope,
    67  		handleNetResult.usedNodePorts,
    68  	)
    69  	if unusedOutports.len() != 0 {
    70  		unusedOutportsResult := d.handleUnusedOutports(unusedOutports)
    71  		desugaredNetwork = append(desugaredNetwork, unusedOutportsResult.virtualConnections...)
    72  		desugaredNodes[unusedOutportsResult.voidNodeName] = unusedOutportsResult.voidNode
    73  	}
    74  
    75  	return handleComponentResult{
    76  		desugaredComponent: src.Component{
    77  			Directives: component.Directives,
    78  			Interface:  component.Interface,
    79  			Nodes:      desugaredNodes,
    80  			Net:        desugaredNetwork,
    81  			Meta:       component.Meta,
    82  		},
    83  		virtualEntities: virtualEntities,
    84  	}, nil
    85  }
    86  
    87  func (d Desugarer) handleNodes(
    88  	component src.Component,
    89  	scope src.Scope,
    90  	virtualEntities map[string]src.Entity,
    91  ) (map[string]src.Node, []src.Connection, *compiler.Error) {
    92  	desugaredNodes := make(map[string]src.Node, len(component.Nodes))
    93  	virtualConns := []src.Connection{}
    94  
    95  	for nodeName, node := range component.Nodes {
    96  		extraConns, err := d.handleNode(
    97  			scope,
    98  			node,
    99  			desugaredNodes,
   100  			nodeName,
   101  			virtualEntities,
   102  		)
   103  		if err != nil {
   104  			return nil, nil, err
   105  		}
   106  
   107  		virtualConns = append(virtualConns, extraConns...)
   108  	}
   109  
   110  	return desugaredNodes, virtualConns, nil
   111  }