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 }