grammar Clef rule statement assignment / expression end rule expression additive end rule assignment channel space '=' space expression { def evaluate(env) env.play(channel.evaluate(env).to_i, expression.evaluate(env)) end } end rule additive operand1:multitive space operator:additive_operator space operand2:additive { def evaluate(env) operator.apply(operand1.evaluate(env), operand2.evaluate(env)) end } / multitive end rule additive_operator '+' { def apply(a, b) a + b end } / '-' { def apply(a, b) a - b end } end rule multitive operand1:primary space operator:multitive_operator space operand2:multitive { def evaluate(env) operator.apply(operand1.evaluate(env), operand2.evaluate(env)) end } / primary end rule multitive_operator '*' { def apply(a, b) a * b end } / '/' { def apply(a, b) a / b end } / '&' { def apply(a, b) a & b end } end rule primary sequence / integer / channel / '(' space expression space ')' { def evaluate(env) expression.evaluate(env) end } end rule sequence '[' playables ']' { def evaluate(env) Clef::Sequence.new(playables.evaluate(env)) end } end rule key [A-Ga-g] { def evaluate(env) text_value end } end rule accent ('-' / '#') { def evaluate(env) text_value end } end rule integer '-'? [0-9]+ { def evaluate(env) text_value.to_i end } end rule octave [0-9] { def evaluate(env) text_value.to_i end } end rule note key accent octave { def evaluate(env) Clef::Note.new( key.evaluate(env), accent.evaluate(env), octave.evaluate(env)) end } / rest end rule notes note space notes { def evaluate(env) [ note.evaluate(env), notes.evaluate(env) ].flatten end } / note end rule rest '_'+ { def evaluate(env) Clef::Rest.new end } end rule harmony '(' space notes space ')' { def evaluate(env) Harmony.new(notes.evaluate(env)) end } end rule playable note / harmony end rule playables playable space playables { def evaluate(env) [ playable.evaluate(env), playables.evaluate(env) ].flatten end } / playable end rule channel_number '0' / '1' / '2' / '3' / '4' / '5' / '6' / '7' / '8' / '9' / '10' / '11' / '12' / '13' / '14' / '15' end rule channel '@' channel_number { def evaluate(env) env.channels[channel_number.text_value.to_i] end } end rule space ' '* end end