diff --git a/AGENTS.md b/AGENTS.md index b1827cb3a..e656dd1e0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,6 +43,15 @@ Follow these instructions. - **Gotchas**: In sender position, `[...]` is parsed as fan-in (multiple senders), so list literals should not be used as senders without explicit disambiguation. - **Gotchas**: Literal senders are limited to primitives/union literals; list/dict/struct literals are rejected for now (use const refs). +### Session Notes (2026-01-27) + +- **Language semantics**: Literal senders must be in a chain triggered by a signal (e.g. `:start -> true -> ...`). +- **Language semantics**: Fan-out (`-> [...]`) can contain chained connections, but the chain head is the sender before the fan-out (e.g. `:start -> [foo, bar -> baz]`). +- **Language semantics**: `std/core.New` now requires a `sig` inport; explicit uses must be triggered (e.g. `:start -> new:sig`). +- **Common patterns**: Stdlib Switch setups should seed case values via `:start` to avoid autonomous constant senders. +- **Architecture insights**: `analyzeSender` rejects const senders when `prevChainLink` is empty (analyzer enforces the rule). +- **Gotchas**: Stdlib modules can fail compilation after analyzer rule changes; update `std/*` constants accordingly. + ## 3. ⚡ Core Concepts - **Dataflow**: Programs are graphs. Nodes process data; edges transport it. diff --git a/e2e/99_bottles_verbose/main/main.neva b/e2e/99_bottles_verbose/main/main.neva index cb0dbc2e0..509ad1225 100644 --- a/e2e/99_bottles_verbose/main/main.neva +++ b/e2e/99_bottles_verbose/main/main.neva @@ -1,36 +1,38 @@ import { - fmt - runtime + fmt + runtime } // https://www.99-bottles-of-beer.net def Main(start any) (stop any) { - // we use explicit lock to implement fan-in to printNext2Lines - s Switch - print_next_2_lines PrintNext2Lines - lock Lock - panic runtime.Panic - --- - :start -> lock:sig - 99 -> lock:data - [lock:data, s:else] -> print_next_2_lines - print_next_2_lines:n -> s:data - -1 -> s:case[0] -> :stop - print_next_2_lines:err -> panic + // we use explicit lock to implement fan-in to printNext2Lines + s Switch + print_next_2_lines PrintNext2Lines + lock Lock + panic runtime.Panic + --- + :start -> [lock:sig, 99 -> lock:data] + [lock:data, s:else] -> print_next_2_lines + print_next_2_lines:n -> [ + s:data, + -1 -> s:case[0] + ] + s:case[0] -> :stop + print_next_2_lines:err -> panic } def PrintNext2Lines(n int) (n int, err error) { - dec Dec - print_first_line PrintFirstLine? - print_second_line PrintSecondLine? - --- - // print_first_line and print_second_line won't work in parallel - // because they are in the loop at the level of Main - :n -> print_first_line:n - print_first_line:n -> dec:data - dec:res -> print_second_line:n - print_second_line:n -> :n + dec Dec + print_first_line PrintFirstLine? + print_second_line PrintSecondLine? + --- + // print_first_line and print_second_line won't work in parallel + // because they are in the loop at the level of Main + :n -> print_first_line:n + print_first_line:n -> dec:data + dec:res -> print_second_line:n + print_second_line:n -> :n } // === First Line === @@ -40,26 +42,28 @@ const firstLine2 string = '1 bottle of beer on the wall, 1 bottle of beer.' const firstLine3 string = 'No more bottles of beer on the wall, no more bottles of beer.' def PrintFirstLine(n int) (n int, err error) { - s Switch - p1 fmt.Println? - p2 fmt.Println? - printf fmt.Printf? - lock Lock - --- - :n -> [s:data, lock:data] - - 0 -> s:case[0] - 1 -> s:case[1] - s:case[0] -> $firstLine3 -> p1:data - s:case[1] -> $firstLine2 -> p2:data - - s:else -> [ - printf:args[0], - $firstLine1 -> printf:tpl - ] - - [p1:res, p2:res, printf:sig] -> lock:sig - lock:data -> :n + s Switch + p1 fmt.Println? + p2 fmt.Println? + printf fmt.Printf? + lock Lock + --- + :n -> [ + s:data, + lock:data, + 0 -> s:case[0], + 1 -> s:case[1] + ] + s:case[0] -> $firstLine3 -> p1:data + s:case[1] -> $firstLine2 -> p2:data + + s:else -> [ + printf:args[0], + $firstLine1 -> printf:tpl + ] + + [p1:res, p2:res, printf:sig] -> lock:sig + lock:data -> :n } // === Second Line === @@ -70,28 +74,30 @@ const secondLine3 string = 'Take one down and pass it around, no more bottles of const secondLine4 string = 'Go to the store and buy some more, 99 bottles of beer on the wall.' def PrintSecondLine(n int) (n int, err error) { - s Switch - p1 fmt.Println? - p2 fmt.Println? - p3 fmt.Println? - printf fmt.Printf? - lock Lock - --- - :n -> [s:data, lock:data] - - -1 -> s:case[0] - 0 -> s:case[1] - 1 -> s:case[2] - - s:case[0] -> $secondLine4 -> p1:data - s:case[1] -> $secondLine3 -> p2:data - s:case[2] -> $secondLine2 -> p3:data - - s:else -> [ - printf:args[0], - $secondLine1 -> printf:tpl - ] - - [p1:res, p2:res, p3:res, printf:sig] -> lock:sig - lock:data -> :n -} \ No newline at end of file + s Switch + p1 fmt.Println? + p2 fmt.Println? + p3 fmt.Println? + printf fmt.Printf? + lock Lock + --- + :n -> [ + s:data, + lock:data, + -1 -> s:case[0], + 0 -> s:case[1], + 1 -> s:case[2] + ] + + s:case[0] -> $secondLine4 -> p1:data + s:case[1] -> $secondLine3 -> p2:data + s:case[2] -> $secondLine2 -> p3:data + + s:else -> [ + printf:args[0], + $secondLine1 -> printf:tpl + ] + + [p1:res, p2:res, p3:res, printf:sig] -> lock:sig + lock:data -> :n +} diff --git a/e2e/array_inport_holes/main/main.neva b/e2e/array_inport_holes/main/main.neva index 63c197c9b..047c4a8c0 100644 --- a/e2e/array_inport_holes/main/main.neva +++ b/e2e/array_inport_holes/main/main.neva @@ -1,10 +1,12 @@ import { fmt } def Main(start any) (stop any) { - fmt.Printf + printf fmt.Printf --- - :start -> '$1 $2 $3' -> printf:tpl - 1 -> printf:args[0] - 3 -> printf:args[2] + :start -> [ + '$1 $2 $3' -> printf:tpl, + 1 -> printf:args[0], + 3 -> printf:args[2] + ] [printf:sig, printf:err] -> :stop } diff --git a/e2e/compare_ints/main/main.neva b/e2e/compare_ints/main/main.neva index 7d102060d..7322ff5c9 100644 --- a/e2e/compare_ints/main/main.neva +++ b/e2e/compare_ints/main/main.neva @@ -13,9 +13,11 @@ def Main(start any) (stop any) { 50 -> gt:left, 10 -> gt:right ] - gt:res -> ternary:if - 'Actual is greater' -> ternary:then - 'Actual is lower' -> ternary:else + gt:res -> [ + ternary:if, + 'Actual is greater' -> ternary:then, + 'Actual is lower' -> ternary:else + ] ternary:res -> println:data println:res -> :stop println:err -> panic diff --git a/e2e/compare_strings/main/main.neva b/e2e/compare_strings/main/main.neva index 72465f268..5e9944b3e 100644 --- a/e2e/compare_strings/main/main.neva +++ b/e2e/compare_strings/main/main.neva @@ -13,9 +13,11 @@ def Main(start any) (stop any) { 'Z' -> gt:left, 'A' -> gt:right ] - gt:res -> ternary:if - 'Actual is greater' -> ternary:then - 'Actual is lower' -> ternary:else + gt:res -> [ + ternary:if, + 'Actual is greater' -> ternary:then, + 'Actual is lower' -> ternary:else + ] ternary -> println:data println:res -> :stop println:err -> panic diff --git a/e2e/compiler_error_autonomous_const/e2e_test.go b/e2e/compiler_error_autonomous_const/e2e_test.go new file mode 100644 index 000000000..e071c7e8e --- /dev/null +++ b/e2e/compiler_error_autonomous_const/e2e_test.go @@ -0,0 +1,17 @@ +package test + +import ( + "testing" + + "github.com/nevalang/neva/pkg/e2e" + "github.com/stretchr/testify/require" +) + +func Test(t *testing.T) { + _, stderr := e2e.Run(t, []string{"run", "main"}, e2e.WithCode(1)) + require.Contains( + t, + stderr, + "Constants must be triggered by a signal (e.g. :start -> 42 -> ...)", + ) +} diff --git a/e2e/compiler_error_autonomous_const/main/main.neva b/e2e/compiler_error_autonomous_const/main/main.neva new file mode 100644 index 000000000..3dc7cf441 --- /dev/null +++ b/e2e/compiler_error_autonomous_const/main/main.neva @@ -0,0 +1,11 @@ +import { fmt } + +const myConst string = 'Hello, World!' + +def Main(start any) (stop any) { + p1 fmt.Println + p2 fmt.Println + --- + :start -> p1 + $myConst -> p2 +} diff --git a/e2e/compiler_error_autonomous_const/neva.yml b/e2e/compiler_error_autonomous_const/neva.yml new file mode 100644 index 000000000..d01518a8d --- /dev/null +++ b/e2e/compiler_error_autonomous_const/neva.yml @@ -0,0 +1 @@ +neva: 0.32.0 diff --git a/e2e/compiler_error_unused_outport/e2e_test.go b/e2e/compiler_error_unused_outport/e2e_test.go index c1a590f3c..196766606 100644 --- a/e2e/compiler_error_unused_outport/e2e_test.go +++ b/e2e/compiler_error_unused_outport/e2e_test.go @@ -12,6 +12,6 @@ func Test(t *testing.T) { require.Contains( t, stderr, - "main/main.neva:8:4: All node's outports are unused: sub2\n", + "main/main.neva:8:1: All node's outports are unused: sub2\n", ) } diff --git a/e2e/compiler_error_unused_outport/main/main.neva b/e2e/compiler_error_unused_outport/main/main.neva index d1502c1a7..fc75542c6 100644 --- a/e2e/compiler_error_unused_outport/main/main.neva +++ b/e2e/compiler_error_unused_outport/main/main.neva @@ -1,24 +1,26 @@ import { - fmt - runtime + fmt + runtime } def Main(start any) (stop any) { - sub1 SubComponent - sub2 SubComponent - --- - :start -> 'Hi, Neva!' -> sub1:data - sub1:stop-> :stop - '1' -> sub2 + sub1 SubComponent + sub2 SubComponent + --- + :start -> [ + 'Hi, Neva!' -> sub1, + '1' -> sub2 + ] + sub1 -> :stop } // Here we are panicking inside the sub-component instead of propagating the error. // If we wouldn't to it, the file would compile and therefore the test would fail. def SubComponent(data string) (stop any) { - println fmt.Println - panic runtime.Panic - --- - :data -> println:data - println:res -> :stop - println:err -> panic + println fmt.Println + panic runtime.Panic + --- + :data -> println:data + println:res -> :stop + println:err -> panic } diff --git a/e2e/errors_must/main/main.neva b/e2e/errors_must/main/main.neva index 6181eef7c..201935435 100644 --- a/e2e/errors_must/main/main.neva +++ b/e2e/errors_must/main/main.neva @@ -20,7 +20,9 @@ def Main(start any) (stop any) { def Handler(data string) (res any, err error) { write_all io.WriteAll? --- - :data -> write_all:filename - 'Hello, io.WriteAll!' -> write_all:data + :data -> [ + write_all:filename, + 'Hello, io.WriteAll!' -> write_all:data + ] write_all:res -> :res } diff --git a/e2e/for_with_range_and_if/main/main.neva b/e2e/for_with_range_and_if/main/main.neva index f57e16dc1..0ed641099 100644 --- a/e2e/for_with_range_and_if/main/main.neva +++ b/e2e/for_with_range_and_if/main/main.neva @@ -22,9 +22,11 @@ def PrintAsNum(data bool) (res any, err error) { ternary Ternary println fmt.Println --- - :data -> ternary:if - 1 -> ternary:then - 0 -> ternary:else + :data -> [ + ternary:if, + 1 -> ternary:then, + 0 -> ternary:else + ] ternary -> println println:res -> :res println:err -> :err diff --git a/e2e/hello_world_verbose/main/main.neva b/e2e/hello_world_verbose/main/main.neva index 32cf77f92..52621c998 100644 --- a/e2e/hello_world_verbose/main/main.neva +++ b/e2e/hello_world_verbose/main/main.neva @@ -11,10 +11,8 @@ def Main(start any) (stop any) { println fmt.Println lock Lock panic runtime.Panic - --- - - :start -> lock:sig + :start -> [lock:sig, greeting:sig] greeting:res -> lock:data lock:data -> println:data println:res -> :stop diff --git a/e2e/hello_world_with_const_sender/main/main.neva b/e2e/hello_world_with_const_sender/main/main.neva index 48307aa5b..ea88111ab 100644 --- a/e2e/hello_world_with_const_sender/main/main.neva +++ b/e2e/hello_world_with_const_sender/main/main.neva @@ -6,13 +6,15 @@ import { const greeting string = 'Hello, World!' def Main(start any) (stop any) { - println fmt.Println - lock Lock - panic runtime.Panic - --- - :start -> lock:sig - $greeting -> lock:data - lock:data -> println:data - println:res -> :stop - println:err -> panic + println fmt.Println + lock Lock + panic runtime.Panic + --- + :start -> [ + lock:sig, + $greeting -> lock:data + ] + lock:data -> println:data + println:res -> :stop + println:err -> panic } \ No newline at end of file diff --git a/e2e/logic_gate_and/main/main.neva b/e2e/logic_gate_and/main/main.neva index d3afb5674..3aede114a 100644 --- a/e2e/logic_gate_and/main/main.neva +++ b/e2e/logic_gate_and/main/main.neva @@ -8,10 +8,10 @@ def Main(start any) (stop any) { panic runtime.Panic --- :start -> [ - { true -> and:left }, - { true -> and:right } + true -> and:left, + true -> and:right ] and -> println:data println:res -> :stop println:err -> panic -} \ No newline at end of file +} diff --git a/e2e/logic_gate_or/main/main.neva b/e2e/logic_gate_or/main/main.neva index e972f6927..89ff9c3d8 100644 --- a/e2e/logic_gate_or/main/main.neva +++ b/e2e/logic_gate_or/main/main.neva @@ -8,10 +8,10 @@ def Main(start any) (stop any) { panic runtime.Panic --- :start -> [ - { false -> or:left }, - { false -> or:right } + false -> or:left, + false -> or:right ] or -> println:data println:res -> :stop println:err -> panic -} \ No newline at end of file +} diff --git a/e2e/multiply_numbers/main/main.neva b/e2e/multiply_numbers/main/main.neva index 7298e7898..db97ddb2c 100644 --- a/e2e/multiply_numbers/main/main.neva +++ b/e2e/multiply_numbers/main/main.neva @@ -7,14 +7,16 @@ import { const l list = [1, 2, 3] def Main(start any) (stop any) { - println fmt.Println - reduce streams.Reduce{Mul} - list_to_stream ListToStream - panic runtime.Panic - --- - :start -> $l -> list_to_stream -> reduce:data - 1 -> reduce:init - reduce -> println:data - println:res -> :stop - println:err -> panic + println fmt.Println + reduce streams.Reduce{Mul} + list_to_stream ListToStream + panic runtime.Panic + --- + :start -> [ + $l -> list_to_stream -> reduce:data, + 1 -> reduce:init + ] + reduce -> println:data + println:res -> :stop + println:err -> panic } diff --git a/e2e/order_dependend_with_arr_inport/main/main.neva b/e2e/order_dependend_with_arr_inport/main/main.neva index 7010d71ae..b265b8218 100644 --- a/e2e/order_dependend_with_arr_inport/main/main.neva +++ b/e2e/order_dependend_with_arr_inport/main/main.neva @@ -8,13 +8,15 @@ const l list = [1, 2, 3] def Main(start any) (stop any) { println fmt.Println - reduce streams.Reduce{Sub} - list_to_stream ListToStream - panic runtime.Panic - --- - :start -> $l -> list_to_stream -> reduce:data - 0 -> reduce:init - reduce -> println:data - println:res -> :stop - println:err -> panic + reduce streams.Reduce{Sub} + list_to_stream ListToStream + panic runtime.Panic + --- + :start -> [ + $l -> list_to_stream -> reduce:data, + 0 -> reduce:init + ] + reduce -> println:data + println:res -> :stop + println:err -> panic } diff --git a/e2e/slow_iteration_with_for/main/main.neva b/e2e/slow_iteration_with_for/main/main.neva index db4098bb8..6eaf4442e 100644 --- a/e2e/slow_iteration_with_for/main/main.neva +++ b/e2e/slow_iteration_with_for/main/main.neva @@ -18,8 +18,10 @@ def Slow(data int) (res any, err error) { time.Delay fmt.Println? --- - :data -> delay:data - $time.second -> delay:dur + :data -> [ + delay:data, + $time.second -> delay:dur + ] delay -> println:data println:res -> :res } diff --git a/e2e/slow_iteration_with_map/main/main.neva b/e2e/slow_iteration_with_map/main/main.neva index 9734c4e96..4ddb293f9 100644 --- a/e2e/slow_iteration_with_map/main/main.neva +++ b/e2e/slow_iteration_with_map/main/main.neva @@ -27,7 +27,9 @@ def Slow(data int) (res int) { delay time.Delay dec Dec --- - :data -> delay:data - $time.second -> delay:dur + :data -> [ + delay:data, + $time.second -> delay:dur + ] delay -> dec -> :res } diff --git a/examples/compare_values/main.neva b/examples/compare_values/main.neva index 2972d1d0d..4b104e266 100644 --- a/examples/compare_values/main.neva +++ b/examples/compare_values/main.neva @@ -13,9 +13,11 @@ def Main(start any) (stop any) { 2 -> eq:left, 2 -> eq:right ] - eq -> ternary:if - 'They match' -> ternary:then - 'They do not match' -> ternary:else + eq -> [ + ternary:if, + 'They match' -> ternary:then, + 'They do not match' -> ternary:else + ] ternary -> println println:res -> :stop println:err -> panic diff --git a/examples/delayed_echo/main.neva b/examples/delayed_echo/main.neva index 3c5ced697..69acb0c49 100644 --- a/examples/delayed_echo/main.neva +++ b/examples/delayed_echo/main.neva @@ -34,8 +34,10 @@ def PrintAfter1Sec(data any) (res any) { println fmt.Println panic runtime.Panic --- - :data -> delay:data - $time.second -> delay:dur + :data -> [ + delay:data, + $time.second -> delay:dur + ] delay -> println println:res -> :res println:err -> panic diff --git a/examples/dict/main.neva b/examples/dict/main.neva index a878d3513..e905e4075 100644 --- a/examples/dict/main.neva +++ b/examples/dict/main.neva @@ -11,8 +11,10 @@ const d dict = { def Main(start any) (stop any) { Get, fmt.Println, runtime.Panic --- - :start -> 'name' -> get:key - $d -> get:dict + :start -> [ + 'name' -> get:key, + $d -> get:dict + ] [get:res, get:err] -> println:data println:res -> :stop println:err -> panic diff --git a/examples/filter_list/main.neva b/examples/filter_list/main.neva index c3389973d..926637f4a 100644 --- a/examples/filter_list/main.neva +++ b/examples/filter_list/main.neva @@ -22,9 +22,7 @@ def IsEven(data int) (res bool) { mod Mod eq Eq --- - :data -> mod:left - 2 -> mod:right - mod -> eq:left - 0 -> eq:right + :data -> [mod:left, 2 -> mod:right] + mod -> [eq:left, 0 -> eq:right] eq -> :res } diff --git a/examples/fizzbuzz/main.neva b/examples/fizzbuzz/main.neva index c30347226..b55839ad7 100644 --- a/examples/fizzbuzz/main.neva +++ b/examples/fizzbuzz/main.neva @@ -30,16 +30,13 @@ def FizzBuzz(data int) (res any) { :data -> [mod15, select:then[3]] - mod15:then -> select:if[0] - 'FizzBuzz' -> select:then[0] + mod15:then -> [select:if[0], 'FizzBuzz' -> select:then[0]] mod15:else -> mod3 - mod3:then -> select:if[1] - 'Fizz' -> select:then[1] + mod3:then -> [select:if[1], 'Fizz' -> select:then[1]] mod3:else -> mod5 - mod5:then -> select:if[2] - 'Buzz' -> select:then[2] + mod5:then -> [select:if[2], 'Buzz' -> select:then[2]] mod5:else -> select:if[3] select -> :res @@ -48,8 +45,7 @@ def FizzBuzz(data int) (res any) { def Mod15(num int) (then int, else int) { h ModHelper --- - :num -> h:num - 15 -> h:den + :num -> [h:num, 15 -> h:den] h:then -> :then h:else -> :else } @@ -57,8 +53,7 @@ def Mod15(num int) (then int, else int) { def Mod3(num int) (then int, else int) { h ModHelper --- - :num -> h:num - 3 -> h:den + :num -> [h:num, 3 -> h:den] h:then -> :then h:else -> :else } @@ -66,8 +61,7 @@ def Mod3(num int) (then int, else int) { def Mod5(num int) (then int, else int) { h ModHelper --- - :num -> h:num - 5 -> h:den + :num -> [h:num, 5 -> h:den] h:then -> :then h:else -> :else } @@ -80,8 +74,7 @@ def ModHelper(num int, den int) (then int, else int) { :num -> [mod:left, cond:data] :den -> mod:right - mod -> eq:left - 0 -> eq:right + mod -> [eq:left, 0 -> eq:right] eq -> cond:if cond:then -> :then diff --git a/examples/image_png/main.neva b/examples/image_png/main.neva index 34cc94066..bba800455 100644 --- a/examples/image_png/main.neva +++ b/examples/image_png/main.neva @@ -6,6 +6,7 @@ def NewPixel(x int, y int, c image.RGBA) (pixel image.Pixel) { :x -> pb:x :y -> pb:y :c -> pb:color + pb -> :pixel } @@ -22,9 +23,11 @@ def NewColor(r int, g int, b int, a int) (color image.RGBA) { def NewStream(p image.Pixel) (s stream) { sb Struct> --- - 0 -> sb:idx - :p -> sb:data - true -> sb:last + :p -> [ + sb:data, + 0 -> sb:idx, + true -> sb:last + ] sb -> :s } diff --git a/examples/match/main.neva b/examples/match/main.neva index c35f3b1dd..a720933ac 100644 --- a/examples/match/main.neva +++ b/examples/match/main.neva @@ -22,18 +22,16 @@ def Handler(data int) (res any, err error) { --- - :data -> match:data - - 1 -> match:if[0] - 'one' -> match:then[0] - - 2 -> match:if[1] - 'two' -> match:then[1] - - 3 -> match:if[2] - 'three' -> match:then[2] - - 'four' -> match:else + :data -> [ + match:data, + 1 -> match:if[0], + 'one' -> match:then[0], + 2 -> match:if[1], + 'two' -> match:then[1], + 3 -> match:if[2], + 'three' -> match:then[2], + 'four' -> match:else + ] match -> println -> :res } diff --git a/examples/reduce_list/main.neva b/examples/reduce_list/main.neva index c7f6e68f0..788d1fe1b 100644 --- a/examples/reduce_list/main.neva +++ b/examples/reduce_list/main.neva @@ -12,8 +12,10 @@ def Main(start any) (stop any) { println fmt.Println panic runtime.Panic --- - :start -> $lst -> l2s -> reduce:data - 0 -> reduce:init + :start -> [ + $lst -> l2s -> reduce:data, + 0 -> reduce:init + ] reduce -> println:data println:res -> :stop println:err -> panic diff --git a/examples/stream_zip/main.neva b/examples/stream_zip/main.neva index 49ee2cb95..403f36e3d 100644 --- a/examples/stream_zip/main.neva +++ b/examples/stream_zip/main.neva @@ -1,19 +1,26 @@ -import { streams, fmt, runtime } +import { + fmt + runtime + streams +} const strings list = ['a', 'b', 'c'] def Main(start any) (stop any) { - ListToStream, streams.Zip + list_to_stream ListToStream range streams.Range - For{fmt.Println}, streams.Wait, runtime.Panic + zip streams.Zip + for_println For{fmt.Println} + wait streams.Wait + panic runtime.Panic --- :start -> [ 0 -> range:from, 10 -> range:to, - $strings -> listToStream -> zip:right + $strings -> list_to_stream -> zip:right ] range -> zip:left - zip:res -> for - for:res -> wait -> :stop - for:err -> panic + zip:res -> for_println + for_println:res -> wait -> :stop + for_println:err -> panic } diff --git a/examples/time_after/main.neva b/examples/time_after/main.neva index d506e199f..c32bd8897 100644 --- a/examples/time_after/main.neva +++ b/examples/time_after/main.neva @@ -3,5 +3,5 @@ import { time } def Main(start any) (stop any) { time.After --- - :start -> { $time.second -> after -> :stop } + :start -> $time.second -> after -> :stop } diff --git a/examples/wait_group/main.neva b/examples/wait_group/main.neva index 572baec37..7bd2278b7 100644 --- a/examples/wait_group/main.neva +++ b/examples/wait_group/main.neva @@ -4,16 +4,16 @@ def Main(start any) (stop any) { p1 fmt.Println p2 fmt.Println p3 fmt.Println - wg sync.WaitGroup - panic runtime.Panic - --- - :start -> [ - 'Hello' -> p1, - 'Neva' -> p2, - 'World!' -> p3 - ] - [p1:res, p2:res, p3:res] -> wg:sig - 3 -> wg:count - wg -> :stop - [p1:err, p2:err, p3:err] -> panic + wg sync.WaitGroup + panic runtime.Panic + --- + :start -> [ + 'Hello' -> p1, + 'Neva' -> p2, + 'World!' -> p3, + 3 -> wg:count + ] + [p1:res, p2:res, p3:res] -> wg:sig + wg -> :stop + [p1:err, p2:err, p3:err] -> panic } diff --git a/internal/compiler/analyzer/senders.go b/internal/compiler/analyzer/senders.go index d5da52011..149ce0dad 100644 --- a/internal/compiler/analyzer/senders.go +++ b/internal/compiler/analyzer/senders.go @@ -70,6 +70,13 @@ func (a Analyzer) analyzeSender( } } + if sender.Const != nil && len(prevChainLink) == 0 { + return nil, nil, &compiler.Error{ + Message: "Constants must be triggered by a signal (e.g. :start -> 42 -> ...)", + Meta: &sender.Meta, + } + } + if len(sender.StructSelector) > 0 && len(prevChainLink) == 0 { return nil, nil, &compiler.Error{ Message: "struct selectors cannot be used in non-chained connection", diff --git a/internal/compiler/desugarer/network.go b/internal/compiler/desugarer/network.go index b30b29968..15a63d1c3 100644 --- a/internal/compiler/desugarer/network.go +++ b/internal/compiler/desugarer/network.go @@ -411,7 +411,7 @@ func (d *Desugarer) desugarChainedConnection( var chainHeadPort string switch { case chainHead.Const != nil: - chainHeadPort = "sig" // NewV2 has sig inport + chainHeadPort = "sig" // New has sig inport case len(chainHead.StructSelector) != 0: chainHeadPort = "data" case chainHead.PortAddr != nil: @@ -442,7 +442,7 @@ func (d *Desugarer) desugarChainedConnection( nodesToInsert[triggerNodeName] = src.Node{ EntityRef: core.EntityRef{ Pkg: "builtin", - Name: "NewV2", + Name: "New", Meta: locOnlyMeta, }, TypeArgs: []ts.Expr{constTypeExpr}, @@ -459,7 +459,7 @@ func (d *Desugarer) desugarChainedConnection( nodesToInsert[triggerNodeName] = src.Node{ EntityRef: core.EntityRef{ Pkg: "builtin", - Name: "NewV2", + Name: "New", Meta: locOnlyMeta, }, TypeArgs: []ts.Expr{chainHead.Const.TypeExpr}, diff --git a/internal/compiler/desugarer/network_test.go b/internal/compiler/desugarer/network_test.go index d76b02ba6..658c7729e 100644 --- a/internal/compiler/desugarer/network_test.go +++ b/internal/compiler/desugarer/network_test.go @@ -560,7 +560,7 @@ func TestDesugarNetwork(t *testing.T) { }, nodesToInsert: map[string]src.Node{ "__newv2__1": { - EntityRef: core.EntityRef{Pkg: "builtin", Name: "NewV2"}, + EntityRef: core.EntityRef{Pkg: "builtin", Name: "New"}, TypeArgs: src.TypeArgs{ { Inst: &ts.InstExpr{ @@ -654,7 +654,7 @@ func TestDesugarNetwork(t *testing.T) { }, nodesToInsert: map[string]src.Node{ "__newv2__1": { - EntityRef: core.EntityRef{Pkg: "builtin", Name: "NewV2"}, + EntityRef: core.EntityRef{Pkg: "builtin", Name: "New"}, TypeArgs: src.TypeArgs{ { Inst: &ts.InstExpr{ diff --git a/internal/compiler/utils/generated/exports.go b/internal/compiler/utils/generated/exports.go index 2931ee08c..473e8b8b6 100755 --- a/internal/compiler/utils/generated/exports.go +++ b/internal/compiler/utils/generated/exports.go @@ -22,36 +22,42 @@ type ParseEntityRefOutput struct { func ParseEntityRef(ctx context.Context, in ParseEntityRefInput) (ParseEntityRefOutput, error) { var ( - at_name_2_out_err_to_p2_in_data = make(chan runtime.OrderedMsg) - eq_out_res_to_cond_in_if = make(chan runtime.OrderedMsg) - __new__7_out_res_to_at_name_2_in_idx = make(chan runtime.OrderedMsg) - fan_in_pkg_out_res_to_builder_in_pkg = make(chan runtime.OrderedMsg) - __fan_out__13_out_data_1_to_at_name_1_in_data = make(chan runtime.OrderedMsg) - __fan_out__10_out_data_0_to_split_in_data = make(chan runtime.OrderedMsg) - in_ref_to___fan_out__10_in_data = make(chan runtime.OrderedMsg) - __fan_out__10_out_data_1_to_builder_in_metaText = make(chan runtime.OrderedMsg) - __new__6_out_res_to_at_pkg_2_in_idx = make(chan runtime.OrderedMsg) - at_name_2_out_res_to_fan_in_name_in_data_0 = make(chan runtime.OrderedMsg) - at_name_1_out_err_to_p3_in_data = make(chan runtime.OrderedMsg) - __fan_out__12_out_data_0_to_at_pkg_2_in_data = make(chan runtime.OrderedMsg) - cond_out_else_to___fan_out__13_in_data = make(chan runtime.OrderedMsg) - __new__4_out_res_to_split_in_delim = make(chan runtime.OrderedMsg) - __fan_out__13_out_data_0_to_lock_empty_pkg_in_sig = make(chan runtime.OrderedMsg) - __fan_out__11_out_data_1_to_cond_in_data = make(chan runtime.OrderedMsg) - __new__8_out_res_to_lock_empty_pkg_in_data = make(chan runtime.OrderedMsg) - __fan_out__12_out_data_1_to_at_name_2_in_data = make(chan runtime.OrderedMsg) - len_out_res_to_eq_in_left = make(chan runtime.OrderedMsg) - cond_out_then_to___fan_out__12_in_data = make(chan runtime.OrderedMsg) - __new__9_out_res_to_at_name_1_in_idx = make(chan runtime.OrderedMsg) - __fan_out__11_out_data_0_to_len_in_data = make(chan runtime.OrderedMsg) - at_pkg_2_out_res_to_fan_in_pkg_in_data_0 = make(chan runtime.OrderedMsg) - at_name_1_out_res_to_fan_in_name_in_data_1 = make(chan runtime.OrderedMsg) - split_out_res_to___fan_out__11_in_data = make(chan runtime.OrderedMsg) - at_pkg_2_out_err_to_p1_in_data = make(chan runtime.OrderedMsg) - builder_out_res_to_out_res = make(chan runtime.OrderedMsg) - fan_in_name_out_res_to_builder_in_name = make(chan runtime.OrderedMsg) - lock_empty_pkg_out_data_to_fan_in_pkg_in_data_1 = make(chan runtime.OrderedMsg) - __new__5_out_res_to_eq_in_right = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_2_to___newv2__1_in_sig = make(chan runtime.OrderedMsg) + builder_out_res_to_out_res = make(chan runtime.OrderedMsg) + __fan_out__4_out_data_1_to_at_name_1_in_data = make(chan runtime.OrderedMsg) + at_name_1_out_err_to_p3_in_data = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_5_to___newv2__4_in_sig = make(chan runtime.OrderedMsg) + split_out_res_to___fan_out__2_in_data = make(chan runtime.OrderedMsg) + __newv2__4_out_res_to_at_name_2_in_idx = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_7_to___newv2__6_in_sig = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_0_to_split_in_data = make(chan runtime.OrderedMsg) + __fan_out__3_out_data_1_to_at_name_2_in_data = make(chan runtime.OrderedMsg) + eq_out_res_to_cond_in_if = make(chan runtime.OrderedMsg) + __newv2__1_out_res_to_split_in_delim = make(chan runtime.OrderedMsg) + __fan_out__2_out_data_1_to_cond_in_data = make(chan runtime.OrderedMsg) + __fan_out__2_out_data_0_to_len_in_data = make(chan runtime.OrderedMsg) + in_ref_to___fan_out__1_in_data = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_6_to___newv2__5_in_sig = make(chan runtime.OrderedMsg) + cond_out_else_to___fan_out__4_in_data = make(chan runtime.OrderedMsg) + __newv2__3_out_res_to_at_pkg_2_in_idx = make(chan runtime.OrderedMsg) + fan_in_pkg_out_res_to_builder_in_pkg = make(chan runtime.OrderedMsg) + at_name_2_out_res_to_fan_in_name_in_data_0 = make(chan runtime.OrderedMsg) + len_out_res_to_eq_in_left = make(chan runtime.OrderedMsg) + __fan_out__3_out_data_0_to_at_pkg_2_in_data = make(chan runtime.OrderedMsg) + at_name_2_out_err_to_p2_in_data = make(chan runtime.OrderedMsg) + at_pkg_2_out_res_to_fan_in_pkg_in_data_0 = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_4_to___newv2__3_in_sig = make(chan runtime.OrderedMsg) + at_pkg_2_out_err_to_p1_in_data = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_1_to_builder_in_metaText = make(chan runtime.OrderedMsg) + fan_in_name_out_res_to_builder_in_name = make(chan runtime.OrderedMsg) + __fan_out__1_out_data_3_to___newv2__2_in_sig = make(chan runtime.OrderedMsg) + __newv2__6_out_res_to_at_name_1_in_idx = make(chan runtime.OrderedMsg) + lock_empty_pkg_out_data_to_fan_in_pkg_in_data_1 = make(chan runtime.OrderedMsg) + __newv2__5_out_res_to_lock_empty_pkg_in_data = make(chan runtime.OrderedMsg) + cond_out_then_to___fan_out__3_in_data = make(chan runtime.OrderedMsg) + at_name_1_out_res_to_fan_in_name_in_data_1 = make(chan runtime.OrderedMsg) + __newv2__2_out_res_to_eq_in_right = make(chan runtime.OrderedMsg) + __fan_out__4_out_data_0_to_lock_empty_pkg_in_sig = make(chan runtime.OrderedMsg) ) interceptor := runtime.ProdInterceptor{} @@ -59,7 +65,7 @@ func ParseEntityRef(ctx context.Context, in ParseEntityRefInput) (ParseEntityRef startPort = runtime.NewSingleOutport( runtime.PortAddr{Path: "in", Port: "start"}, interceptor, - in_ref_to___fan_out__10_in_data, + in_ref_to___fan_out__1_in_data, ) stopPort = runtime.NewSingleInport( builder_out_res_to_out_res, @@ -70,86 +76,84 @@ func ParseEntityRef(ctx context.Context, in ParseEntityRefInput) (ParseEntityRef funcCalls := []runtime.FuncCall{ { - Ref: "fan_out", + Ref: "new", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(in_ref_to___fan_out__10_in_data, runtime.PortAddr{Path: "__fan_out__10/in", Port: "data"}, interceptor)), + "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_7_to___newv2__6_in_sig, runtime.PortAddr{Path: "__newv2__6/in", Port: "sig"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__10/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__10_out_data_0_to_split_in_data, __fan_out__10_out_data_1_to_builder_in_metaText})), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__newv2__6/out", Port: "res"}, interceptor, __newv2__6_out_res_to_at_name_1_in_idx), nil), }), }, - Config: nil, + Config: runtime.NewIntMsg(0), }, { - Ref: "fan_in", + Ref: "new", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(runtime.NewArrayInport([]<-chan runtime.OrderedMsg{at_pkg_2_out_res_to_fan_in_pkg_in_data_0, lock_empty_pkg_out_data_to_fan_in_pkg_in_data_1}, runtime.PortAddr{Path: "fan_in_pkg/in", Port: "data"}, interceptor), nil), + "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_3_to___newv2__2_in_sig, runtime.PortAddr{Path: "__newv2__2/in", Port: "sig"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "fan_in_pkg/out", Port: "res"}, interceptor, fan_in_pkg_out_res_to_builder_in_pkg), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__newv2__2/out", Port: "res"}, interceptor, __newv2__2_out_res_to_eq_in_right), nil), }), }, - Config: nil, + Config: runtime.NewIntMsg(2), }, { Ref: "panic", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(at_pkg_2_out_err_to_p1_in_data, runtime.PortAddr{Path: "p1/in", Port: "data"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(at_name_1_out_err_to_p3_in_data, runtime.PortAddr{Path: "p3/in", Port: "data"}, interceptor)), + }), + Out: runtime.NewOutports(map[string]runtime.Outport{ }), - Out: runtime.NewOutports(map[string]runtime.Outport{}), }, Config: nil, }, { - Ref: "lock", + Ref: "fan_in", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(__new__8_out_res_to_lock_empty_pkg_in_data, runtime.PortAddr{Path: "lock_empty_pkg/in", Port: "data"}, interceptor)), - "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__13_out_data_0_to_lock_empty_pkg_in_sig, runtime.PortAddr{Path: "lock_empty_pkg/in", Port: "sig"}, interceptor)), + "data": runtime.NewInport(runtime.NewArrayInport([]<-chan runtime.OrderedMsg{at_name_2_out_res_to_fan_in_name_in_data_0, at_name_1_out_res_to_fan_in_name_in_data_1}, runtime.PortAddr{Path: "fan_in_name/in", Port: "data"}, interceptor), nil), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "data": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "lock_empty_pkg/out", Port: "data"}, interceptor, lock_empty_pkg_out_data_to_fan_in_pkg_in_data_1), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "fan_in_name/out", Port: "res"}, interceptor, fan_in_name_out_res_to_builder_in_name), nil), }), }, Config: nil, }, { - Ref: "list_at", + Ref: "panic", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__13_out_data_1_to_at_name_1_in_data, runtime.PortAddr{Path: "at_name_1/in", Port: "data"}, interceptor)), - "idx": runtime.NewInport(nil, runtime.NewSingleInport(__new__9_out_res_to_at_name_1_in_idx, runtime.PortAddr{Path: "at_name_1/in", Port: "idx"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(at_pkg_2_out_err_to_p1_in_data, runtime.PortAddr{Path: "p1/in", Port: "data"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "err": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_1/out", Port: "err"}, interceptor, at_name_1_out_err_to_p3_in_data), nil), - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_1/out", Port: "res"}, interceptor, at_name_1_out_res_to_fan_in_name_in_data_1), nil), }), }, Config: nil, }, { - Ref: "fan_in", + Ref: "eq", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(runtime.NewArrayInport([]<-chan runtime.OrderedMsg{at_name_2_out_res_to_fan_in_name_in_data_0, at_name_1_out_res_to_fan_in_name_in_data_1}, runtime.PortAddr{Path: "fan_in_name/in", Port: "data"}, interceptor), nil), + "left": runtime.NewInport(nil, runtime.NewSingleInport(len_out_res_to_eq_in_left, runtime.PortAddr{Path: "eq/in", Port: "left"}, interceptor)), + "right": runtime.NewInport(nil, runtime.NewSingleInport(__newv2__2_out_res_to_eq_in_right, runtime.PortAddr{Path: "eq/in", Port: "right"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "fan_in_name/out", Port: "res"}, interceptor, fan_in_name_out_res_to_builder_in_name), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "eq/out", Port: "res"}, interceptor, eq_out_res_to_cond_in_if), nil), }), }, Config: nil, }, { - Ref: "fan_out", + Ref: "fan_in", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(split_out_res_to___fan_out__11_in_data, runtime.PortAddr{Path: "__fan_out__11/in", Port: "data"}, interceptor)), + "data": runtime.NewInport(runtime.NewArrayInport([]<-chan runtime.OrderedMsg{at_pkg_2_out_res_to_fan_in_pkg_in_data_0, lock_empty_pkg_out_data_to_fan_in_pkg_in_data_1}, runtime.PortAddr{Path: "fan_in_pkg/in", Port: "data"}, interceptor), nil), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__11/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__11_out_data_0_to_len_in_data, __fan_out__11_out_data_1_to_cond_in_data})), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "fan_in_pkg/out", Port: "res"}, interceptor, fan_in_pkg_out_res_to_builder_in_pkg), nil), }), }, Config: nil, @@ -157,68 +161,72 @@ func ParseEntityRef(ctx context.Context, in ParseEntityRefInput) (ParseEntityRef { Ref: "new", IO: runtime.IO{ - In: runtime.NewInports(map[string]runtime.Inport{}), + In: runtime.NewInports(map[string]runtime.Inport{ + "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_5_to___newv2__4_in_sig, runtime.PortAddr{Path: "__newv2__4/in", Port: "sig"}, interceptor)), + }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__new__5/out", Port: "res"}, interceptor, __new__5_out_res_to_eq_in_right), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__newv2__4/out", Port: "res"}, interceptor, __newv2__4_out_res_to_at_name_2_in_idx), nil), }), }, - Config: runtime.NewIntMsg(2), + Config: runtime.NewIntMsg(1), }, { - Ref: "list_at", + Ref: "fan_out", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__12_out_data_1_to_at_name_2_in_data, runtime.PortAddr{Path: "at_name_2/in", Port: "data"}, interceptor)), - "idx": runtime.NewInport(nil, runtime.NewSingleInport(__new__7_out_res_to_at_name_2_in_idx, runtime.PortAddr{Path: "at_name_2/in", Port: "idx"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(cond_out_then_to___fan_out__3_in_data, runtime.PortAddr{Path: "__fan_out__3/in", Port: "data"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "err": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_2/out", Port: "err"}, interceptor, at_name_2_out_err_to_p2_in_data), nil), - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_2/out", Port: "res"}, interceptor, at_name_2_out_res_to_fan_in_name_in_data_0), nil), + "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__3/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__3_out_data_0_to_at_pkg_2_in_data, __fan_out__3_out_data_1_to_at_name_2_in_data})), }), }, Config: nil, }, { - Ref: "list_len", + Ref: "lock", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__11_out_data_0_to_len_in_data, runtime.PortAddr{Path: "len/in", Port: "data"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(__newv2__5_out_res_to_lock_empty_pkg_in_data, runtime.PortAddr{Path: "lock_empty_pkg/in", Port: "data"}, interceptor)), + "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__4_out_data_0_to_lock_empty_pkg_in_sig, runtime.PortAddr{Path: "lock_empty_pkg/in", Port: "sig"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "len/out", Port: "res"}, interceptor, len_out_res_to_eq_in_left), nil), + "data": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "lock_empty_pkg/out", Port: "data"}, interceptor, lock_empty_pkg_out_data_to_fan_in_pkg_in_data_1), nil), }), }, Config: nil, }, { - Ref: "fan_out", + Ref: "list_at", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(cond_out_then_to___fan_out__12_in_data, runtime.PortAddr{Path: "__fan_out__12/in", Port: "data"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__3_out_data_0_to_at_pkg_2_in_data, runtime.PortAddr{Path: "at_pkg_2/in", Port: "data"}, interceptor)), + "idx": runtime.NewInport(nil, runtime.NewSingleInport(__newv2__3_out_res_to_at_pkg_2_in_idx, runtime.PortAddr{Path: "at_pkg_2/in", Port: "idx"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__12/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__12_out_data_0_to_at_pkg_2_in_data, __fan_out__12_out_data_1_to_at_name_2_in_data})), + "err": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_pkg_2/out", Port: "err"}, interceptor, at_pkg_2_out_err_to_p1_in_data), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_pkg_2/out", Port: "res"}, interceptor, at_pkg_2_out_res_to_fan_in_pkg_in_data_0), nil), }), }, Config: nil, }, { - Ref: "new", + Ref: "panic", IO: runtime.IO{ - In: runtime.NewInports(map[string]runtime.Inport{}), + In: runtime.NewInports(map[string]runtime.Inport{ + "data": runtime.NewInport(nil, runtime.NewSingleInport(at_name_2_out_err_to_p2_in_data, runtime.PortAddr{Path: "p2/in", Port: "data"}, interceptor)), + }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__new__7/out", Port: "res"}, interceptor, __new__7_out_res_to_at_name_2_in_idx), nil), }), }, - Config: runtime.NewIntMsg(1), + Config: nil, }, { Ref: "struct_builder", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "metaText": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__10_out_data_1_to_builder_in_metaText, runtime.PortAddr{Path: "builder/in", Port: "metaText"}, interceptor)), - "name": runtime.NewInport(nil, runtime.NewSingleInport(fan_in_name_out_res_to_builder_in_name, runtime.PortAddr{Path: "builder/in", Port: "name"}, interceptor)), - "pkg": runtime.NewInport(nil, runtime.NewSingleInport(fan_in_pkg_out_res_to_builder_in_pkg, runtime.PortAddr{Path: "builder/in", Port: "pkg"}, interceptor)), + "metaText": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_1_to_builder_in_metaText, runtime.PortAddr{Path: "builder/in", Port: "metaText"}, interceptor)), + "name": runtime.NewInport(nil, runtime.NewSingleInport(fan_in_name_out_res_to_builder_in_name, runtime.PortAddr{Path: "builder/in", Port: "name"}, interceptor)), + "pkg": runtime.NewInport(nil, runtime.NewSingleInport(fan_in_pkg_out_res_to_builder_in_pkg, runtime.PortAddr{Path: "builder/in", Port: "pkg"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "builder/out", Port: "res"}, interceptor, builder_out_res_to_out_res), nil), @@ -227,136 +235,149 @@ func ParseEntityRef(ctx context.Context, in ParseEntityRefInput) (ParseEntityRef Config: nil, }, { - Ref: "panic", + Ref: "cond", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(at_name_1_out_err_to_p3_in_data, runtime.PortAddr{Path: "p3/in", Port: "data"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__2_out_data_1_to_cond_in_data, runtime.PortAddr{Path: "cond/in", Port: "data"}, interceptor)), + "if": runtime.NewInport(nil, runtime.NewSingleInport(eq_out_res_to_cond_in_if, runtime.PortAddr{Path: "cond/in", Port: "if"}, interceptor)), + }), + Out: runtime.NewOutports(map[string]runtime.Outport{ + "else": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "cond/out", Port: "else"}, interceptor, cond_out_else_to___fan_out__4_in_data), nil), + "then": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "cond/out", Port: "then"}, interceptor, cond_out_then_to___fan_out__3_in_data), nil), }), - Out: runtime.NewOutports(map[string]runtime.Outport{}), }, Config: nil, }, { - Ref: "strings_split", + Ref: "new", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__10_out_data_0_to_split_in_data, runtime.PortAddr{Path: "split/in", Port: "data"}, interceptor)), - "delim": runtime.NewInport(nil, runtime.NewSingleInport(__new__4_out_res_to_split_in_delim, runtime.PortAddr{Path: "split/in", Port: "delim"}, interceptor)), + "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_6_to___newv2__5_in_sig, runtime.PortAddr{Path: "__newv2__5/in", Port: "sig"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "split/out", Port: "res"}, interceptor, split_out_res_to___fan_out__11_in_data), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__newv2__5/out", Port: "res"}, interceptor, __newv2__5_out_res_to_lock_empty_pkg_in_data), nil), }), }, - Config: nil, + Config: runtime.NewStringMsg(""), }, { - Ref: "fan_out", + Ref: "new", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(cond_out_else_to___fan_out__13_in_data, runtime.PortAddr{Path: "__fan_out__13/in", Port: "data"}, interceptor)), + "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_4_to___newv2__3_in_sig, runtime.PortAddr{Path: "__newv2__3/in", Port: "sig"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__13/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__13_out_data_0_to_lock_empty_pkg_in_sig, __fan_out__13_out_data_1_to_at_name_1_in_data})), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__newv2__3/out", Port: "res"}, interceptor, __newv2__3_out_res_to_at_pkg_2_in_idx), nil), }), }, - Config: nil, + Config: runtime.NewIntMsg(0), }, { - Ref: "new", + Ref: "list_len", IO: runtime.IO{ - In: runtime.NewInports(map[string]runtime.Inport{}), + In: runtime.NewInports(map[string]runtime.Inport{ + "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__2_out_data_0_to_len_in_data, runtime.PortAddr{Path: "len/in", Port: "data"}, interceptor)), + }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__new__4/out", Port: "res"}, interceptor, __new__4_out_res_to_split_in_delim), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "len/out", Port: "res"}, interceptor, len_out_res_to_eq_in_left), nil), }), }, - Config: runtime.NewStringMsg("."), + Config: nil, }, { - Ref: "new", + Ref: "strings_split", IO: runtime.IO{ - In: runtime.NewInports(map[string]runtime.Inport{}), + In: runtime.NewInports(map[string]runtime.Inport{ + "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_0_to_split_in_data, runtime.PortAddr{Path: "split/in", Port: "data"}, interceptor)), + "delim": runtime.NewInport(nil, runtime.NewSingleInport(__newv2__1_out_res_to_split_in_delim, runtime.PortAddr{Path: "split/in", Port: "delim"}, interceptor)), + }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__new__9/out", Port: "res"}, interceptor, __new__9_out_res_to_at_name_1_in_idx), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "split/out", Port: "res"}, interceptor, split_out_res_to___fan_out__2_in_data), nil), }), }, - Config: runtime.NewIntMsg(0), + Config: nil, }, { - Ref: "eq", + Ref: "fan_out", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "left": runtime.NewInport(nil, runtime.NewSingleInport(len_out_res_to_eq_in_left, runtime.PortAddr{Path: "eq/in", Port: "left"}, interceptor)), - "right": runtime.NewInport(nil, runtime.NewSingleInport(__new__5_out_res_to_eq_in_right, runtime.PortAddr{Path: "eq/in", Port: "right"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(split_out_res_to___fan_out__2_in_data, runtime.PortAddr{Path: "__fan_out__2/in", Port: "data"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "eq/out", Port: "res"}, interceptor, eq_out_res_to_cond_in_if), nil), + "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__2/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__2_out_data_0_to_len_in_data, __fan_out__2_out_data_1_to_cond_in_data})), }), }, Config: nil, }, { - Ref: "cond", + Ref: "fan_out", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__11_out_data_1_to_cond_in_data, runtime.PortAddr{Path: "cond/in", Port: "data"}, interceptor)), - "if": runtime.NewInport(nil, runtime.NewSingleInport(eq_out_res_to_cond_in_if, runtime.PortAddr{Path: "cond/in", Port: "if"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(cond_out_else_to___fan_out__4_in_data, runtime.PortAddr{Path: "__fan_out__4/in", Port: "data"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "else": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "cond/out", Port: "else"}, interceptor, cond_out_else_to___fan_out__13_in_data), nil), - "then": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "cond/out", Port: "then"}, interceptor, cond_out_then_to___fan_out__12_in_data), nil), + "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__4/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__4_out_data_0_to_lock_empty_pkg_in_sig, __fan_out__4_out_data_1_to_at_name_1_in_data})), }), }, Config: nil, }, { - Ref: "list_at", + Ref: "fan_out", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__12_out_data_0_to_at_pkg_2_in_data, runtime.PortAddr{Path: "at_pkg_2/in", Port: "data"}, interceptor)), - "idx": runtime.NewInport(nil, runtime.NewSingleInport(__new__6_out_res_to_at_pkg_2_in_idx, runtime.PortAddr{Path: "at_pkg_2/in", Port: "idx"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(in_ref_to___fan_out__1_in_data, runtime.PortAddr{Path: "__fan_out__1/in", Port: "data"}, interceptor)), }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "err": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_pkg_2/out", Port: "err"}, interceptor, at_pkg_2_out_err_to_p1_in_data), nil), - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_pkg_2/out", Port: "res"}, interceptor, at_pkg_2_out_res_to_fan_in_pkg_in_data_0), nil), + "data": runtime.NewOutport(nil, runtime.NewArrayOutport(runtime.PortAddr{Path: "__fan_out__1/out", Port: "data"}, interceptor, []chan<- runtime.OrderedMsg{__fan_out__1_out_data_0_to_split_in_data, __fan_out__1_out_data_1_to_builder_in_metaText, __fan_out__1_out_data_2_to___newv2__1_in_sig, __fan_out__1_out_data_3_to___newv2__2_in_sig, __fan_out__1_out_data_4_to___newv2__3_in_sig, __fan_out__1_out_data_5_to___newv2__4_in_sig, __fan_out__1_out_data_6_to___newv2__5_in_sig, __fan_out__1_out_data_7_to___newv2__6_in_sig})), }), }, Config: nil, }, { - Ref: "panic", + Ref: "list_at", IO: runtime.IO{ In: runtime.NewInports(map[string]runtime.Inport{ - "data": runtime.NewInport(nil, runtime.NewSingleInport(at_name_2_out_err_to_p2_in_data, runtime.PortAddr{Path: "p2/in", Port: "data"}, interceptor)), + "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__4_out_data_1_to_at_name_1_in_data, runtime.PortAddr{Path: "at_name_1/in", Port: "data"}, interceptor)), + "idx": runtime.NewInport(nil, runtime.NewSingleInport(__newv2__6_out_res_to_at_name_1_in_idx, runtime.PortAddr{Path: "at_name_1/in", Port: "idx"}, interceptor)), + }), + Out: runtime.NewOutports(map[string]runtime.Outport{ + "err": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_1/out", Port: "err"}, interceptor, at_name_1_out_err_to_p3_in_data), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_1/out", Port: "res"}, interceptor, at_name_1_out_res_to_fan_in_name_in_data_1), nil), }), - Out: runtime.NewOutports(map[string]runtime.Outport{}), }, Config: nil, }, { - Ref: "new", + Ref: "list_at", IO: runtime.IO{ - In: runtime.NewInports(map[string]runtime.Inport{}), + In: runtime.NewInports(map[string]runtime.Inport{ + "data": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__3_out_data_1_to_at_name_2_in_data, runtime.PortAddr{Path: "at_name_2/in", Port: "data"}, interceptor)), + "idx": runtime.NewInport(nil, runtime.NewSingleInport(__newv2__4_out_res_to_at_name_2_in_idx, runtime.PortAddr{Path: "at_name_2/in", Port: "idx"}, interceptor)), + }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__new__6/out", Port: "res"}, interceptor, __new__6_out_res_to_at_pkg_2_in_idx), nil), + "err": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_2/out", Port: "err"}, interceptor, at_name_2_out_err_to_p2_in_data), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "at_name_2/out", Port: "res"}, interceptor, at_name_2_out_res_to_fan_in_name_in_data_0), nil), }), }, - Config: runtime.NewIntMsg(0), + Config: nil, }, { Ref: "new", IO: runtime.IO{ - In: runtime.NewInports(map[string]runtime.Inport{}), + In: runtime.NewInports(map[string]runtime.Inport{ + "sig": runtime.NewInport(nil, runtime.NewSingleInport(__fan_out__1_out_data_2_to___newv2__1_in_sig, runtime.PortAddr{Path: "__newv2__1/in", Port: "sig"}, interceptor)), + }), Out: runtime.NewOutports(map[string]runtime.Outport{ - "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__new__8/out", Port: "res"}, interceptor, __new__8_out_res_to_lock_empty_pkg_in_data), nil), + "res": runtime.NewOutport(runtime.NewSingleOutport(runtime.PortAddr{Path: "__newv2__1/out", Port: "res"}, interceptor, __newv2__1_out_res_to_split_in_delim), nil), }), }, - Config: runtime.NewStringMsg(""), + Config: runtime.NewStringMsg("."), }, } rprog := runtime.Program{ - Start: startPort, - Stop: stopPort, + Start: startPort, + Stop: stopPort, FuncCalls: funcCalls, } startMsg := runtime.NewStringMsg(in.Ref) diff --git a/internal/compiler/utils/utils.neva b/internal/compiler/utils/utils.neva index 486a381fe..e482a1c87 100644 --- a/internal/compiler/utils/utils.neva +++ b/internal/compiler/utils/utils.neva @@ -19,59 +19,60 @@ pub def ParseEntityRef(ref string) (res EntityRef) { lock_empty_pkg Lock // Path 2 parts - at_pkg_2 lists.At - at_name_2 lists.At + at_pkg_2 MustAt + at_name_2 MustAt // Path 1 part - at_name_1 lists.At + at_name_1 MustAt fan_in_pkg FanIn fan_in_name FanIn builder Struct - p1 runtime.Panic - p2 runtime.Panic - p3 runtime.Panic - --- :ref -> [ split:data, - builder:metaText + builder:metaText, + '.' -> split:delim, + 2 -> eq:right, + 0 -> at_pkg_2:idx, + 1 -> at_name_2:idx, + '' -> lock_empty_pkg:data, + 0 -> at_name_1:idx ] - '.' -> split:delim split:res -> [len:data, cond:data] len -> eq:left - 2 -> eq:right eq -> cond:if // If 2 parts cond:then -> [at_pkg_2:data, at_name_2:data] - 0 -> at_pkg_2:idx - 1 -> at_name_2:idx at_pkg_2:res -> fan_in_pkg:data[0] at_name_2:res -> fan_in_name:data[0] // If 1 part cond:else -> [lock_empty_pkg:sig, at_name_1:data] - '' -> lock_empty_pkg:data lock_empty_pkg:data -> fan_in_pkg:data[1] - 0 -> at_name_1:idx at_name_1:res -> fan_in_name:data[1] fan_in_pkg -> builder:pkg fan_in_name -> builder:name builder -> :res - - // Invariants - at_pkg_2:err -> p1 - at_name_2:err -> p2 - at_name_1:err -> p3 } +def MustAt(data list, idx int) (res string) { + at lists.At + panic runtime.Panic + --- + :data -> at:data + :idx -> at:idx + at:err -> panic + at:res -> :res +} + diff --git a/internal/runtime/funcs/new.go b/internal/runtime/funcs/new.go index 694048b5f..8df73ae65 100644 --- a/internal/runtime/funcs/new.go +++ b/internal/runtime/funcs/new.go @@ -6,9 +6,14 @@ import ( "github.com/nevalang/neva/internal/runtime" ) -type newV1 struct{} +type newV2 struct{} + +func (c newV2) Create(io runtime.IO, cfg runtime.Msg) (func(ctx context.Context), error) { + sigIn, err := io.In.Single("sig") + if err != nil { + return nil, err + } -func (c newV1) Create(io runtime.IO, cfg runtime.Msg) (func(ctx context.Context), error) { resOut, err := io.Out.Single("res") if err != nil { return nil, err @@ -16,6 +21,9 @@ func (c newV1) Create(io runtime.IO, cfg runtime.Msg) (func(ctx context.Context) return func(ctx context.Context) { for { + if _, ok := sigIn.Receive(ctx); !ok { + return + } if !resOut.Send(ctx, cfg) { return } diff --git a/internal/runtime/funcs/new_v2.go b/internal/runtime/funcs/new_v2.go deleted file mode 100644 index 8df73ae65..000000000 --- a/internal/runtime/funcs/new_v2.go +++ /dev/null @@ -1,32 +0,0 @@ -package funcs - -import ( - "context" - - "github.com/nevalang/neva/internal/runtime" -) - -type newV2 struct{} - -func (c newV2) Create(io runtime.IO, cfg runtime.Msg) (func(ctx context.Context), error) { - sigIn, err := io.In.Single("sig") - if err != nil { - return nil, err - } - - resOut, err := io.Out.Single("res") - if err != nil { - return nil, err - } - - return func(ctx context.Context) { - for { - if _, ok := sigIn.Receive(ctx); !ok { - return - } - if !resOut.Send(ctx, cfg) { - return - } - } - }, nil -} diff --git a/internal/runtime/funcs/registry.go b/internal/runtime/funcs/registry.go index c6c5eee1c..7dd038f50 100644 --- a/internal/runtime/funcs/registry.go +++ b/internal/runtime/funcs/registry.go @@ -8,8 +8,7 @@ import ( func NewRegistry() map[string]runtime.FuncCreator { return map[string]runtime.FuncCreator{ - "new": newV1{}, - "new_v2": newV2{}, + "new": newV2{}, "del": del{}, "lock": lock{}, "fan_in": fanIn{}, diff --git a/std/builtin/core.neva b/std/builtin/core.neva index ee5c5fab7..be8863412 100644 --- a/std/builtin/core.neva +++ b/std/builtin/core.neva @@ -1,15 +1,11 @@ -// New emits a message in an infinite loop. -// It is inteited to be used with #bind directive. -// You should prefer constant references and literals over New if possible. -// New, just like constant senders, must be used with caution. -// Being infinite, it can easily lead to buffer overflow. -// New is within small group of components without inports. +// New emits a message when triggered by a signal. +// It is intended to be used with #bind directive. +// You should prefer constant references and literals over New. +// New requires a trigger signal to prevent buffer overflow. #extern(new) -pub def New() (res T) +pub def New(sig any) (res T) + -// NewV2 is like New but with `:sig` inport that works like trigger. -#extern(new_v2) -pub def NewV2(sig any) (res T) // Del receives and discards the message. // You should avoid using it because compiler will insert it automatically diff --git a/std/builtin/streams.neva b/std/builtin/streams.neva index 110eccf7d..c8d8286cc 100644 --- a/std/builtin/streams.neva +++ b/std/builtin/streams.neva @@ -39,8 +39,10 @@ def First(data stream) (then stream, else stream) { pass Pass> --- :data -> [cond:data, pass] - pass -> .idx -> eq:left - 0 -> eq:right + pass -> [ + .idx -> eq:left, + 0 -> eq:right + ] eq -> cond:if cond:then -> :then cond:else -> :else diff --git a/std/errors/errors.neva b/std/errors/errors.neva index 4094986ab..497d5f828 100644 --- a/std/errors/errors.neva +++ b/std/errors/errors.neva @@ -28,9 +28,9 @@ pub def Lift(data T) (res Y, err error) { --- :data -> [ handler -> :res, - false -> s:data + false -> s:data, + true -> s:case[0] ] - true -> s:case[0] s:case[0] -> '' -> new -> :err s:else -> del } diff --git a/std/streams/streams.neva b/std/streams/streams.neva index 90ae2f471..c1bad1b75 100644 --- a/std/streams/streams.neva +++ b/std/streams/streams.neva @@ -9,8 +9,10 @@ pub def Wait(data stream) (sig any) { del Del s Switch --- - :data -> .last -> s:data - true -> s:case[0] + :data -> [ + .last -> s:data, + true -> s:case[0] + ] s:case[0] -> :sig s:else -> del }