github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/sourcecode/sourcecode.go (about) 1 // This package defines source code entities - abstractions that end-user (a programmer) operates on. 2 // For convenience these structures have json tags. This is not clean architecture but it's very handy for LSP. 3 package sourcecode 4 5 import ( 6 "errors" 7 "fmt" 8 9 "github.com/nevalang/neva/internal/compiler/sourcecode/core" 10 ts "github.com/nevalang/neva/internal/compiler/sourcecode/typesystem" 11 ) 12 13 type Build struct { 14 EntryModRef ModuleRef `json:"entryModRef,omitempty"` 15 Modules map[ModuleRef]Module `json:"modules,omitempty"` 16 } 17 18 type Module struct { 19 Manifest ModuleManifest `json:"manifest,omitempty"` 20 Packages map[string]Package `json:"packages,omitempty"` 21 } 22 23 func (mod Module) Entity(entityRef core.EntityRef) (entity Entity, filename string, err error) { 24 pkg, ok := mod.Packages[entityRef.Pkg] 25 if !ok { 26 return Entity{}, "", fmt.Errorf("%w '%v'", ErrPkgNotFound, entityRef.Pkg) 27 } 28 29 entity, filename, ok = pkg.Entity(entityRef.Name) 30 if !ok { 31 return Entity{}, "", fmt.Errorf("%w: '%v'", ErrEntityNotFound, entityRef.Name) 32 } 33 34 return entity, filename, nil 35 } 36 37 func (mod Module) Files(f func(file File, pkgName, fileName string)) { 38 for pkgName, pkg := range mod.Packages { 39 for fileName, file := range pkg { 40 f(file, pkgName, fileName) 41 } 42 } 43 } 44 45 type ModuleManifest struct { 46 LanguageVersion string `json:"neva,omitempty" yaml:"neva,omitempty"` 47 Deps map[string]ModuleRef `json:"deps,omitempty" yaml:"deps,omitempty"` 48 } 49 50 type ModuleRef struct { 51 Path string `json:"path,omitempty"` 52 Version string `json:"version,omitempty"` 53 } 54 55 func (m ModuleRef) String() string { 56 if m.Version == "" { 57 return m.Path 58 } 59 return fmt.Sprintf("%v@%v", m.Path, m.Version) 60 } 61 62 var ErrEntityNotFound = errors.New("entity not found") 63 64 type Package map[string]File 65 66 // Just like program's Entity 67 func (p Package) Entity(entityName string) (entity Entity, filename string, ok bool) { 68 for fileName, file := range p { 69 entity, ok := file.Entities[entityName] 70 if ok { 71 return entity, fileName, true 72 } 73 } 74 return Entity{}, "", false 75 } 76 77 func (p Package) Entities(f func(entity Entity, entityName string, fileName string) error) error { 78 for fileName, file := range p { 79 for entityName, entity := range file.Entities { 80 if err := f(entity, entityName, fileName); err != nil { 81 return err 82 } 83 } 84 } 85 return nil 86 } 87 88 type File struct { 89 Imports map[string]Import `json:"imports,omitempty"` 90 Entities map[string]Entity `json:"entities,omitempty"` 91 } 92 93 type Import struct { 94 Module string `json:"moduleName,omitempty"` 95 Package string `json:"pkgName,omitempty"` 96 } 97 98 type Entity struct { 99 IsPublic bool `json:"exported,omitempty"` 100 Kind EntityKind `json:"kind,omitempty"` 101 Const Const `json:"const,omitempty"` 102 Type ts.Def `json:"type,omitempty"` 103 Interface Interface `json:"interface,omitempty"` 104 Component Component `json:"component,omitempty"` 105 } 106 107 func (e Entity) Meta() *core.Meta { 108 m := core.Meta{} 109 switch e.Kind { 110 case ConstEntity: 111 m = e.Const.Meta 112 case TypeEntity: 113 m = e.Type.Meta.(core.Meta) //nolint 114 case InterfaceEntity: 115 m = e.Interface.Meta 116 case ComponentEntity: 117 m = e.Component.Meta 118 } 119 return &m 120 } 121 122 type EntityKind string // It's handy to transmit strings enum instead of digital 123 124 const ( 125 ComponentEntity EntityKind = "component_entity" 126 ConstEntity EntityKind = "const_entity" 127 TypeEntity EntityKind = "type_entity" 128 InterfaceEntity EntityKind = "interface_entity" 129 ) 130 131 type Component struct { 132 Directives map[Directive][]string `json:"directives,omitempty"` 133 Interface `json:"interface,omitempty"` 134 Nodes map[string]Node `json:"nodes,omitempty"` 135 Net []Connection `json:"net,omitempty"` 136 Meta core.Meta `json:"meta,omitempty"` 137 } 138 139 type Directive string 140 141 type Interface struct { 142 TypeParams TypeParams `json:"typeParams,omitempty"` 143 IO IO `json:"io,omitempty,"` 144 Meta core.Meta `json:"meta,omitempty"` 145 } 146 147 type TypeParams struct { 148 Params []ts.Param `json:"params,omitempty"` 149 Meta core.Meta `json:"meta,omitempty"` 150 } 151 152 func (t TypeParams) ToFrame() map[string]ts.Def { 153 frame := make(map[string]ts.Def, len(t.Params)) 154 for _, param := range t.Params { 155 frame[param.Name] = ts.Def{ 156 BodyExpr: ¶m.Constr, 157 Meta: param.Constr.Meta, 158 } 159 } 160 return frame 161 } 162 163 func (t TypeParams) String() string { 164 s := "<" 165 for i, param := range t.Params { 166 s += param.Name + " " + param.Constr.String() 167 if i < len(t.Params)-1 { 168 s += ", " 169 } 170 } 171 return s + ">" 172 } 173 174 type Node struct { 175 Directives map[Directive][]string `json:"directives,omitempty"` 176 EntityRef core.EntityRef `json:"entityRef,omitempty"` 177 TypeArgs TypeArgs `json:"typeArgs,omitempty"` 178 ErrGuard bool `json:"errGuard,omitempty"` 179 Deps map[string]Node `json:"componentDi,omitempty"` 180 Meta core.Meta `json:"meta,omitempty"` 181 } 182 183 func (n Node) String() string { 184 return fmt.Sprintf("%v%v", n.EntityRef.String(), n.TypeArgs.String()) 185 } 186 187 type TypeArgs []ts.Expr 188 189 func (t TypeArgs) String() string { 190 s := "<" 191 for i, arg := range t { 192 s += arg.String() 193 if i < len(t)-1 { 194 s += " , " 195 } 196 } 197 return s + ">" 198 } 199 200 type Const struct { 201 Ref *core.EntityRef `json:"ref,omitempty"` 202 Message *Message `json:"value,omitempty"` 203 Meta core.Meta `json:"meta,omitempty"` 204 } 205 206 func (c Const) String() string { 207 if c.Ref != nil { 208 return c.Ref.String() 209 } 210 if c.Message == nil { 211 return "<invalid_message>" 212 } 213 return c.Message.String() 214 } 215 216 type Message struct { 217 TypeExpr ts.Expr `json:"typeExpr,omitempty"` 218 Bool *bool `json:"bool,omitempty"` 219 Int *int `json:"int,omitempty"` 220 Float *float64 `json:"float,omitempty"` 221 Str *string `json:"str,omitempty"` 222 List []Const `json:"vec,omitempty"` 223 MapOrStruct map[string]Const `json:"map,omitempty"` 224 Enum *EnumMessage `json:"enum,omitempty"` 225 Meta core.Meta `json:"meta,omitempty"` 226 } 227 228 type EnumMessage struct { 229 EnumRef core.EntityRef 230 MemberName string 231 } 232 233 func (m Message) String() string { 234 switch { 235 case m.Bool != nil: 236 return fmt.Sprintf("%v", *m.Bool) 237 case m.Int != nil: 238 return fmt.Sprintf("%v", *m.Int) 239 case m.Float != nil: 240 return fmt.Sprintf("%v", *m.Float) 241 case m.Str != nil: 242 return fmt.Sprintf("%q", *m.Str) 243 case len(m.List) != 0: 244 s := "[" 245 for i, item := range m.List { 246 s += item.String() 247 if i != len(m.List)-1 { 248 s += ", " 249 } 250 } 251 return s + "]" 252 case len(m.MapOrStruct) != 0: 253 s := "{" 254 for key, value := range m.MapOrStruct { 255 s += fmt.Sprintf("%q: %v", key, value.String()) 256 } 257 return s + "}" 258 } 259 return "message" 260 } 261 262 type IO struct { 263 In map[string]Port `json:"in,omitempty"` 264 Out map[string]Port `json:"out,omitempty"` 265 } 266 267 type Port struct { 268 TypeExpr ts.Expr `json:"typeExpr,omitempty"` 269 IsArray bool `json:"isArray,omitempty"` 270 Meta core.Meta `json:"meta,omitempty"` 271 } 272 273 type Connection struct { 274 Normal *NormalConnection `json:"normal,omitempty"` 275 ArrayBypass *ArrayBypassConnection `json:"arrayBypass,omitempty"` 276 Meta core.Meta `json:"meta,omitempty"` 277 } 278 279 type NormalConnection struct { 280 SenderSide ConnectionSenderSide `json:"senderSide,omitempty"` 281 ReceiverSide ConnectionReceiverSide `json:"receiverSide,omitempty"` 282 } 283 284 type ArrayBypassConnection struct { 285 SenderOutport PortAddr `json:"senderOutport,omitempty"` 286 ReceiverInport PortAddr `json:"receiverOutport,omitempty"` 287 } 288 289 type ConnectionReceiverSide struct { 290 DeferredConnections []Connection `json:"deferredConnections,omitempty"` 291 Receivers []ConnectionReceiver `json:"receivers,omitempty"` 292 } 293 294 type ConnectionReceiver struct { 295 PortAddr PortAddr `json:"portAddr,omitempty"` 296 Selectors ConnectionSideSelectors `json:"selectors,omitempty"` 297 Meta core.Meta `json:"meta,omitempty"` 298 } 299 300 type ConnectionSideSelectors []string 301 302 func (c ConnectionSideSelectors) String() string { 303 if len(c) == 0 { 304 return "" 305 } 306 s := "" 307 for i, field := range c { 308 s += field 309 if i != len(c)-1 { 310 s += "/" 311 } 312 } 313 return s 314 } 315 316 func (r ConnectionReceiver) String() string { 317 if len(r.Selectors) == 0 { 318 return r.PortAddr.String() 319 } 320 return fmt.Sprintf("%v/%v", r.PortAddr.String(), r.Selectors.String()) 321 } 322 323 // ConnectionSenderSide unlike ReceiverConnectionSide could refer to constant. 324 type ConnectionSenderSide struct { 325 PortAddr *PortAddr `json:"portAddr,omitempty"` 326 Const *Const `json:"literal,omitempty"` 327 Selectors []string `json:"selectors,omitempty"` 328 Meta core.Meta `json:"meta,omitempty"` 329 } 330 331 func (s ConnectionSenderSide) String() string { 332 selectorsString := "" 333 if len(s.Selectors) != 0 { 334 for _, selector := range s.Selectors { 335 selectorsString += ":" + selector 336 } 337 } 338 339 var result string 340 if s.Const != nil { 341 if s.Const.Ref != nil { 342 result = s.Const.Ref.String() 343 } else { 344 result = s.Const.Message.String() 345 } 346 } else { 347 result = s.PortAddr.String() 348 } 349 350 return result + selectorsString 351 } 352 353 type PortAddr struct { 354 Node string `json:"node,omitempty"` 355 Port string `json:"port,omitempty"` 356 Idx *uint8 `json:"idx,omitempty"` 357 Meta core.Meta `json:"meta,omitempty"` 358 } 359 360 func (p PortAddr) String() string { 361 hasNode := p.Node != "" 362 hasPort := p.Port != "" 363 hasIdx := p.Idx != nil 364 365 switch { 366 case hasNode && hasPort && hasIdx: 367 return fmt.Sprintf("%v:%v[%v]", p.Node, p.Port, *p.Idx) 368 case hasNode && hasPort: 369 return fmt.Sprintf("%v:%v", p.Node, p.Port) 370 case hasNode: 371 return fmt.Sprintf("%v:UNKNOWN", p.Node) 372 } 373 374 return "invalid port addr" 375 }