From d3215feed8f5a16f225ecc5f8c01d00342622cad Mon Sep 17 00:00:00 2001 From: Emil Valeev Date: Sun, 21 Apr 2024 10:14:26 +0500 Subject: [PATCH 1/5] wip --- .vscode/launch.json | 259 +------------------- README.md | 72 +++--- examples/struct_selector/main.neva | 9 +- internal/cli/cli.go | 11 +- internal/compiler/analyzer/component_net.go | 1 + internal/compiler/compiler.go | 5 +- internal/compiler/desugarer/network.go | 132 ++++++---- 7 files changed, 141 insertions(+), 348 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 328d3b5d..bd4f070a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,10 +1,8 @@ { "version": "0.2.0", "configurations": [ - // CLI - // get { - "name": "neva get github.com/nevalang/x", + "name": "GET", "type": "go", "request": "launch", "mode": "auto", @@ -12,7 +10,6 @@ "cwd": "${workspaceFolder}/examples", "args": ["get", "github.com/nevalang/x"] }, - // run (examples) { "name": "RUN", "type": "go", @@ -22,7 +19,6 @@ "cwd": "${workspaceFolder}/examples", "args": ["run", "struct_selector"] }, - // === LSP === { "name": "LSP", "type": "go", @@ -32,259 +28,8 @@ "cwd": "${workspaceFolder}", "args": ["-debug"] }, - // === ANTLR === { - "name": "antlr_000_empty.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/000_empty.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_001_newline.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/001_newline.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_002_comments.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/002_comments.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_003_use.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/003_use.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_004_type.simple.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/004_type.simple.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_005_type.args.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/005_type.args.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_006_type.enum.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/006_type.enum.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_007_type.rec.simple.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/007_type.rec.simple.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_008_type.rec.args.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/008_type.rec.args.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_009_type.rec.nested.empty.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/009_type.rec.nested.empty.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_010_type.rec.nested.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/010_type.rec.nested.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_012_type.union.simple.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/012_type.union.simple.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_013_type.union.args.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/013_type.union.args.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_014_type.complex.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/014_type.complex.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_015_interface.simple.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/015_interface.simple.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_016_interface.enums.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/016_interface.enums.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_018_interface.struct_simple.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/018_interface.struct_simple.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_019_interface.struct_nested.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/019_interface.struct_nested.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_020_interface.union.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/020_interface.union.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_021_interface.mixed.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/021_interface.mixed.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_022_interface.typeargs.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/022_interface.typeargs.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_023_const.simple.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/023_const.simple.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_024_const.mixed.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/024_const.mixed.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_025_component.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/025_component.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_026_mixed.neva", - "type": "antlr-debug", - "request": "launch", - "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/026_mixed.neva", - "grammar": "${workspaceFolder}/internal/compiler/parser/neva.g4", - "startRule": "prog", - "printParseTree": true, - "visualParseTree": true - }, - { - "name": "antlr_027_compiler_directives.neva", + "name": "ANTLR", "type": "antlr-debug", "request": "launch", "input": "${workspaceFolder}/internal/compiler/parser/tests/happypath/027_compiler_directives.neva", diff --git a/README.md b/README.md index 1331f0f3..2c68c711 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,21 @@ A general-purpose flow-based programming language with static types and implicit Website: https://nevalang.org/ +## Features 🚀 + +- **Flow-Based Programming** +- **Strong Static Typing** +- **Implicit Parallelism** +- **Compiles to Machine Code, Go and More** +- **Clean C-like Syntax** +- **Interpreter Mode** +- **First-Class Dependency Injection** +- **Builtin Observability** +- **Package Management** +- **Garbage Collection** + +Please note that even though these features are technically implemented, _developer-experience may be bad_ due to current project state. _No backward-compatibility_ guarantees at the time. + ## Quick Start ### Download Neva CLI @@ -38,28 +53,14 @@ curl -o installer.bat -sSL https://raw.githubusercontent.com/nevalang/neva/main/ ```bash neva new test -cd test -``` - -Replace the code in `src/main.neva` with the following: - -```neva -component Main(start) (stop) { - nodes { Println } - net { - :start -> ('Hello, World!' -> println -> :stop) - } -} ``` -Here we define _component_ `Main` with _inport_ `start` and _outport_ `stop`. It has 1 _node_ `println` that's an _instance_ of `Println` component. Then we define _network_ - set of connections that describe dataflow - when message from `start` received, a string literal "Hello, World!" is sent to node `println`. When that message is printed, program is terminated by sending to `stop`. +Replace the code in `cat test/src/main.neva` with the following: ### Execute -Now run (make sure you are in created `test` directory with `neva.yml`): - ```bash -neva run src +neva run test/src ``` You should see the following output: @@ -68,26 +69,25 @@ You should see the following output: Hello, World! ``` -### What's Next? +### What's inside? -- [See more examples](./examples/) -- [Learn how to generate native code, Go or other targets](https://nevalang.org/docs/quick-start) -- [Learn more about the language](https://nevalang.org/docs/about) +If you open `test/src/main.neva` with your favorite IDE you'll see this -## Features 🚀 +```neva +component Main(start) (stop) { + nodes { Println } + net { + :start -> ('Hello, World!' -> println -> :stop) + } +} +``` + +Here we define component `Main` with inport `start` and outport `stop`. It has 1 node `println` that is an instance of the `Println` component. Then we define `net` - set of connections that describe dataflow. When message from `start` received, a string literal `Hello, World!` is sent to node `println`. When that message is printed, program is terminated by sending to `stop`. -- Flow-Based Programming -- Implicit Parallelism -- Strong Static Typing -- Multi-Target Compilation -- Clean C-like Syntax -- Interpreter Mode -- Builtin Dependency Injection -- Builtin Observability -- Package Management -- Garbage Collection +### What's Next? -Please note that even though these features are technically implemented, **developer-experience may be bad** due to current project state. **No backward-compatibility** guarantees at the time. +- [Learn more about the language](https://nevalang.org/) +- [See more examples](./examples/) (`git clone` this repo and `neva run` them!) ## Roadmap (🚧 WIP) @@ -96,15 +96,15 @@ Nevalang is at an extremely early stage but with the help of community it can be - Building a Community - Core Standard Library - Feature-Rich LSP-compatible Language Server -- Go Interop (import go from neva and neva from go) +- **Go Interop** (import go from neva and neva from go) - DAP-compatible Debugger - Testing Framework - No Runtime Exceptions (If it runs then it works) -- Visual Programming in VSCode (Nevalang becomes hybrid langauge) +- **Visual Programming** in VSCode (Nevalang becomes hybrid langauge) [See backlog for more details](https://github.com/orgs/nevalang/projects) -Nevalang needs your help - it currently just a few maintainers. +Nevalang needs _your_ help - it currently just a few maintainers. ## Community @@ -123,4 +123,4 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) and [ARCHITECTURE.md](./ARCHITECTURE.md Neva is a relatively small and simple language. Don't be intimidated, feel free to dive in and hack around. Some directories have a `README.md`. -Note that, due to the early stage of development, the documentation can sometimes be outdated. Feel free to reach maintainers if you need _any_ help. \ No newline at end of file +Note that, due to the early stage of development, the documentation can sometimes be outdated. Feel free to reach maintainers if you need _any_ help. diff --git a/examples/struct_selector/main.neva b/examples/struct_selector/main.neva index 2e537ea1..0d0030f7 100644 --- a/examples/struct_selector/main.neva +++ b/examples/struct_selector/main.neva @@ -7,11 +7,10 @@ type { } component Main(start) (stop) { - nodes { UserSender, Println } + nodes { GetUser, Println } net { - :start -> userSender - userSender.pet.name -> println:data // https://github.com/nevalang/neva/issues/558 - println -> :stop + :start -> getUser + getUser.pet.name -> println -> :stop } } @@ -20,6 +19,6 @@ const user User = { pet: { name: 'Charley' } } -component UserSender(sig) (u User) { +component GetUser(sig) (u User) { :sig -> ($user -> :u) } \ No newline at end of file diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 1fbe6516..b9e67e8d 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -188,15 +188,12 @@ func createNevaMod(path string) error { } // Create main.neva file - mainNevaContent := `component Main(start any) (stop any) { - nodes { - - } + mainNevaContent := `component Main(start) (stop) { + nodes { Println } net { - :start -> :stop + :start -> ('Hello, World!' -> println -> :stop) } -} -` +}` if err := os.WriteFile( filepath.Join(srcPath, "main.neva"), diff --git a/internal/compiler/analyzer/component_net.go b/internal/compiler/analyzer/component_net.go index 91d1f45a..a12cb9cd 100644 --- a/internal/compiler/analyzer/component_net.go +++ b/internal/compiler/analyzer/component_net.go @@ -68,6 +68,7 @@ func (a Analyzer) analyzeConnections( if err != nil { return nil, err } + resolvedNet = append(resolvedNet, resolvedConn) } diff --git a/internal/compiler/compiler.go b/internal/compiler/compiler.go index 3edc3637..18ba2b94 100644 --- a/internal/compiler/compiler.go +++ b/internal/compiler/compiler.go @@ -31,7 +31,10 @@ func (c Compiler) Compile( return c.backend.Emit(dstPath, ir) } -func (c Compiler) CompileToIR(whereCLIExecuted string, whereEntryPkg string) (*ir.Program, *Error) { +func (c Compiler) CompileToIR( + whereCLIExecuted string, + whereEntryPkg string, +) (*ir.Program, *Error) { rawBuild, err := c.builder.Build( context.Background(), whereEntryPkg, diff --git a/internal/compiler/desugarer/network.go b/internal/compiler/desugarer/network.go index 1e0b8238..3384785c 100644 --- a/internal/compiler/desugarer/network.go +++ b/internal/compiler/desugarer/network.go @@ -3,10 +3,10 @@ package desugarer import ( "errors" "maps" + "slices" "github.com/nevalang/neva/internal/compiler" src "github.com/nevalang/neva/internal/compiler/sourcecode" - "github.com/nevalang/neva/internal/compiler/sourcecode/core" ) type handleNetResult struct { @@ -21,10 +21,10 @@ func (d Desugarer) handleNetwork( nodes map[string]src.Node, scope src.Scope, ) (handleNetResult, *compiler.Error) { - nodesToInsert := map[string]src.Node{} desugaredConns := make([]src.Connection, 0, len(net)) + nodesToInsert := map[string]src.Node{} + constsToInsert := map[string]src.Const{} usedNodePorts := newNodePortsMap() - constantsToInsert := map[string]src.Const{} for _, conn := range net { if conn.ArrayBypass != nil { @@ -41,31 +41,36 @@ func (d Desugarer) handleNetwork( } if conn.Normal.SenderSide.PortAddr != nil { - if conn.Normal.SenderSide.PortAddr.Port == "" { // if port is not specified, use first available - io, err := getNodeIOByPortAddr(scope, nodes, conn.Normal.SenderSide.PortAddr) - if err != nil { - return handleNetResult{}, err + if conn.Normal.SenderSide.PortAddr.Port != "" { + usedNodePorts.set( + conn.Normal.SenderSide.PortAddr.Node, + conn.Normal.SenderSide.PortAddr.Port, + ) + continue + } + + found, err := getFirstOutPortName(scope, nodes, *conn.Normal.SenderSide.PortAddr) + if err != nil { + return handleNetResult{}, &compiler.Error{ + Err: err, } - for outport := range io.Out { - conn = src.Connection{ - Normal: &src.NormalConnection{ - SenderSide: src.ConnectionSenderSide{ - PortAddr: &src.PortAddr{ - Node: conn.Normal.SenderSide.PortAddr.Node, - Port: outport, // <- substituted - Idx: conn.Normal.SenderSide.PortAddr.Idx, - Meta: core.Meta{}, - }, - Selectors: conn.Normal.SenderSide.Selectors, - Meta: conn.Normal.SenderSide.Meta, - }, - ReceiverSide: conn.Normal.ReceiverSide, + } + + conn = src.Connection{ + Normal: &src.NormalConnection{ + SenderSide: src.ConnectionSenderSide{ + PortAddr: &src.PortAddr{ + Port: found, + Node: conn.Normal.SenderSide.PortAddr.Node, + Idx: conn.Normal.SenderSide.PortAddr.Idx, + Meta: conn.Normal.SenderSide.PortAddr.Meta, }, - Meta: conn.Meta, - } - conn.Normal.SenderSide.PortAddr.Port = outport - break - } + Selectors: conn.Normal.SenderSide.Selectors, + Meta: conn.Normal.SenderSide.Meta, + }, + ReceiverSide: conn.Normal.ReceiverSide, + }, + Meta: conn.Meta, } usedNodePorts.set( @@ -74,7 +79,6 @@ func (d Desugarer) handleNetwork( ) } - // TODO possible option is to check whether we do not need to desugar anything here if len(conn.Normal.SenderSide.Selectors) != 0 { result, err := d.desugarStructSelectors(*conn.Normal) if err != nil { @@ -85,12 +89,14 @@ func (d Desugarer) handleNetwork( }.Wrap(err) } nodesToInsert[result.nodeToInsertName] = result.nodeToInsert - constantsToInsert[result.constToInsertName] = result.constToInsert + constsToInsert[result.constToInsertName] = result.constToInsert conn = result.connToReplace + + // FIXME result.connToInsert needs desugaring itself! Because of portless conn desugaredConns = append(desugaredConns, result.connToInsert) } - if conn.Normal.SenderSide.Const != nil { //nolint:nestif + if conn.Normal.SenderSide.Const != nil { if conn.Normal.SenderSide.Const.Ref != nil { result, err := d.handleConstRefSender(conn, scope) if err != nil { @@ -103,29 +109,49 @@ func (d Desugarer) handleNetwork( if err != nil { return handleNetResult{}, err } - constantsToInsert[result.constName] = *conn.Normal.SenderSide.Const + constsToInsert[result.constName] = *conn.Normal.SenderSide.Const nodesToInsert[result.emitterNodeName] = result.emitterNode conn = result.connectionWithoutConstSender } } if len(conn.Normal.ReceiverSide.DeferredConnections) == 0 { + desugaredReceivers := slices.Clone(conn.Normal.ReceiverSide.Receivers) + for i, receiver := range conn.Normal.ReceiverSide.Receivers { - if receiver.PortAddr.Port == "" { - io, err := getNodeIOByPortAddr(scope, nodes, &receiver.PortAddr) - if err != nil { - return handleNetResult{}, err - } - for inport := range io.In { - receiver.PortAddr.Port = inport - break - } - conn.Normal.ReceiverSide.Receivers[i].PortAddr.Port = receiver.PortAddr.Port // <- substituted (mutation) + if receiver.PortAddr.Port != "" { + usedNodePorts.set(receiver.PortAddr.Node, receiver.PortAddr.Port) + continue + } + + found, err := getFirstInPortName(scope, nodes, receiver.PortAddr) + if err != nil { + return handleNetResult{}, &compiler.Error{Err: err} + } + + desugaredReceivers[i] = src.ConnectionReceiver{ + PortAddr: src.PortAddr{ + Port: found, + Node: receiver.PortAddr.Node, + Idx: receiver.PortAddr.Idx, + Meta: receiver.PortAddr.Meta, + }, + Meta: receiver.Meta, } usedNodePorts.set(receiver.PortAddr.Node, receiver.PortAddr.Port) } + conn = src.Connection{ + Normal: &src.NormalConnection{ + SenderSide: conn.Normal.SenderSide, + ReceiverSide: src.ConnectionReceiverSide{ + Receivers: desugaredReceivers, + }, + }, + Meta: conn.Meta, + } + desugaredConns = append(desugaredConns, conn) continue } @@ -140,7 +166,7 @@ func (d Desugarer) handleNetwork( } maps.Copy(usedNodePorts.m, deferredConnsResult.usedNodesPorts.m) - maps.Copy(constantsToInsert, deferredConnsResult.virtualConstants) + maps.Copy(constsToInsert, deferredConnsResult.virtualConstants) maps.Copy(nodesToInsert, deferredConnsResult.virtualNodes) desugaredConns = append( @@ -152,7 +178,7 @@ func (d Desugarer) handleNetwork( return handleNetResult{ desugaredConnections: desugaredConns, usedNodePorts: usedNodePorts, - virtualConstants: constantsToInsert, + virtualConstants: constsToInsert, virtualNodes: nodesToInsert, }, nil } @@ -180,3 +206,25 @@ func getNodeIOByPortAddr( return iface.IO, nil } + +func getFirstInPortName(scope src.Scope, nodes map[string]src.Node, portAddr src.PortAddr) (string, error) { + io, err := getNodeIOByPortAddr(scope, nodes, &portAddr) + if err != nil { + return "", err + } + for inport := range io.In { + return inport, nil + } + return "", errors.New("first inport not found") +} + +func getFirstOutPortName(scope src.Scope, nodes map[string]src.Node, portAddr src.PortAddr) (string, error) { + io, err := getNodeIOByPortAddr(scope, nodes, &portAddr) + if err != nil { + return "", err + } + for outport := range io.Out { + return outport, nil + } + return "", errors.New("first outport not found") +} From 1c4e705ac6bcc5488675058ff66e58f2a266a06d Mon Sep 17 00:00:00 2001 From: Emil Valeev Date: Thu, 25 Apr 2024 18:15:11 +0500 Subject: [PATCH 2/5] wip --- internal/compiler/desugarer/network.go | 248 ++++++++++++++----------- 1 file changed, 140 insertions(+), 108 deletions(-) diff --git a/internal/compiler/desugarer/network.go b/internal/compiler/desugarer/network.go index 3384785c..cb6a7a41 100644 --- a/internal/compiler/desugarer/network.go +++ b/internal/compiler/desugarer/network.go @@ -27,33 +27,59 @@ func (d Desugarer) handleNetwork( usedNodePorts := newNodePortsMap() for _, conn := range net { - if conn.ArrayBypass != nil { - usedNodePorts.set( - conn.ArrayBypass.SenderOutport.Node, - conn.ArrayBypass.SenderOutport.Port, - ) - usedNodePorts.set( - conn.ArrayBypass.ReceiverInport.Node, - conn.ArrayBypass.ReceiverInport.Port, - ) - desugaredConns = append(desugaredConns, conn) - continue + newDesugaredConns, err := d.desugarConn( + conn, + usedNodePorts, + scope, + nodes, + nodesToInsert, + constsToInsert, + ) + if err != nil { + return handleNetResult{}, err } - if conn.Normal.SenderSide.PortAddr != nil { - if conn.Normal.SenderSide.PortAddr.Port != "" { - usedNodePorts.set( - conn.Normal.SenderSide.PortAddr.Node, - conn.Normal.SenderSide.PortAddr.Port, - ) - continue - } + desugaredConns = append(desugaredConns, newDesugaredConns...) + } + + return handleNetResult{ + desugaredConnections: desugaredConns, + usedNodePorts: usedNodePorts, + virtualConstants: constsToInsert, + virtualNodes: nodesToInsert, + }, nil +} +// desugarConn modifies given nodesToInsert, constsToInsert and usedNodePorts +// and returns list of connections to append as a result of desugaring of one connection. +func (d Desugarer) desugarConn( + conn src.Connection, + usedNodePorts nodePortsMap, + scope src.Scope, + nodes map[string]src.Node, + nodesToInsert map[string]src.Node, + constsToInsert map[string]src.Const, +) ([]src.Connection, *compiler.Error) { + // array bypass connection - nothing to desugar, just mark as used and return as-is + if conn.ArrayBypass != nil { + usedNodePorts.set( + conn.ArrayBypass.SenderOutport.Node, + conn.ArrayBypass.SenderOutport.Port, + ) + usedNodePorts.set( + conn.ArrayBypass.ReceiverInport.Node, + conn.ArrayBypass.ReceiverInport.Port, + ) + return []src.Connection{conn}, nil + } + + // normal connection with port address sender + if conn.Normal.SenderSide.PortAddr != nil { + // if port is unknown, find first and use it instead + if conn.Normal.SenderSide.PortAddr.Port == "" { found, err := getFirstOutPortName(scope, nodes, *conn.Normal.SenderSide.PortAddr) if err != nil { - return handleNetResult{}, &compiler.Error{ - Err: err, - } + return nil, &compiler.Error{Err: err} } conn = src.Connection{ @@ -72,115 +98,121 @@ func (d Desugarer) handleNetwork( }, Meta: conn.Meta, } + } - usedNodePorts.set( - conn.Normal.SenderSide.PortAddr.Node, - conn.Normal.SenderSide.PortAddr.Port, - ) + // mark as used + usedNodePorts.set( + conn.Normal.SenderSide.PortAddr.Node, + conn.Normal.SenderSide.PortAddr.Port, + ) + } + + // from this point it's possible that we return more than one connection + connsToReturn := []src.Connection{} + + if len(conn.Normal.SenderSide.Selectors) != 0 { + result, err := d.desugarStructSelectors(*conn.Normal) + if err != nil { + return nil, compiler.Error{ + Err: errors.New("Cannot desugar struct selectors"), + Location: &scope.Location, + Meta: &conn.Meta, + }.Wrap(err) } - if len(conn.Normal.SenderSide.Selectors) != 0 { - result, err := d.desugarStructSelectors(*conn.Normal) - if err != nil { - return handleNetResult{}, compiler.Error{ - Err: errors.New("Cannot desugar struct selectors"), - Location: &scope.Location, - Meta: &conn.Meta, - }.Wrap(err) - } - nodesToInsert[result.nodeToInsertName] = result.nodeToInsert - constsToInsert[result.constToInsertName] = result.constToInsert - conn = result.connToReplace + nodesToInsert[result.nodeToInsertName] = result.nodeToInsert + constsToInsert[result.constToInsertName] = result.constToInsert + connsToReturn = append(connsToReturn, result.connToInsert) - // FIXME result.connToInsert needs desugaring itself! Because of portless conn - desugaredConns = append(desugaredConns, result.connToInsert) + replacedConnDesugarRes, err := d.desugarConn(result.connToReplace, usedNodePorts, scope, nodes, nodesToInsert, constsToInsert) + if err != nil { + return nil, err } - if conn.Normal.SenderSide.Const != nil { - if conn.Normal.SenderSide.Const.Ref != nil { - result, err := d.handleConstRefSender(conn, scope) - if err != nil { - return handleNetResult{}, err - } - nodesToInsert[result.emitterNodeName] = result.emitterNode - conn = result.connectionWithoutConstSender - } else if conn.Normal.SenderSide.Const.Message != nil { - result, err := d.handleLiteralSender(conn) - if err != nil { - return handleNetResult{}, err - } - constsToInsert[result.constName] = *conn.Normal.SenderSide.Const - nodesToInsert[result.emitterNodeName] = result.emitterNode - conn = result.connectionWithoutConstSender + // FIXME instead of replacing conn we append it + // but the execution of this function is continuing + // so we end up with duplicate/incorrect version + connsToReturn = append(connsToReturn, replacedConnDesugarRes...) + } + + if conn.Normal.SenderSide.Const != nil { + if conn.Normal.SenderSide.Const.Ref != nil { + result, err := d.handleConstRefSender(conn, scope) + if err != nil { + return nil, err + } + nodesToInsert[result.emitterNodeName] = result.emitterNode + conn = result.connectionWithoutConstSender + } else if conn.Normal.SenderSide.Const.Message != nil { + result, err := d.handleLiteralSender(conn) + if err != nil { + return nil, err } + constsToInsert[result.constName] = *conn.Normal.SenderSide.Const + nodesToInsert[result.emitterNodeName] = result.emitterNode + conn = result.connectionWithoutConstSender } + } - if len(conn.Normal.ReceiverSide.DeferredConnections) == 0 { - desugaredReceivers := slices.Clone(conn.Normal.ReceiverSide.Receivers) - - for i, receiver := range conn.Normal.ReceiverSide.Receivers { - if receiver.PortAddr.Port != "" { - usedNodePorts.set(receiver.PortAddr.Node, receiver.PortAddr.Port) - continue - } - - found, err := getFirstInPortName(scope, nodes, receiver.PortAddr) - if err != nil { - return handleNetResult{}, &compiler.Error{Err: err} - } - - desugaredReceivers[i] = src.ConnectionReceiver{ - PortAddr: src.PortAddr{ - Port: found, - Node: receiver.PortAddr.Node, - Idx: receiver.PortAddr.Idx, - Meta: receiver.PortAddr.Meta, - }, - Meta: receiver.Meta, - } + if len(conn.Normal.ReceiverSide.DeferredConnections) == 0 { + desugaredReceivers := slices.Clone(conn.Normal.ReceiverSide.Receivers) + for i, receiver := range conn.Normal.ReceiverSide.Receivers { + if receiver.PortAddr.Port != "" { usedNodePorts.set(receiver.PortAddr.Node, receiver.PortAddr.Port) + continue } - conn = src.Connection{ - Normal: &src.NormalConnection{ - SenderSide: conn.Normal.SenderSide, - ReceiverSide: src.ConnectionReceiverSide{ - Receivers: desugaredReceivers, - }, + found, err := getFirstInPortName(scope, nodes, receiver.PortAddr) + if err != nil { + return nil, &compiler.Error{Err: err} + } + + desugaredReceivers[i] = src.ConnectionReceiver{ + PortAddr: src.PortAddr{ + Port: found, + Node: receiver.PortAddr.Node, + Idx: receiver.PortAddr.Idx, + Meta: receiver.PortAddr.Meta, }, - Meta: conn.Meta, + Meta: receiver.Meta, } - desugaredConns = append(desugaredConns, conn) - continue + usedNodePorts.set(receiver.PortAddr.Node, receiver.PortAddr.Port) } - deferredConnsResult, err := d.handleDeferredConnections( - *conn.Normal, - nodes, - scope, - ) - if err != nil { - return handleNetResult{}, err + conn = src.Connection{ + Normal: &src.NormalConnection{ + SenderSide: conn.Normal.SenderSide, + ReceiverSide: src.ConnectionReceiverSide{ + Receivers: desugaredReceivers, + }, + }, + Meta: conn.Meta, } - maps.Copy(usedNodePorts.m, deferredConnsResult.usedNodesPorts.m) - maps.Copy(constsToInsert, deferredConnsResult.virtualConstants) - maps.Copy(nodesToInsert, deferredConnsResult.virtualNodes) + desugaredConns = append(desugaredConns, conn) + continue + } - desugaredConns = append( - desugaredConns, - deferredConnsResult.desugaredConnections..., - ) + deferredConnsResult, err := d.handleDeferredConnections( + *conn.Normal, + nodes, + scope, + ) + if err != nil { + return nil, true, handleNetResult{}, err } - return handleNetResult{ - desugaredConnections: desugaredConns, - usedNodePorts: usedNodePorts, - virtualConstants: constsToInsert, - virtualNodes: nodesToInsert, - }, nil + maps.Copy(usedNodePorts.m, deferredConnsResult.usedNodesPorts.m) + maps.Copy(constsToInsert, deferredConnsResult.virtualConstants) + maps.Copy(nodesToInsert, deferredConnsResult.virtualNodes) + + desugaredConns = append( + desugaredConns, + deferredConnsResult.desugaredConnections..., + ) + return desugaredConns, false, handleNetResult{}, nil } func getNodeIOByPortAddr( From 7611e1bae703ef300bb254f317a915f92cefa01b Mon Sep 17 00:00:00 2001 From: Emil Valeev Date: Sun, 28 Apr 2024 13:28:45 +0500 Subject: [PATCH 3/5] fix(desugarer): refactor network desugaring and correctly handle struct selectors --- internal/compiler/desugarer/const_sender.go | 18 ++-- .../compiler/desugarer/defer_connections.go | 33 +++--- internal/compiler/desugarer/network.go | 100 ++++++++++-------- 3 files changed, 83 insertions(+), 68 deletions(-) diff --git a/internal/compiler/desugarer/const_sender.go b/internal/compiler/desugarer/const_sender.go index afa91caa..8bacfbf1 100644 --- a/internal/compiler/desugarer/const_sender.go +++ b/internal/compiler/desugarer/const_sender.go @@ -21,9 +21,9 @@ type handleLiteralSenderResult struct { } type handleConstRefSenderResult struct { - connectionWithoutConstSender src.Connection - emitterNodeName string - emitterNode src.Node + connToReplace src.Connection // connection without const sender + nodeToInsertName string // name of emitter node + nodeToInsert src.Node // emitter node } // In the future compiler can operate in concurrently @@ -71,7 +71,7 @@ func (d Desugarer) handleLiteralSender( return handleLiteralSenderResult{ constName: constName, handleConstRefSenderResult: handleConstRefSenderResult{ - connectionWithoutConstSender: src.Connection{ + connToReplace: src.Connection{ Normal: &src.NormalConnection{ SenderSide: src.ConnectionSenderSide{ PortAddr: &emitterNodeOutportAddr, @@ -82,8 +82,8 @@ func (d Desugarer) handleLiteralSender( }, Meta: conn.Meta, }, - emitterNodeName: emitterNodeName, - emitterNode: emitterNode, + nodeToInsertName: emitterNodeName, + nodeToInsert: emitterNode, }, }, nil } @@ -126,7 +126,7 @@ func (d Desugarer) handleConstRefSender( } return handleConstRefSenderResult{ - connectionWithoutConstSender: src.Connection{ + connToReplace: src.Connection{ Normal: &src.NormalConnection{ SenderSide: src.ConnectionSenderSide{ PortAddr: &emitterNodeOutportAddr, @@ -137,8 +137,8 @@ func (d Desugarer) handleConstRefSender( }, Meta: conn.Meta, }, - emitterNodeName: virtualEmitterName, - emitterNode: emitterNode, + nodeToInsertName: virtualEmitterName, + nodeToInsert: emitterNode, }, nil } diff --git a/internal/compiler/desugarer/defer_connections.go b/internal/compiler/desugarer/defer_connections.go index 276be761..8fc9849c 100644 --- a/internal/compiler/desugarer/defer_connections.go +++ b/internal/compiler/desugarer/defer_connections.go @@ -27,10 +27,11 @@ var virtualBlockerNode = src.Node{ } type handleThenConnectionsResult struct { - desugaredConnections []src.Connection // these replaces original deferred connections - virtualConstants map[string]src.Const - virtualNodes map[string]src.Node - usedNodesPorts nodePortsMap + connsToInsert []src.Connection + connToReplace src.Connection + constsToInsert map[string]src.Const + nodesToInsert map[string]src.Node + nodesPortsUsed nodePortsMap // (probably?) to generate "Del" instances where needed } var virtualBlockersCounter atomic.Uint64 @@ -132,22 +133,20 @@ func (d Desugarer) handleDeferredConnections( //nolint:funlen ) // don't forget to append first connection - virtualConns = append( - virtualConns, - src.Connection{ - Normal: &src.NormalConnection{ - SenderSide: originalSender, - ReceiverSide: src.ConnectionReceiverSide{ - Receivers: receiversForOriginalSender, - }, + connToReplace := src.Connection{ + Normal: &src.NormalConnection{ + SenderSide: originalSender, + ReceiverSide: src.ConnectionReceiverSide{ + Receivers: receiversForOriginalSender, }, }, - ) + } return handleThenConnectionsResult{ - virtualNodes: virtualNodes, - desugaredConnections: virtualConns, - virtualConstants: handleNetResult.virtualConstants, - usedNodesPorts: handleNetResult.usedNodePorts, + nodesToInsert: virtualNodes, + connsToInsert: virtualConns, + constsToInsert: handleNetResult.virtualConstants, + nodesPortsUsed: handleNetResult.usedNodePorts, + connToReplace: connToReplace, }, nil } diff --git a/internal/compiler/desugarer/network.go b/internal/compiler/desugarer/network.go index cb6a7a41..d1b0604f 100644 --- a/internal/compiler/desugarer/network.go +++ b/internal/compiler/desugarer/network.go @@ -27,7 +27,7 @@ func (d Desugarer) handleNetwork( usedNodePorts := newNodePortsMap() for _, conn := range net { - newDesugaredConns, err := d.desugarConn( + result, err := d.desugarConn( conn, usedNodePorts, scope, @@ -39,7 +39,8 @@ func (d Desugarer) handleNetwork( return handleNetResult{}, err } - desugaredConns = append(desugaredConns, newDesugaredConns...) + desugaredConns = append(desugaredConns, result.connToReplace) + desugaredConns = append(desugaredConns, result.connsToInsert...) } return handleNetResult{ @@ -50,8 +51,14 @@ func (d Desugarer) handleNetwork( }, nil } +type desugarConnResult struct { + connToReplace src.Connection + connsToInsert []src.Connection +} + // desugarConn modifies given nodesToInsert, constsToInsert and usedNodePorts -// and returns list of connections to append as a result of desugaring of one connection. +// it also returns connection to replace the original one and other connections +// that were generated while desugared the original one. func (d Desugarer) desugarConn( conn src.Connection, usedNodePorts nodePortsMap, @@ -59,7 +66,7 @@ func (d Desugarer) desugarConn( nodes map[string]src.Node, nodesToInsert map[string]src.Node, constsToInsert map[string]src.Const, -) ([]src.Connection, *compiler.Error) { +) (desugarConnResult, *compiler.Error) { // array bypass connection - nothing to desugar, just mark as used and return as-is if conn.ArrayBypass != nil { usedNodePorts.set( @@ -70,7 +77,9 @@ func (d Desugarer) desugarConn( conn.ArrayBypass.ReceiverInport.Node, conn.ArrayBypass.ReceiverInport.Port, ) - return []src.Connection{conn}, nil + return desugarConnResult{ + connToReplace: conn, + }, nil } // normal connection with port address sender @@ -79,7 +88,7 @@ func (d Desugarer) desugarConn( if conn.Normal.SenderSide.PortAddr.Port == "" { found, err := getFirstOutPortName(scope, nodes, *conn.Normal.SenderSide.PortAddr) if err != nil { - return nil, &compiler.Error{Err: err} + return desugarConnResult{}, &compiler.Error{Err: err} } conn = src.Connection{ @@ -107,13 +116,13 @@ func (d Desugarer) desugarConn( ) } - // from this point it's possible that we return more than one connection - connsToReturn := []src.Connection{} + connsToInsert := []src.Connection{} + // if conn has selectors, desugar it, then replace it and insert generated ones if len(conn.Normal.SenderSide.Selectors) != 0 { result, err := d.desugarStructSelectors(*conn.Normal) if err != nil { - return nil, compiler.Error{ + return desugarConnResult{}, compiler.Error{ Err: errors.New("Cannot desugar struct selectors"), Location: &scope.Location, Meta: &conn.Meta, @@ -122,38 +131,44 @@ func (d Desugarer) desugarConn( nodesToInsert[result.nodeToInsertName] = result.nodeToInsert constsToInsert[result.constToInsertName] = result.constToInsert - connsToReturn = append(connsToReturn, result.connToInsert) - replacedConnDesugarRes, err := d.desugarConn(result.connToReplace, usedNodePorts, scope, nodes, nodesToInsert, constsToInsert) + replacedConnDesugarRes, err := d.desugarConn( + result.connToReplace, + usedNodePorts, + scope, + nodes, + nodesToInsert, + constsToInsert, + ) if err != nil { - return nil, err + return desugarConnResult{}, err } - // FIXME instead of replacing conn we append it - // but the execution of this function is continuing - // so we end up with duplicate/incorrect version - connsToReturn = append(connsToReturn, replacedConnDesugarRes...) + conn = replacedConnDesugarRes.connToReplace + connsToInsert = append(connsToInsert, result.connToInsert) } + // if sender is const or literal, replace it with desugared and insert const/node for emitter if conn.Normal.SenderSide.Const != nil { if conn.Normal.SenderSide.Const.Ref != nil { result, err := d.handleConstRefSender(conn, scope) if err != nil { - return nil, err + return desugarConnResult{}, err } - nodesToInsert[result.emitterNodeName] = result.emitterNode - conn = result.connectionWithoutConstSender + nodesToInsert[result.nodeToInsertName] = result.nodeToInsert + conn = result.connToReplace } else if conn.Normal.SenderSide.Const.Message != nil { result, err := d.handleLiteralSender(conn) if err != nil { - return nil, err + return desugarConnResult{}, err } constsToInsert[result.constName] = *conn.Normal.SenderSide.Const - nodesToInsert[result.emitterNodeName] = result.emitterNode - conn = result.connectionWithoutConstSender + nodesToInsert[result.nodeToInsertName] = result.nodeToInsert + conn = result.connToReplace } } + // if there's no deferred connections, then desugar empty port receivers and that's it if len(conn.Normal.ReceiverSide.DeferredConnections) == 0 { desugaredReceivers := slices.Clone(conn.Normal.ReceiverSide.Receivers) @@ -165,7 +180,7 @@ func (d Desugarer) desugarConn( found, err := getFirstInPortName(scope, nodes, receiver.PortAddr) if err != nil { - return nil, &compiler.Error{Err: err} + return desugarConnResult{}, &compiler.Error{Err: err} } desugaredReceivers[i] = src.ConnectionReceiver{ @@ -181,38 +196,39 @@ func (d Desugarer) desugarConn( usedNodePorts.set(receiver.PortAddr.Node, receiver.PortAddr.Port) } - conn = src.Connection{ - Normal: &src.NormalConnection{ - SenderSide: conn.Normal.SenderSide, - ReceiverSide: src.ConnectionReceiverSide{ - Receivers: desugaredReceivers, + return desugarConnResult{ + connToReplace: src.Connection{ + Normal: &src.NormalConnection{ + SenderSide: conn.Normal.SenderSide, + ReceiverSide: src.ConnectionReceiverSide{ + Receivers: desugaredReceivers, + }, }, + Meta: conn.Meta, }, - Meta: conn.Meta, - } - - desugaredConns = append(desugaredConns, conn) - continue + connsToInsert: connsToInsert, + }, nil } + // if there's desugared connections, desugar them, + // insert what's needed and replace original connection deferredConnsResult, err := d.handleDeferredConnections( *conn.Normal, nodes, scope, ) if err != nil { - return nil, true, handleNetResult{}, err + return desugarConnResult{}, err } - maps.Copy(usedNodePorts.m, deferredConnsResult.usedNodesPorts.m) - maps.Copy(constsToInsert, deferredConnsResult.virtualConstants) - maps.Copy(nodesToInsert, deferredConnsResult.virtualNodes) + maps.Copy(usedNodePorts.m, deferredConnsResult.nodesPortsUsed.m) + maps.Copy(constsToInsert, deferredConnsResult.constsToInsert) + maps.Copy(nodesToInsert, deferredConnsResult.nodesToInsert) - desugaredConns = append( - desugaredConns, - deferredConnsResult.desugaredConnections..., - ) - return desugaredConns, false, handleNetResult{}, nil + return desugarConnResult{ + connToReplace: deferredConnsResult.connToReplace, + connsToInsert: deferredConnsResult.connsToInsert, + }, nil } func getNodeIOByPortAddr( From 0213026c8b3c7295c099a624b3dcf527bc3dd514 Mon Sep 17 00:00:00 2001 From: Emil Valeev Date: Sun, 28 Apr 2024 14:04:55 +0500 Subject: [PATCH 4/5] fix,refactor(builder,examples,std): add hack to builder to erase std before each run, fix list iter example to avoid unpredictable order, refactor Iter component to use standard naming for ports --- examples/iterate_over_list/e2e_test.go | 2 +- examples/iterate_over_list/main.neva | 18 +++++------------- internal/builder/builder.go | 23 +++++++++++++++-------- internal/runtime/funcs/list_iter.go | 12 +++++++----- std/builtin/collections.neva | 2 +- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/examples/iterate_over_list/e2e_test.go b/examples/iterate_over_list/e2e_test.go index 8952a262..05862cea 100644 --- a/examples/iterate_over_list/e2e_test.go +++ b/examples/iterate_over_list/e2e_test.go @@ -22,7 +22,7 @@ func Test(t *testing.T) { require.NoError(t, err) require.Equal( t, - "50\n30\n20\n100\n", + "50\n30\n20\n100\n\n", string(out), ) diff --git a/examples/iterate_over_list/main.neva b/examples/iterate_over_list/main.neva index a5523e0c..c0ca4534 100644 --- a/examples/iterate_over_list/main.neva +++ b/examples/iterate_over_list/main.neva @@ -1,17 +1,9 @@ -const l list = [50, 30, 20, 100] +const lst list = [50, 30, 20, 100] -component Main(start any) (stop any) { - nodes { - print Println - iter Iter - unw Unwrap - del Del - } +component Main(start) (stop) { + nodes { Println>, Iter, Unwrap } net { - :start -> ($l -> iter:lst) - iter:res -> unw:data - unw:some -> print:data - print:sig -> del:msg - unw:none -> :stop + :start -> ($lst -> iter -> println -> unwrap) + unwrap:none -> :stop } } \ No newline at end of file diff --git a/internal/builder/builder.go b/internal/builder/builder.go index 876eef27..cad3eed5 100644 --- a/internal/builder/builder.go +++ b/internal/builder/builder.go @@ -122,7 +122,8 @@ func getThirdPartyPath() (string, error) { return path, nil } -func getStdlibPath() (string, error) { +// rewriteStdlibOntoDisk erases stdlib on the disk if it's there and writes it again. +func rewriteStdlibOntoDisk() (string, error) { home, err := os.UserHomeDir() if err != nil { return "", err @@ -130,15 +131,21 @@ func getStdlibPath() (string, error) { path := filepath.Join(home, "neva", "std") - _, err = os.Stat(path) - if err == nil { - return path, nil - } - - if !os.IsNotExist(err) { + // TODO replace this dirty hack with good solution of https://github.com/nevalang/neva/issues/563 + err = os.RemoveAll(path) + if err != nil { return "", err } + // _, err = os.Stat(path) + // if err == nil { + // return path, nil + // } + + // if !os.IsNotExist(err) { + // return "", err + // } + // Inject missing stdlib files into user's home directory stdFS := std.FS err = fs.WalkDir(stdFS, ".", func(path string, d fs.DirEntry, err error) error { @@ -179,7 +186,7 @@ func New(parser ManifestParser) (Builder, error) { return Builder{}, err } - stdlibPath, err := getStdlibPath() + stdlibPath, err := rewriteStdlibOntoDisk() if err != nil { return Builder{}, err } diff --git a/internal/runtime/funcs/list_iter.go b/internal/runtime/funcs/list_iter.go index b095df65..4a8820c1 100644 --- a/internal/runtime/funcs/list_iter.go +++ b/internal/runtime/funcs/list_iter.go @@ -2,17 +2,19 @@ package funcs import ( "context" + "github.com/nevalang/neva/internal/runtime" ) type list_iter struct{} func (c list_iter) Create(io runtime.FuncIO, _ runtime.Msg) (func(ctx context.Context), error) { - lstIn, err := io.In.Port("lst") + dataIn, err := io.In.Port("data") if err != nil { return nil, err } - outport, err := io.Out.Port("res") + + seqOut, err := io.Out.Port("seq") if err != nil { return nil, err } @@ -20,7 +22,7 @@ func (c list_iter) Create(io runtime.FuncIO, _ runtime.Msg) (func(ctx context.Co return func(ctx context.Context) { for { select { - case data, ok := <-lstIn: + case data, ok := <-dataIn: if !ok { return // lstIn channel closed } @@ -28,13 +30,13 @@ func (c list_iter) Create(io runtime.FuncIO, _ runtime.Msg) (func(ctx context.Co select { case <-ctx.Done(): return - case outport <- data.List()[i]: + case seqOut <- data.List()[i]: } } select { case <-ctx.Done(): return - case outport <- nil: + case seqOut <- nil: } case <-ctx.Done(): return diff --git a/std/builtin/collections.neva b/std/builtin/collections.neva index f975c357..5b2e2674 100644 --- a/std/builtin/collections.neva +++ b/std/builtin/collections.neva @@ -33,5 +33,5 @@ component { pub Slice>(data T, from int, to int) (res T, err error) #extern(list_iter) - pub Iter (lst list) (res maybe) + pub Iter (data list) (seq maybe) } From 2a0a780f496ca455cc48f82bcd138546c58cf1b9 Mon Sep 17 00:00:00 2001 From: Emil Valeev Date: Sun, 28 Apr 2024 15:35:20 +0500 Subject: [PATCH 5/5] fix(desugarer): case with struct selectors AND portless connection --- .../e2e_test.go | 23 ++++++++++++++++ .../main/main.neva | 27 +++++++++++++++++++ e2e/struct_selector_with_more_sugar/neva.yml | 1 + examples/struct_selector/main.neva | 3 +-- internal/compiler/desugarer/network.go | 20 +++++++++++++- 5 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 e2e/struct_selector_with_more_sugar/e2e_test.go create mode 100644 e2e/struct_selector_with_more_sugar/main/main.neva create mode 100644 e2e/struct_selector_with_more_sugar/neva.yml diff --git a/e2e/struct_selector_with_more_sugar/e2e_test.go b/e2e/struct_selector_with_more_sugar/e2e_test.go new file mode 100644 index 00000000..637164ad --- /dev/null +++ b/e2e/struct_selector_with_more_sugar/e2e_test.go @@ -0,0 +1,23 @@ +package test + +import ( + "os/exec" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test(t *testing.T) { + cmd := exec.Command("neva", "run", "main") + + out, err := cmd.CombinedOutput() + require.NoError(t, err) + + require.Equal( + t, + "Charley\n", + string(out), + ) + + require.Equal(t, 0, cmd.ProcessState.ExitCode()) +} diff --git a/e2e/struct_selector_with_more_sugar/main/main.neva b/e2e/struct_selector_with_more_sugar/main/main.neva new file mode 100644 index 00000000..1c1e866c --- /dev/null +++ b/e2e/struct_selector_with_more_sugar/main/main.neva @@ -0,0 +1,27 @@ +// Here we learn how to read struct fields without compiler directives +// by using another one syntax sugare `.` called "struct selectors". + +type { + User struct { + name string + pet Pet + } + Pet struct { name string } +} + +component Main(start) (stop) { + nodes { UserSender, Println } + net { + :start -> userSender:sig + userSender.pet.name -> println -> :stop + } +} + +const user User = { + name: 'John', + pet: { name: 'Charley' } +} + +component UserSender(sig) (u User) { + :sig -> ($user -> :u) +} \ No newline at end of file diff --git a/e2e/struct_selector_with_more_sugar/neva.yml b/e2e/struct_selector_with_more_sugar/neva.yml new file mode 100644 index 00000000..56866f0d --- /dev/null +++ b/e2e/struct_selector_with_more_sugar/neva.yml @@ -0,0 +1 @@ +neva: 0.10.0 \ No newline at end of file diff --git a/examples/struct_selector/main.neva b/examples/struct_selector/main.neva index 0d0030f7..178e2b1b 100644 --- a/examples/struct_selector/main.neva +++ b/examples/struct_selector/main.neva @@ -9,8 +9,7 @@ type { component Main(start) (stop) { nodes { GetUser, Println } net { - :start -> getUser - getUser.pet.name -> println -> :stop + :start -> getUser.pet.name -> println -> :stop } } diff --git a/internal/compiler/desugarer/network.go b/internal/compiler/desugarer/network.go index d1b0604f..2e6ef5d4 100644 --- a/internal/compiler/desugarer/network.go +++ b/internal/compiler/desugarer/network.go @@ -132,6 +132,23 @@ func (d Desugarer) desugarConn( nodesToInsert[result.nodeToInsertName] = result.nodeToInsert constsToInsert[result.constToInsertName] = result.constToInsert + // generated connection might need desugaring itself + connToInsertDesugarRes, err := d.desugarConn( + result.connToInsert, + usedNodePorts, + scope, + nodes, + nodesToInsert, + constsToInsert, + ) + if err != nil { + return desugarConnResult{}, err + } + + connsToInsert = append(connsToInsert, connToInsertDesugarRes.connToReplace) + connsToInsert = append(connsToInsert, connToInsertDesugarRes.connsToInsert...) + + // connection that replaces original one might need desugaring itself replacedConnDesugarRes, err := d.desugarConn( result.connToReplace, usedNodePorts, @@ -144,8 +161,9 @@ func (d Desugarer) desugarConn( return desugarConnResult{}, err } + connsToInsert = append(connsToInsert, replacedConnDesugarRes.connsToInsert...) + conn = replacedConnDesugarRes.connToReplace - connsToInsert = append(connsToInsert, result.connToInsert) } // if sender is const or literal, replace it with desugared and insert const/node for emitter