Rules

The primary component of a tadpole specification file is called a rule.

rule example = 'a' -> 'b';

It starts with the rule keyword, followed by a rule name. Note that the rule name can only contain alphanumeric characters and underscores and can not start with a digit.

After the equals sign is the rule content. The most basic rule type shown here consists of a matcher on the left side of the arrow and a replacer on the left side of the arrow, terminated by a semicolon.

This example uses a symbol matcher and a symbol replacer to find (match) all instances of a in the input word and replace them with b. Note that unlike in most other sound change engines, symbols are always explicitly delimited by single quotes.

All unicode characters are supported as symbols. To use a quote character as a symbol, escape it as '\''. If you prefer to avoid weird-looking alignment with things like combining diacritics, tadpole also supports specifying unicode codepoints as an escape sequence, so that '\u{0259}' is equivalent to 'ə'.

You can also match a sequence of other matchers by simply writing them next to each other, and the same applies to replacers.

rule sequence = 'a' 'b' -> 'c' 'd';

When combining symbols in this way, there is also the handy shortcut of using a string matcher or replacer:

rule string = "ab" -> "cd";

Rules are applied one after the other, so the following rules:

rule example1 = 'a' -> 'b';
rule example2 = 'b' -> 'c';

would result in any instances of a or b in the input to be replaced with c.

Alternatives

The result of the two rules above can actually be achieved in a single rule by using the alternative construct.

rule alternative = ('a' | 'b') -> 'c';

This will match either a or b and replace it with c in one step.

But if in the above example we wanted an a in the input become a b in the output without then being further replaced by a c, there are several ways to accomplish this in tadpole. (including swapping the order of the rules, but that would be less interesting for the tutorial)

To use alternative constructs, we could write the following:

rule alternatives = ('a' | 'b')@i -> ('b' | 'c')@i;

There are several things going on here, so let’s go step by step.

The alternative matcher 'a' | 'b' will match either a or b. Similarly, the alternative replacer 'b' | 'c' can replace the matched symbol with either b or c. However, since the replacer has multiple possible outputs, it needs to have a way of choosing which to use. This is where bindings come in.

Unlike other sound change engines, tadpole never implicitly connects matchers and replacers for this purpose, but requires you to specify named bindings for replacers which need them. In this case, the binding is named i and written as @i.

Alternative constructs generate and require index bindings, which contain information about which one of the alternative matcher’s options matched, or which one of the alternative replacer’s options to output. There are other types of bindings which we will explore in later chapters.