github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/desugarer/const_sender.go (about) 1 package desugarer 2 3 import ( 4 "fmt" 5 "sync/atomic" 6 7 "github.com/nevalang/neva/internal/compiler" 8 src "github.com/nevalang/neva/internal/compiler/sourcecode" 9 "github.com/nevalang/neva/internal/compiler/sourcecode/core" 10 ts "github.com/nevalang/neva/internal/compiler/sourcecode/typesystem" 11 ) 12 13 var emitterComponentRef = core.EntityRef{ 14 Pkg: "builtin", 15 Name: "New", 16 } 17 18 type handleLiteralSenderResult struct { 19 constName string 20 handleConstRefSenderResult // conceptually incorrrect but convenient to reuse 21 } 22 23 type handleConstRefSenderResult struct { 24 connToReplace src.Connection // connection without const sender 25 nodeToInsertName string // name of emitter node 26 nodeToInsert src.Node // emitter node 27 } 28 29 // In the future compiler can operate in concurrently 30 var ( 31 virtualEmittersCount atomic.Uint64 32 virtualConstCount atomic.Uint64 33 ) 34 35 func (d Desugarer) handleLiteralSender( 36 conn src.Connection, 37 ) ( 38 handleLiteralSenderResult, 39 *compiler.Error, 40 ) { 41 constCounter := virtualConstCount.Load() 42 virtualConstCount.Store(constCounter + 1) 43 constName := fmt.Sprintf("__const__%d", constCounter) 44 45 // we can't call d.handleConstRefSender() 46 // because our virtual const isn't in the scope 47 48 emitterNode := src.Node{ 49 Directives: map[src.Directive][]string{ 50 compiler.BindDirective: {constName}, 51 }, 52 EntityRef: emitterComponentRef, 53 TypeArgs: []ts.Expr{ 54 conn. 55 Normal.SenderSide. 56 Const. 57 Message. 58 TypeExpr, 59 }, 60 } 61 62 emitterCounter := virtualEmittersCount.Load() 63 virtualEmittersCount.Store(emitterCounter + 1) 64 emitterNodeName := fmt.Sprintf("__new__%d", emitterCounter) 65 66 emitterNodeOutportAddr := src.PortAddr{ 67 Node: emitterNodeName, 68 Port: "msg", 69 } 70 71 return handleLiteralSenderResult{ 72 constName: constName, 73 handleConstRefSenderResult: handleConstRefSenderResult{ 74 connToReplace: src.Connection{ 75 Normal: &src.NormalConnection{ 76 SenderSide: src.ConnectionSenderSide{ 77 PortAddr: &emitterNodeOutportAddr, 78 Selectors: conn.Normal.SenderSide.Selectors, 79 Meta: conn.Normal.SenderSide.Meta, 80 }, 81 ReceiverSide: conn.Normal.ReceiverSide, 82 }, 83 Meta: conn.Meta, 84 }, 85 nodeToInsertName: emitterNodeName, 86 nodeToInsert: emitterNode, 87 }, 88 }, nil 89 } 90 91 func (d Desugarer) handleConstRefSender( 92 conn src.Connection, 93 scope src.Scope, 94 ) ( 95 handleConstRefSenderResult, 96 *compiler.Error, 97 ) { 98 constTypeExpr, err := d.getConstTypeByRef(*conn.Normal.SenderSide.Const.Ref, scope) 99 if err != nil { 100 return handleConstRefSenderResult{}, compiler.Error{ 101 Err: fmt.Errorf( 102 "Unable to get constant type by reference '%v'", 103 *conn.Normal.SenderSide.Const.Ref, 104 ), 105 Location: &scope.Location, 106 Meta: &conn.Normal.SenderSide.Const.Ref.Meta, 107 }.Wrap(err) 108 } 109 110 counter := virtualEmittersCount.Load() 111 virtualEmittersCount.Store(counter + 1) 112 virtualEmitterName := fmt.Sprintf("__new__%d", counter) 113 114 emitterNode := src.Node{ 115 Directives: map[src.Directive][]string{ 116 compiler.BindDirective: { 117 conn.Normal.SenderSide.Const.Ref.String(), // don't forget to bind const 118 }, 119 }, 120 EntityRef: emitterComponentRef, 121 TypeArgs: []ts.Expr{constTypeExpr}, 122 } 123 emitterNodeOutportAddr := src.PortAddr{ 124 Node: virtualEmitterName, 125 Port: "msg", 126 } 127 128 return handleConstRefSenderResult{ 129 connToReplace: src.Connection{ 130 Normal: &src.NormalConnection{ 131 SenderSide: src.ConnectionSenderSide{ 132 PortAddr: &emitterNodeOutportAddr, 133 Selectors: conn.Normal.SenderSide.Selectors, 134 Meta: conn.Normal.SenderSide.Meta, 135 }, 136 ReceiverSide: conn.Normal.ReceiverSide, 137 }, 138 Meta: conn.Meta, 139 }, 140 nodeToInsertName: virtualEmitterName, 141 nodeToInsert: emitterNode, 142 }, nil 143 } 144 145 // getConstTypeByRef is needed to figure out type parameters for Const node 146 func (d Desugarer) getConstTypeByRef(ref core.EntityRef, scope src.Scope) (ts.Expr, *compiler.Error) { 147 entity, _, err := scope.Entity(ref) 148 if err != nil { 149 return ts.Expr{}, &compiler.Error{ 150 Err: err, 151 Location: &scope.Location, 152 Meta: &ref.Meta, 153 } 154 } 155 156 if entity.Kind != src.ConstEntity { 157 return ts.Expr{}, &compiler.Error{ 158 Err: fmt.Errorf("%w: %v", ErrConstSenderEntityKind, entity.Kind), 159 Location: &scope.Location, 160 Meta: entity.Meta(), 161 } 162 } 163 164 if entity.Const.Ref != nil { 165 expr, err := d.getConstTypeByRef(*entity.Const.Ref, scope) 166 if err != nil { 167 return ts.Expr{}, compiler.Error{ 168 Location: &scope.Location, 169 Meta: entity.Meta(), 170 }.Wrap(err) 171 } 172 return expr, nil 173 } 174 175 return entity.Const.Message.TypeExpr, nil 176 }