mirror of
https://github.com/alda-lang/alda.git
synced 2026-03-03 18:23:36 +01:00
This provides filename/line/column context for any error I could possibly find. To achieve this, I made it so that all ScoreUpdates have source context, so when updating the score results in an error, we can print out the line and column number corresponding to the error. It's a bit more complicated than that, because score updates are nestable (e.g. event sequences can contain cram expressions can contain chords, etc.), which essentially gives us a stacktrace whenever a score update results in an error. I punted on giving the user the full stacktrace, in favor of doing something simpler and just showing the bottom-most error, because that's probably going to be the line and column number that's the most helpful.
75 lines
1.8 KiB
Go
75 lines
1.8 KiB
Go
package model
|
|
|
|
import (
|
|
"alda.io/client/json"
|
|
"github.com/mohae/deepcopy"
|
|
)
|
|
|
|
// A Repeat expression repeats an event a number of times.
|
|
type Repeat struct {
|
|
SourceContext AldaSourceContext
|
|
Event ScoreUpdate
|
|
Times int32
|
|
}
|
|
|
|
// GetSourceContext implements HasSourceContext.GetSourceContext.
|
|
func (repeat Repeat) GetSourceContext() AldaSourceContext {
|
|
return repeat.SourceContext
|
|
}
|
|
|
|
// JSON implements RepresentableAsJSON.JSON.
|
|
func (repeat Repeat) JSON() *json.Container {
|
|
return json.Object(
|
|
"type", "repeat",
|
|
"value", json.Object(
|
|
"event", repeat.Event.JSON(),
|
|
"times", repeat.Times,
|
|
),
|
|
)
|
|
}
|
|
|
|
// UpdateScore implements ScoreUpdate.UpdateScore by repeatedly updating the
|
|
// score with an event a specified number of times.
|
|
func (repeat Repeat) UpdateScore(score *Score) error {
|
|
for repetition := int32(1); repetition <= repeat.Times; repetition++ {
|
|
for _, part := range score.CurrentParts {
|
|
part.currentRepetition = repetition
|
|
}
|
|
|
|
if err := score.Update(repeat.Event); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DurationMs implements ScoreUpdate.DurationMs by returning the total duration
|
|
// of the event being repeated the specified number of times.
|
|
func (repeat Repeat) DurationMs(part *Part) float64 {
|
|
durationMs := 0.0
|
|
|
|
for repetition := int32(1); repetition <= repeat.Times; repetition++ {
|
|
part.currentRepetition = repetition
|
|
durationMs += repeat.Event.DurationMs(part)
|
|
}
|
|
|
|
return durationMs
|
|
}
|
|
|
|
// VariableValue implements ScoreUpdate.VariableValue by returning a version of
|
|
// the repeat where the value of the event to be repeated is captured.
|
|
func (repeat Repeat) VariableValue(score *Score) (ScoreUpdate, error) {
|
|
result := deepcopy.Copy(repeat).(Repeat)
|
|
|
|
eventValue, err := repeat.Event.VariableValue(score)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result.Event = eventValue
|
|
|
|
return result, nil
|
|
}
|