Files
ziffers-python/ziffers/spec/ziffers.lark

93 lines
3.2 KiB
Plaintext

// Root for the rules
?root: sequence -> start
sequence: (pitch_class | repeat_item | assignment | variable | rest | dur_change | oct_mod | oct_change | WS | chord | named_roman | cycle | random_integer | random_pitch | random_percent | range | list | repeated_list | lisp_operation | list_op | subdivision | eval | euclid | repeat)*
// Pitch classes
pitch_class: prefix* pitch
prefix: (octave | duration_chars | escaped_decimal | escaped_octave | modifier)
pitch: /-?[0-9TE]/
escaped_decimal: "<" decimal ">"
escaped_octave: /<-?[0-9]>/
octave: /[_^]+/
modifier: /[#b]/
// Variable assignment
assignment: variable ass_op (list | pitch_class | random_integer | random_pitch | cycle | list_op)
ass_op: /[=~]/
variable: /[A-Z]/
// Durations
// TODO: Refactor dchar as: /([mklpdcwyhnqaefsxtgujzo](\.)*)(?=\d)/
duration_chars: dotted_dur+
dotted_dur: dchar dot*
decimal: /-?[0-9]+\.[0-9]+/
dchar: /[mklpdcwyhnqaefsxtgujzo]/
dot: "."
rest: rest_duration? "r"
// TODO: Refactor (\.)* when other durchars uses lookaheads
rest_duration: /([mklpdcwyhnqaefsxtgujzo])(?=r)/
// Chords
chord: pitch_class pitch_class+
named_roman: roman_number (("^" chord_name))? // TODO: Add | ("+" number)
chord_name: /[a-zA-Z0-9]+/
?roman_number: /iv|v|v?i{1,3}/
// Valid as integer
number: NUMBER | random_integer | cycle
// CYCLIC NUMBERS NOT IN USE. NUMBERS MUST BE VALIDATED FROM FULL CYCLES!
// cyclic_number: "<" number (WS number)* ">"
// Repeats
repeat: "[:" sequence ":" [number] "]"
repeat_item: (pitch_class | list | random_integer | cycle | rest | subdivision) ":" number
// List
list: prefix* "(" sequence ")"
repeated_list: prefix* "(:" sequence ":" [number] ")"
// Right recursive list operation
list_op: list (operator right_op)+
right_op: list | number
operator: /([\+\-\*\/%\|\&]|<<|>>)/
// Euclidean cycles
// TODO: Support randomization etc.
//euclid_operator: (">" | "<") number "," number ["," number] (">" | "<")
euclid: list euclid_operator list?
?euclid_operator: /<[0-9]+,[0-9]+(,[0-9])?>/
// Lisp like list operation
lisp_operation: "(" operator WS sequence ")"
// Subdivision
subdivision: "[" subitems "]"
subitems: (pitch_class | random_integer | random_pitch | rest | oct_mod | oct_change | WS | chord | named_roman | cycle | subdivision | list | list_op | range)*
// Control characters modifying future events
oct_mod: octave WS
oct_change: escaped_octave WS
dur_change: (decimal | char_change)
char_change: dchar_not_prefix+
dchar_not_prefix: /([mklpdcwyhnqaefsxtgujzo](\.)*)(?![\dr])/
// Generative rules
random_integer: /\(-?[0-9]+,-?[0-9]+\)/
range: /-?[0-9]+\.\.-?[0-9]+/
cycle: "<" sequence ">"
random_pitch: /(\?)(?!\d)/
random_percent: /(%)(?!\d)/
// Rules for evaluating clauses inside {}
// TODO: Support for parenthesis?
eval: "{" operation+ "}"
operation: atom (operator (sub_operations | operation))*
sub_operations: "(" operation ")"
atom: (NUMBER | DECIMAL)
%import common.NUMBER
//%import common.SIGNED_NUMBER
%import common.DECIMAL
%import common.WS