diff --git a/core/collect.go b/core/collect.go deleted file mode 100644 index b828529..0000000 --- a/core/collect.go +++ /dev/null @@ -1,40 +0,0 @@ -package core - -import ( - "bytes" - "fmt" - - "github.com/emicklei/melrose/notify" -) - -type Collect struct { - Target HasValue - Replaceable HasValue - Each Sequenceable -} - -func (c Collect) S() Sequence { - tv := c.Target.Value() - t, ok := tv.(HasSequenceables) - if !ok { - notify.Warnf("target does not have sequences") - return EmptySequence - } - rv := c.Replaceable.Value() - r, ok := rv.(Replaceable) - if !ok { - notify.Warnf("function does not allow replacement") - return EmptySequence - } - targets := make([]Sequenceable, len(t.Sequenceables())) - for i, each := range t.Sequenceables() { - targets[i] = r.Replaced(c.Each, each) - } - return SequenceableList{Target: targets}.S() -} - -func (c Collect) Storex() string { - var b bytes.Buffer - fmt.Fprintf(&b, "collect(%s,%s)", Storex(c.Target), Storex(c.Replaceable)) - return b.String() -} diff --git a/core/map.go b/core/map.go new file mode 100644 index 0000000..2d0e0c2 --- /dev/null +++ b/core/map.go @@ -0,0 +1,59 @@ +package core + +import ( + "bytes" + "fmt" + + "github.com/emicklei/melrose/notify" +) + +type Map struct { + Target HasValue + Replaceable HasValue + Each Sequenceable +} + +func (c Map) S() Sequence { + return SequenceableList{Target: c.Sequenceables()}.S() +} + +func (c Map) Storex() string { + var b bytes.Buffer + fmt.Fprintf(&b, "map(%s,%s)", Storex(c.Target), Storex(c.Replaceable)) + return b.String() +} + +func (c Map) Sequenceables() []Sequenceable { + tv := c.Target.Value() + t, ok := tv.(HasSequenceables) + if !ok { + notify.Warnf("target does not have sequences") + return []Sequenceable{} + } + rv := c.Replaceable.Value() + r, ok := rv.(Replaceable) + if !ok { + notify.Warnf("function does not allow replacement") + return []Sequenceable{} + } + targets := make([]Sequenceable, len(t.Sequenceables())) + for i, each := range t.Sequenceables() { + targets[i] = r.Replaced(c.Each, each) + } + return targets +} + +func (c Map) Replaced(from, to Sequenceable) Sequenceable { + if from == Sequenceable(c) { + return to + } + newTarget := c.Target + if t, ok := c.Target.Value().(Replaceable); ok { + newTarget = On(t.Replaced(from, to)) + } + newReplaceable := c.Replaceable + if r, ok := c.Replaceable.Value().(Replaceable); ok { + newReplaceable = On(r.Replaced(from, to)) + } + return Map{Target: newTarget, Replaceable: newReplaceable, Each: c.Each} +} diff --git a/core/utils.go b/core/utils.go index 5c4f04b..45023af 100644 --- a/core/utils.go +++ b/core/utils.go @@ -121,3 +121,19 @@ func ContainsInt(list []int, value int) bool { } return false } + +func ReplacedAll(target []Sequenceable, from, to Sequenceable) []Sequenceable { + newTarget := []Sequenceable{} + for _, each := range target { + if IsIdenticalTo(each, from) { + newTarget = append(newTarget, to) + } else { + if other, ok := each.(Replaceable); ok { + newTarget = append(newTarget, other.Replaced(from, to)) + } else { + newTarget = append(newTarget, each) + } + } + } + return newTarget +} diff --git a/dsl/eval_funcs.go b/dsl/eval_funcs.go index 411e37b..dfef8d4 100644 --- a/dsl/eval_funcs.go +++ b/dsl/eval_funcs.go @@ -1290,13 +1290,14 @@ onkey('c4',onoff('e')) // uses default input and default output MIDI device`, }, }) - registerFunction(eval, "collect", Function{ - Title: "Collect function", - Description: "collect will map each sequence of a collection using a function that references a replacement", - Template: "collect(${1:collection},${2:function-with-underscore})", + registerFunction(eval, "map", Function{ + Title: "Map function", + Description: "map will collect tranformations of each sequence of a collection using a function that references a replacement", + Template: "map(${1:collection},${2:function-with-underscore})", + Alias: "collect", Samples: `j = join(sequence('C E G'),sequence('D F A')) // uses the special variable named "_" - c = collect(j, transpose(1, _ ))`, + c = map(j, transpose(1, _ ))`, Func: func(collection any, function any) any { if _, ok := getValue(collection).(core.HasSequenceables); !ok { return notify.Panic(errors.New("collection must have sequenceables")) @@ -1305,7 +1306,7 @@ onkey('c4',onoff('e')) // uses default input and default output MIDI device`, return notify.Panic(errors.New("function must allow replacement")) } each, _ := ctx.Variables().Get("_") - return core.Collect{ + return core.Map{ Target: core.On(collection), Replaceable: core.On(function), Each: each.(core.Sequenceable), // todo check diff --git a/dsl/evaluator.go b/dsl/evaluator.go index 6c081bd..307ea14 100644 --- a/dsl/evaluator.go +++ b/dsl/evaluator.go @@ -244,8 +244,8 @@ func (e *Evaluator) handleAssignment(varName string, r interface{}) (interface{} // The result is either FunctionResult or a "raw" Go object. func (e *Evaluator) EvaluateExpression(entry string) (interface{}, error) { options := []expr.Option{} - // since 1.14.3 - for _, each := range []string{"join", "repeat", "trim", "replace", "duration"} { + // since expr 1.14.3 + for _, each := range []string{"join", "repeat", "trim", "replace", "duration", "map"} { options = append(options, expr.DisableBuiltin(each)) } env := envMap{} diff --git a/dsl/evaluator_test.go b/dsl/evaluator_test.go index e316589..3e9a011 100644 --- a/dsl/evaluator_test.go +++ b/dsl/evaluator_test.go @@ -265,28 +265,28 @@ func TestEuclidean(t *testing.T) { } } -func TestCollecFraction(t *testing.T) { +func TestMapFraction(t *testing.T) { e := newTestEvaluator() r, err := e.EvaluateProgram(` - c = collect(join(note('e')), fraction(8,_)) + c = map(join(note('e')), fraction(8,_)) `) checkError(t, err) - if got, want := r.(core.Collect).Storex(), "collect(join(note('E')),fraction(8,_))"; got != want { + if got, want := r.(core.Map).Storex(), "map(join(note('E')),fraction(8,_))"; got != want { t.Errorf("got [%v:%T] want [%v:%T]", got, got, want, want) } - if got, want := r.(core.Collect).S().Storex(), "sequence('8E')"; got != want { + if got, want := r.(core.Map).S().Storex(), "sequence('8E')"; got != want { t.Errorf("got [%v:%T] want [%v:%T]", got, got, want, want) } } -func TestCollecTranspose(t *testing.T) { +func TestMapTranspose(t *testing.T) { e := newTestEvaluator() r, err := e.EvaluateProgram(` - c = collect(join(note('e')), transpose(1,_)) + c = map(join(note('e')), transpose(1,_)) `) checkError(t, err) - if got, want := r.(core.Collect).S().Storex(), "sequence('F')"; got != want { + if got, want := r.(core.Map).S().Storex(), "sequence('F')"; got != want { t.Errorf("got [%v:%T] want [%v:%T]", got, got, want, want) } } diff --git a/op/util.go b/op/util.go index dbfa94d..b8ec365 100644 --- a/op/util.go +++ b/op/util.go @@ -57,20 +57,9 @@ func parseIndices(src string) [][]int { return ii } +// depreacted: use core.ReplacedAll func replacedAll(target []core.Sequenceable, from, to core.Sequenceable) []core.Sequenceable { - newTarget := []core.Sequenceable{} - for _, each := range target { - if core.IsIdenticalTo(each, from) { - newTarget = append(newTarget, to) - } else { - if other, ok := each.(core.Replaceable); ok { - newTarget = append(newTarget, other.Replaced(from, to)) - } else { - newTarget = append(newTarget, each) - } - } - } - return newTarget + return core.ReplacedAll(target, from, to) } // "1 (4 5 6) 2 (4 5 6) 3 (4 5 6) 2 (4 5 6)"