Skip to content

Commit

Permalink
math: Add {int,float}_div and int_mod ops
Browse files Browse the repository at this point in the history
Old int_mod was renamed CaseMod (int_casemod)
to reflect its usage. Examples using it were updated.
  • Loading branch information
Catya3 committed Jun 11, 2024
1 parent 74c50ae commit e98b1e8
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 45 deletions.
2 changes: 1 addition & 1 deletion examples/fizzbuzz/main.neva
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ flow Main(start) (stop) {
}

flow PrintLine(data int) (data int) {
nodes { Mod, Println, Lock<int> }
nodes { mod CaseMod, Println, Lock<int> }

:data -> [mod:data, lock:data]

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

import (
"context"

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

type floatDiv struct{}

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

yIn, err := io.In.Port("y")
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 x, y float64
select {
case <-ctx.Done():
return
case msg := <-xIn:
x = msg.Float()
}
select {
case <-ctx.Done():
return
case msg := <-yIn:
y = msg.Float()
}
if y == 0 {
select {
case <-ctx.Done():
return
case errOut <- runtime.NewMapMsg(map[string]runtime.Msg{
"text": runtime.NewStrMsg(errIntegerDivideByZero.Error()),
}):
continue
}
}
select {
case <-ctx.Done():
return
case resOut <- runtime.NewFloatMsg(x / y):
}
}
}, nil
}
82 changes: 82 additions & 0 deletions internal/runtime/funcs/int_casemod.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package funcs

import (
"context"
"errors"

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

type intCaseMod struct{}

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

caseIn, ok := io.In["case"]
if !ok {
return nil, errors.New("port 'case' is required")
}

caseOut, ok := io.Out["case"]
if !ok {
return nil, errors.New("port 'then' is required")
}

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

if len(caseIn) != len(caseOut) {
return nil, errors.New("number of 'case' inports must match number of 'then' outports")
}

return func(ctx context.Context) {
var data runtime.Msg

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

cases := make([]runtime.Msg, len(caseIn))
for i, slot := range caseIn {
select {
case <-ctx.Done():
return
case caseMsg := <-slot:
cases[i] = caseMsg
}
}

matchIdx := -1
dataInt := data.Int()
for i, caseMsg := range cases {
if dataInt%caseMsg.Int() == 0 {
matchIdx = i
break
}
}

if matchIdx != -1 {
select {
case <-ctx.Done():
return
case caseOut[matchIdx] <- data:
continue
}
}

select {
case <-ctx.Done():
return
case elseOut <- data:
}
}
}, nil
}
64 changes: 64 additions & 0 deletions internal/runtime/funcs/int_div.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package funcs

import (
"context"

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

type intDiv struct{}

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

yIn, err := io.In.Port("y")
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 x, y int64
select {
case <-ctx.Done():
return
case msg := <-xIn:
x = msg.Int()
}
select {
case <-ctx.Done():
return
case msg := <-yIn:
y = msg.Int()
}
if y == 0 {
select {
case <-ctx.Done():
return
case errOut <- runtime.NewMapMsg(map[string]runtime.Msg{
"text": runtime.NewStrMsg(errIntegerDivideByZero.Error()),
}):
continue
}
}
select {
case <-ctx.Done():
return
case resOut <- runtime.NewIntMsg(x / y):
}
}
}, nil
}
61 changes: 23 additions & 38 deletions internal/runtime/funcs/int_mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,75 +7,60 @@ import (
"github.com/nevalang/neva/internal/runtime"
)

var errIntegerDivideByZero = errors.New("integer divide by zero")

type intMod struct{}

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

caseIn, ok := io.In["case"]
if !ok {
return nil, errors.New("port 'case' is required")
}

caseOut, ok := io.Out["case"]
if !ok {
return nil, errors.New("port 'then' is required")
yIn, err := io.In.Port("y")
if err != nil {
return nil, err
}

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

if len(caseIn) != len(caseOut) {
return nil, errors.New("number of 'case' inports must match number of 'then' outports")
errOut, err := io.Out.Port("err")
if err != nil {
return nil, err
}

return func(ctx context.Context) {
var data runtime.Msg

for {
var x, y int64
select {
case <-ctx.Done():
return
case data = <-dataIn:
case msg := <-xIn:
x = msg.Int()
}

cases := make([]runtime.Msg, len(caseIn))
for i, slot := range caseIn {
select {
case <-ctx.Done():
return
case caseMsg := <-slot:
cases[i] = caseMsg
}
}

matchIdx := -1
dataInt := data.Int()
for i, caseMsg := range cases {
if dataInt%caseMsg.Int() == 0 {
matchIdx = i
break
}
select {
case <-ctx.Done():
return
case msg := <-yIn:
y = msg.Int()
}

if matchIdx != -1 {
if y == 0 {
select {
case <-ctx.Done():
return
case caseOut[matchIdx] <- data:
case errOut <- runtime.NewMapMsg(map[string]runtime.Msg{
"text": runtime.NewStrMsg(errIntegerDivideByZero.Error()),
}):
continue
}
}

select {
case <-ctx.Done():
return
case elseOut <- data:
case resOut <- runtime.NewIntMsg(x % y):
}
}
}, nil
Expand Down
13 changes: 8 additions & 5 deletions internal/runtime/funcs/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ func CreatorRegistry() map[string]runtime.FuncCreator {
"field": readStructField{},

// math
"int_add": intAdd{},
"int_sub": intSub{},
"int_mul": intMul{},
"int_decr": intDecr{},
"int_mod": intMod{},
"int_add": intAdd{},
"int_sub": intSub{},
"int_mul": intMul{},
"int_div": intDiv{},
"float_div": floatDiv{},
"int_decr": intDecr{},
"int_mod": intCaseMod{},
"int_casemod": intCaseMod{},

// strconv
"parse_int": parseInt{},
Expand Down
8 changes: 7 additions & 1 deletion std/builtin/math.neva
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ pub flow Sub<T int | float >(seq stream<T>) (res T)
#extern(int int_mul, float float_mul)
pub flow Mul<T int | float >(seq stream<T>) (res T)

#extern(int int_div, float float_div)
pub flow Div<T int | float >(seq stream<T>) (res T, err error)

#extern(int int_decr, float float_decr)
pub flow Decr<T int | float>(data T) (res T)

#extern(int_mod)
pub flow Mod(data int, [case] int) ([case] int, else int)
pub flow Mod(x int, y int) (res int, err error)

#extern(int_casemod)
pub flow CaseMod(data int, [case] int) ([case] int, else int)

0 comments on commit e98b1e8

Please sign in to comment.