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: &param.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  }