Skip to content

Commit

Permalink
Merge pull request #679 from nevalang/lists-at
Browse files Browse the repository at this point in the history
Add `{lists,strings}.At` flow ops to access elements of a List and runes in a string
  • Loading branch information
emil14 authored Jun 15, 2024
2 parents d8dbcdc + 523048a commit a544152
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 79 deletions.
12 changes: 7 additions & 5 deletions examples/list_index/main.neva
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { lists }

const lst list<int> = [1, 1, 5, 112, 69, 420]

flow Main(start) (stop) {
nodes { Index<list<int>>, Println }
nodes { lists.At<int>, Println }
:start -> [
($lst -> index:data),
(4 -> index:idx)
($lst -> at:data),
(4 -> at:idx)
]
[index:res, index:err] -> println -> :stop
}
[at:res, at:err] -> println -> :stop
}
67 changes: 0 additions & 67 deletions internal/runtime/funcs/index.go

This file was deleted.

77 changes: 77 additions & 0 deletions internal/runtime/funcs/list_at.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package funcs

import (
"context"
"errors"

"github.com/nevalang/neva/internal/runtime"
)

var errListIndexOutOfBounds = errors.New("list index out of bounds")

type listAt struct{}

func (listAt) Create(io runtime.FuncIO, _ runtime.Msg) (func(ctx context.Context), error) {
dataIn, err := io.In.Port("data")
if err != nil {
return nil, err
}

idxIn, err := io.In.Port("idx")
if err != nil {
return nil, err
}

resOut, err := io.Out.Port("res")
if err != nil {
return nil, err
}

errOut, err := io.Out.Port("err")
if err != nil {
return nil, err
}

return func(ctx context.Context) {
for {
var data []runtime.Msg
var idx int64

select {
case <-ctx.Done():
return
case msg := <-dataIn:
data = msg.List()
}

select {
case <-ctx.Done():
return
case msg := <-idxIn:
idx = msg.Int()
}

if idx < 0 {
// Support negative indexing:
// $l = [1, 2, 3]
// $l[-1] // 3
idx += int64(len(data))
}

if idx < 0 || idx >= int64(len(data)) {
select {
case <-ctx.Done():
return
case errOut <- errorFromString(errListIndexOutOfBounds.Error()):
continue
}
}

select {
case <-ctx.Done():
return
case resOut <- data[idx]:
}
}
}, nil
}
3 changes: 2 additions & 1 deletion internal/runtime/funcs/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func CreatorRegistry() map[string]runtime.FuncCreator {
"regexp_submatch": regexpSubmatch{},

// list
"index": index{},
"list_at": listAt{},
"list_len": listlen{},
"list_push": listPush{},
"int_sort": listSortInt{},
Expand All @@ -73,6 +73,7 @@ func CreatorRegistry() map[string]runtime.FuncCreator {
"time_sleep": timeSleep{},

// strings
"string_at": stringAt{},
"join": stringJoin{},
"split": stringSplit{},
"string_sort": listSortString{},
Expand Down
88 changes: 88 additions & 0 deletions internal/runtime/funcs/string_at.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package funcs

import (
"context"
"errors"

"github.com/nevalang/neva/internal/runtime"
)

var errStrIndexOutOfBounds = errors.New("string index out of bounds")

type stringAt struct{}

func (stringAt) Create(io runtime.FuncIO, _ runtime.Msg) (func(context.Context), error) {
dataIn, err := io.In.Port("data")
if err != nil {
return nil, err
}

idxIn, err := io.In.Port("idx")
if err != nil {
return nil, err
}

resOut, err := io.Out.Port("res")
if err != nil {
return nil, err
}

errOut, err := io.Out.Port("err")
if err != nil {
return nil, err
}

return func(ctx context.Context) {
for {
var data string
var idx int64

select {
case <-ctx.Done():
return
case msg := <-dataIn:
data = msg.Str()
}

select {
case <-ctx.Done():
return
case msg := <-idxIn:
idx = msg.Int()
}

if idx < 0 {
// Support negaitve indexing:
// $s = "abc"
// $s[-1] // "c"
idx += int64(len(data))
}

if idx >= 0 && idx < int64(len(data)) {
var res rune
var found bool
for i, r := range data {
if int64(i) == idx {
res = r
found = true
break
}
}
if found {
select {
case <-ctx.Done():
return
case resOut <- runtime.NewStrMsg(string(res)):
continue
}
}
}

select {
case <-ctx.Done():
return
case errOut <- errorFromString(errStrIndexOutOfBounds.Error()):
}
}
}, nil
}
6 changes: 0 additions & 6 deletions std/builtin/collections.neva
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@ pub flow Len<T list<any> | map<any> | string>(data T) (res int)
#extern(stream_to_list)
pub flow List<T>(seq stream<T>) (res list<T>)

// Index returns the element at the given index in the ordered collection.
// If the index is out of bounds, it returns an error.
// The index is zero-based.
#extern(index)
pub flow Index<T list<any> | string>(data T, idx int) (res T, err error)

// Push creates new list with appended element.
#extern(list_push)
pub flow Push<T> (lst list<T>, data T) (res list<T>)
Expand Down
3 changes: 3 additions & 0 deletions std/lists/lists.neva
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#extern(list_at)
pub flow At<T>(data list<T>, idx int) (res T, err error)

pub flow For<T>(data list<T>) (sig any) {
nodes {
Iter<T>
Expand Down

0 comments on commit a544152

Please sign in to comment.