diff --git a/ziffers/classes.py b/ziffers/classes.py index 9626d53..976fa3b 100644 --- a/ziffers/classes.py +++ b/ziffers/classes.py @@ -270,6 +270,16 @@ class Function(Event): run: str = field(default=None) +@dataclass(kw_only=True) +class VariableAssignment(Item): + """Class for defining variables""" + variable: str + value: Item + +@dataclass(kw_only=True) +class Variable(Item): + """Class for using variables""" + name: str @dataclass(kw_only=True) class Sequence(Meta): @@ -334,6 +344,12 @@ class Sequence(Meta): yield item else: yield from item.evaluate_tree(options) + elif isinstance(item, VariableAssignment): + options[item.variable.name] = item.value + elif isinstance(item, Variable): + if options[item.name]: + variable = options[item.name] + yield from _resolve_item(variable, options) elif isinstance(item, Range): yield from item.evaluate(options) elif isinstance(item, Cyclic): diff --git a/ziffers/mapper.py b/ziffers/mapper.py index cb96361..2204031 100644 --- a/ziffers/mapper.py +++ b/ziffers/mapper.py @@ -28,6 +28,8 @@ from .classes import ( Integer, Euclid, RepeatedSequence, + VariableAssignment, + Variable ) from .common import flatten, sum_dict from .defaults import DEFAULT_DURS, OPERATORS @@ -255,6 +257,17 @@ class ZiffersTransformer(Transformer): val = token[0].value return Atom(value=val, text=val) + + # Variable assignment + + def assignment(self, items): + var = items[0] + content = items[1] + return VariableAssignment(variable=var, value=content, text=var.text+"="+content.text) + + def variable(self, items): + return Variable(name=items[0].value, text=items[0].value) + # List rules def list(self, items): diff --git a/ziffers/spec/ziffers.lark b/ziffers/spec/ziffers.lark index ea2a5e5..56ecf01 100644 --- a/ziffers/spec/ziffers.lark +++ b/ziffers/spec/ziffers.lark @@ -1,6 +1,6 @@ // Root for the rules ?root: sequence -> start - sequence: (pitch_class | 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)* + sequence: (pitch_class | 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 @@ -11,6 +11,10 @@ octave: /[_^]+/ modifier: /[#b]/ + // Variable assignment + assignment: variable "=" (list | pitch_class | random_integer | random_pitch | cycle | list_op) + variable: /[A-Z]/ + // Durations // TODO: Refactor dchar as: /([mklpdcwyhnqaefsxtgujzo](\.)*)(?=\d)/ duration_chars: dotted_dur+