Skip to content

Commit

Permalink
wip(analyzer): component
Browse files Browse the repository at this point in the history
  • Loading branch information
emil14 committed Sep 30, 2023
1 parent c74594d commit d6fd7aa
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 121 deletions.
2 changes: 1 addition & 1 deletion examples/003_hello_world_2.neva
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ components {
}
net {
in.enter -> lock.in.sig
string 'Hello, World!\n' -> lock.in.v // TODO do we need this?
string 'Hello, World!\n' -> lock.in.v
lock.out.v -> print.in.v
print.out.v -> out.exit
}
Expand Down
2 changes: 1 addition & 1 deletion examples/004_hello_world_3.neva
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use {
}

components {
Main(enter string 'Hello, World!') (exit) {
Main(enter string 'Hello, World!\n') (exit) {
nodes {
print std.Print<str>
}
Expand Down
24 changes: 22 additions & 2 deletions examples/008_calculator_1.neva → examples/008_calculator.neva
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ components {
nodes {
print std.Print
readOp ReadOp
readFirstNum, readSecondNum ReadNum
readFirstNum ReadNum
readSecondNum ReadNum
calc Calc
}
net {
Expand All @@ -41,6 +42,10 @@ components {
}
ReadOp(sig) (v str) {
nodes {
read std.Read
has std.Has
lockErr std.Lock
lockResult std.Lock
}
net {
in.sig -> read.in.sig // read operation
Expand All @@ -54,6 +59,21 @@ components {
}
}
ReadNum(sig) (v int) {

nodes {
read std.Read
parse std.Parse
lockErr std.Lock
lockResult std.Lock
}
net {
in.sig -> read.in.sig // read number
read.out.v -> parse.in.v // parse it
parse.out.err -> out.err // if error trigger error locker
parse.out.v -> lockResult.in.sig // otherwise trigger result locker
parse.out.v -> out.v // and send result to the outport
parse.out.err -> lockErr.in.v // lock error in case of error
lockErr.out.v -> out.err // and send it to the outport
lockResult.out.v -> out.v // send result to the outport
}
}
}
8 changes: 0 additions & 8 deletions examples/009_calculator_2.neva

This file was deleted.

66 changes: 12 additions & 54 deletions internal/compiler/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import (
"fmt"

"github.com/nevalang/neva/internal/compiler/src"
"github.com/nevalang/neva/pkg/typesystem"
ts "github.com/nevalang/neva/pkg/typesystem"
)

type Analyzer struct {
resolver typesystem.Resolver
prog src.Program
resolver ts.Resolver
}

var (
Expand All @@ -20,8 +20,8 @@ var (
ErrUnknownEntityKind = errors.New("unknown entity kind")
)

// AnalyzeAndResolve returns error if program is invalid. It also modifies program by resolving types.
func (a Analyzer) AnalyzeAndResolve(prog src.Program) error {
// Analyze returns error if program is invalid. It also modifies program by resolving types.
func (a Analyzer) Analyze(prog src.Program) error {
if len(prog) == 0 {
return ErrEmptyProgram
}
Expand Down Expand Up @@ -60,7 +60,7 @@ func (a Analyzer) analyzePkg(pkg src.Package, prog src.Program) (src.Package, er
}

if err := pkg.Entities(func(entity src.Entity, entityName, fileName string) error {
resolvedEntity, err := a.analyzeEntity(entityName, entity, pkg[fileName])
resolvedEntity, err := a.analyzeEntity(entity, prog)
if err != nil {
return fmt.Errorf("analyze entity: %v: %v: %w", entityName, fileName, err)
}
Expand All @@ -73,7 +73,7 @@ func (a Analyzer) analyzePkg(pkg src.Package, prog src.Program) (src.Package, er
return resolvedPkg, nil
}

func (a Analyzer) analyzeEntity(entityName string, entity src.Entity, file src.File) (src.Entity, error) {
func (a Analyzer) analyzeEntity(entity src.Entity, prog src.Program) (src.Entity, error) {
resolvedEntity := src.Entity{
Exported: entity.Exported,
Kind: entity.Kind,
Expand All @@ -99,62 +99,20 @@ func (a Analyzer) analyzeEntity(entityName string, entity src.Entity, file src.F
}
resolvedEntity.Interface = resolvedInterface
case src.ComponentEntity:
if err := a.analyzeComponent(entity.Component); err != nil {
resolvedComp, err := a.analyzeComponent(entity.Component, prog)
if err != nil {
return src.Entity{}, fmt.Errorf("analyze component: %w", err)
}
resolvedEntity.Component = resolvedComp
default:
return src.Entity{}, fmt.Errorf("%w: %v", ErrUnknownEntityKind, entity.Kind)
}

return resolvedEntity, nil
}

var ErrCustomBaseType = errors.New("custom type must have body expression and cannot be used for recursive definitions")

func (a Analyzer) analyzeTypeDef(def typesystem.Def) (typesystem.Def, error) {
return def, nil // TODO
}

// TODO unused
func (Analyzer) buildTestExprArgs(params []ts.Param) []ts.Expr {
args := make([]ts.Expr, 0, len(params))
for _, param := range params {
if param.Constr == nil {
args = append(args, ts.Expr{
Inst: &ts.InstExpr{Ref: "any"},
})
} else {
args = append(args, *param.Constr)
}
}
return args
}

// FIXME constr_refereing_type_parameter_(generics_inside_generics)" t<int, vec<int>> {t<a, b vec<a>>, vec<t>, int}
func (a Analyzer) resolveTypeParams(params []ts.Param) ([]ts.Param, error) {
resolvedParams := make([]ts.Param, 0, len(params))
for _, param := range params {
if param.Constr == nil {
resolvedParams = append(resolvedParams, param)
continue
}
resolvedParam, err := a.resolveTypeExpr(*param.Constr)
if err != nil {
return nil, fmt.Errorf("analyze type expr: %w", err)
}
resolvedParams = append(resolvedParams, ts.Param{
Name: param.Name,
Constr: &resolvedParam,
})
func MustNew(resolver ts.Resolver) Analyzer {
return Analyzer{
resolver: resolver,
}
return resolvedParams, nil
}

func (a Analyzer) resolveTypeExpr(expr typesystem.Expr) (typesystem.Expr, error) {
a.resolver.Resolve(expr, nil)
return expr, nil
}

func (a Analyzer) analyzeComponent(def src.Component) error {
return nil
}
92 changes: 92 additions & 0 deletions internal/compiler/analyzer/component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package analyzer

import (
"errors"
"fmt"

"github.com/nevalang/neva/internal/compiler/src"
ts "github.com/nevalang/neva/pkg/typesystem"
)

func (a Analyzer) analyzeComponent(comp src.Component, prog src.Program) (src.Component, error) {
resolvedInterface, err := a.analyzeInterface(comp.Interface)
if err != nil {
return src.Component{}, fmt.Errorf("analyze interface: %w", err)
}

if err := a.analyzeComponentNodes(comp.Nodes, prog); err != nil {
return src.Component{}, fmt.Errorf("analyze component nodes: %w", err)
}

normalizedNetwork, err := a.analyzeComponentNet(comp.Net, resolvedInterface, comp.Nodes)
if err != nil {
return src.Component{}, fmt.Errorf("analyze component network: %w", err)
}

return src.Component{
Interface: resolvedInterface,
Nodes: comp.Nodes,
Net: normalizedNetwork,
}, nil
}

func (a Analyzer) analyzeComponentNodes(nodes map[string]src.Node, prog src.Program) error {
for _, node := range nodes {
if err := a.analyzeComponentNode(node, prog); err != nil {
return fmt.Errorf("analyze node: %w", err)
}
}
return nil
}

var (
ErrNodeEntity = fmt.Errorf("node entity is not a component or interface")
ErrNodeTypeArgsCountMismatch = errors.New("node type args count mismatch")
)

func (a Analyzer) analyzeComponentNode(node src.Node, prog src.Program) error {
entity, err := prog.Entity(node.EntityRef)
if err != nil {
return fmt.Errorf("entity: %w", err)
}

if entity.Kind != src.ComponentEntity && entity.Kind != src.InterfaceEntity {
return fmt.Errorf("%w: %v", ErrNodeEntity, entity.Kind)
}

var compInterface src.Interface
if entity.Kind == src.ComponentEntity {
compInterface = entity.Component.Interface
} else {
compInterface = entity.Interface
}

if len(node.TypeArgs) != len(compInterface.TypeParams) {
return fmt.Errorf(
"%w: want %v, got %v",
ErrNodeTypeArgsCountMismatch, compInterface.TypeParams, node.TypeArgs,
)
}

resolvedArgs := make([]ts.Expr, 0, len(node.TypeArgs))
for _, arg := range node.TypeArgs {
resolvedArg, err := a.analyzeTypeExpr(arg)
if err != nil {
return fmt.Errorf("analyze type expr: %w", err)
}
resolvedArgs = append(resolvedArgs, resolvedArg)
}

// check that args are compatible with type params
// this can be done by creating

return nil
}

func (a Analyzer) analyzeComponentNet(
net []src.Connection,
compInterface src.Interface,
nodes map[string]src.Node,
) ([]src.Connection, error) {
return net, nil // TODO
}
2 changes: 1 addition & 1 deletion internal/compiler/analyzer/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (a Analyzer) analyzeConst(constant src.Const) (src.Const, error) {
panic("// TODO: references for constants not implemented yet")
}

resolvedType, err := a.resolveTypeExpr(constant.Value.TypeExpr)
resolvedType, err := a.analyzeTypeExpr(constant.Value.TypeExpr)
if err != nil {
return src.Const{}, fmt.Errorf("%w: %v", ErrResolveConstType, err)
}
Expand Down
23 changes: 12 additions & 11 deletions internal/compiler/analyzer/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
var ErrInterfaceTypeParams = errors.New("could not resolve interface type parameters")

func (a Analyzer) analyzeInterface(def src.Interface) (src.Interface, error) {
resolvedParams, err := a.resolveTypeParams(def.Params)
resolvedParams, err := a.analyzeTypeParams(def.TypeParams)
if err != nil {
return src.Interface{}, fmt.Errorf("%w: %v", ErrInterfaceTypeParams, def.Params)
return src.Interface{}, fmt.Errorf("%w: %v", ErrInterfaceTypeParams, def.TypeParams)
}

resolvedIO, err := a.analyzeIO(resolvedParams, def.IO)
Expand All @@ -22,8 +22,8 @@ func (a Analyzer) analyzeInterface(def src.Interface) (src.Interface, error) {
}

return src.Interface{
Params: resolvedParams,
IO: resolvedIO,
TypeParams: resolvedParams,
IO: resolvedIO,
}, nil
}

Expand Down Expand Up @@ -57,19 +57,20 @@ func (a Analyzer) analyzePorts(params []ts.Param, ports map[string]src.Port) (ma
}

func (a Analyzer) analyzePort(params []ts.Param, port src.Port) (src.Port, error) {
if port.Type == nil {
if port.TypeExpr == nil {
return port, nil
}

// IDEA: create virtual def and resolve it as we do for regular type defs

resolvedType, err := a.resolveTypeExpr(*port.Type)
resolvedDef, err := a.analyzeTypeDef(ts.Def{
Params: params,
BodyExpr: port.TypeExpr,
})
if err != nil {
return src.Port{}, fmt.Errorf("resolve type expr: %w", err)
return src.Port{}, fmt.Errorf("analyze type def: %w", err)
}

return src.Port{
Type: &resolvedType,
IsArray: port.IsArray,
TypeExpr: resolvedDef.BodyExpr,
IsArray: port.IsArray,
}, nil
}
8 changes: 4 additions & 4 deletions internal/compiler/analyzer/main_component.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ var (
)

func (a Analyzer) analyzeMainComponent(cmp src.Component, pkg src.Package, pkgs map[string]src.Package) error { //nolint:unparam,lll
if len(cmp.Interface.Params) != 0 {
return fmt.Errorf("%w: %v", ErrMainComponentWithTypeParams, cmp.Interface.Params)
if len(cmp.Interface.TypeParams) != 0 {
return fmt.Errorf("%w: %v", ErrMainComponentWithTypeParams, cmp.Interface.TypeParams)
}

if err := a.analyzeMainComponentIO(cmp.Interface.IO); err != nil {
Expand Down Expand Up @@ -54,7 +54,7 @@ func (a Analyzer) analyzeMainComponentIO(io src.IO) error {
return ErrMainPortIsArray
}

if enterInport.Type != nil {
if enterInport.TypeExpr != nil {
return ErrMainComponentPortTypeNotAny
}

Expand All @@ -67,7 +67,7 @@ func (a Analyzer) analyzeMainComponentIO(io src.IO) error {
return ErrMainPortIsArray
}

if exitInport.Type != nil {
if exitInport.TypeExpr != nil {
return ErrMainComponentPortTypeNotAny
}

Expand Down
31 changes: 31 additions & 0 deletions internal/compiler/analyzer/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package analyzer

import (
"fmt"

ts "github.com/nevalang/neva/pkg/typesystem"
)

func (a Analyzer) analyzeTypeDef(def ts.Def) (ts.Def, error) {
resolvedDef, err := a.resolver.ResolveDef(def, nil)
if err != nil {
return ts.Def{}, fmt.Errorf("resolve def: %w", err)
}
return resolvedDef, nil
}

func (a Analyzer) analyzeTypeExpr(expr ts.Expr) (ts.Expr, error) {
resolvedExpr, err := a.resolver.ResolveExpr(expr, nil)
if err != nil {
return ts.Expr{}, fmt.Errorf("resolve expr: %w", err)
}
return resolvedExpr, nil
}

func (a Analyzer) analyzeTypeParams(params []ts.Param) ([]ts.Param, error) {
resolvedParams, _, err := a.resolver.ResolveParams(params, nil)
if err != nil {
return nil, fmt.Errorf("resolve params: %w", err)
}
return resolvedParams, nil
}
Loading

0 comments on commit d6fd7aa

Please sign in to comment.