package compiler_test import ( "context" "github.com/MontFerret/ferret/pkg/compiler" "github.com/MontFerret/ferret/pkg/runtime" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" . "github.com/smartystreets/goconvey/convey" "testing" ) func TestForWhile(t *testing.T) { Convey("FOR WHILE", t, func() { Convey("WHILE", func() { Convey("Should compile FOR i WHILE false RETURN i", func() { c := compiler.New() p, err := c.Compile(` FOR i WHILE false RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[]") }) Convey("Should compile FOR i WHILE [] RETURN i", func() { c := compiler.New() p, err := c.Compile(` FOR i WHILE [] RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[]") }) Convey("Should compile FOR i WHILE F() < 10 RETURN i", func() { c := compiler.New() counter := -1 c.RegisterFunction("F", func(ctx context.Context, args ...core.Value) (core.Value, error) { counter++ return values.NewInt(counter), nil }) p, err := c.Compile(` FOR i WHILE F() < 10 RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0,1,2,3,4,5,6,7,8,9]") }) Convey("Should compile FOR i WHILE F() RETURN i", func() { c := compiler.New() counter := -1 c.RegisterFunction("F", func(ctx context.Context, args ...core.Value) (core.Value, error) { counter++ if counter == 10 { return values.False, nil } return values.True, nil }) p, err := c.Compile(` FOR i WHILE F() RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0,1,2,3,4,5,6,7,8,9]") }) Convey("Should compile nested FOR operators", func() { c := compiler.New() counter := -1 c.RegisterFunction("F", func(ctx context.Context, args ...core.Value) (core.Value, error) { counter++ return values.NewInt(counter), nil }) p, err := c.Compile(` FOR i WHILE F() < 5 LET y = i + 1 FOR x IN 1..y RETURN i * x `) So(err, ShouldBeNil) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0,1,2,2,4,6,3,6,9,12,4,8,12,16,20]") }) }) Convey("DO-WHILE", func() { Convey("Should compile FOR i DO WHILE false RETURN i", func() { c := compiler.New() p, err := c.Compile(` FOR i DO WHILE false RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0]") }) Convey("Should compile FOR i DO WHILE [] RETURN i", func() { c := compiler.New() p, err := c.Compile(` FOR i DO WHILE [] RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0]") }) Convey("Should compile FOR i DO WHILE F() < 10 RETURN i", func() { c := compiler.New() counter := -1 c.RegisterFunction("F", func(ctx context.Context, args ...core.Value) (core.Value, error) { counter++ return values.NewInt(counter), nil }) p, err := c.Compile(` FOR i DO WHILE F() < 10 RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0,1,2,3,4,5,6,7,8,9,10]") }) Convey("Should compile FOR i WHILE F() RETURN i", func() { c := compiler.New() counter := -1 c.RegisterFunction("F", func(ctx context.Context, args ...core.Value) (core.Value, error) { counter++ if counter == 10 { return values.False, nil } return values.True, nil }) p, err := c.Compile(` FOR i WHILE F() RETURN i `) So(err, ShouldBeNil) So(p, ShouldHaveSameTypeAs, &runtime.Program{}) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0,1,2,3,4,5,6,7,8,9]") }) Convey("Should compile nested FOR operators", func() { c := compiler.New() counter := -1 c.RegisterFunction("F", func(ctx context.Context, args ...core.Value) (core.Value, error) { counter++ return values.NewInt(counter), nil }) p, err := c.Compile(` FOR i WHILE F() < 5 LET y = i + 1 FOR x IN 1..y RETURN i * x `) So(err, ShouldBeNil) out, err := p.Run(context.Background()) So(err, ShouldBeNil) So(string(out), ShouldEqual, "[0,1,2,2,4,6,3,6,9,12,4,8,12,16,20]") }) }) }) }