Translating Lexurgy to tadpole

This chapter is based on the Lexurgy Cheatsheet and shows how to translate various Lexurgy constructs into tadpole. Lexurgy constructs are shown on the left, and the corresponding tadpole construct on the right. Titles on each column show the corresponding Lexurgy and tadpole terminology if there is a difference.

Getting Lexurgy Defaults

To get behavior close to that of Lexurgy, some configuration needs to be added that is not implicit in tadpole:

Basics

Comment
# this is a comment
// this is a comment
/* this is a block comment */
Simple ChangeSimple Rule
ɔ => ɑ
'ɔ' -> 'ɑ';
ConditionEnvironment
k => ʃ / a _ a
'k' -> 'ʃ' in 'a' _ 'a';
Exception
k => ʃ // a _ a
'k' -> 'ʃ' except 'a' _ 'a';
Condition and ExceptionEnvironments
k => ʃ / _ a // a _
'k' -> 'ʃ' in _ 'a' except 'a' _;
Word Beginning
k => kʰ / $ _
'k' -> 'kʰ' in # _;
Word End
a => ə / _ $
'a' -> 'ə' in _ #;
Insertion
* => e / $ _ s
() -> 'e' in # _ 's';
Deletion
h => *
'h' -> ();
Collapsing Alternatives
{p, t, k} => ʔ
'p' | 't' | 'k' -> 'ʔ';
Corresponding Alternatives
{p, t, k} => {b, d, ɡ}
('p' | 't' | 'k')@i -> ('b' | 'd' | 'ɡ')@i;
Alternative EnvironmentsMultiple Environments
k => ʃ / {_ a, a _}
'k' -> 'ʃ' in _ 'a' or 'a' _;
Sound ClassClass Matcher
class stop {p, t, k}
rule:
  @stop => ʔ
class stop = 'p' 't' 'k';
rule _rule = stop -> 'ʔ';
Corresponding Sound ClassesClass Replacer
class stop {p, t, k}
class fricative {f, θ, x}
rule:
  @stop => @fricative
class stop = 'p' 't' 'k';
class fricative = 'f' 'θ' 'x';
rule _rule = stop@i -> fricative@i;
Wildcard
[] => x
. -> 'x';
Multi-character SymbolSymbol Definition
Symbol ts, dz
symbol 'ts' = [];
symbol 'dz' = [];
segmentation symbol;
Note: Can also be implemented with classes, symbol definitions are more appropriate when using features.
Escape
\*
not applicable; symbols are always quoted

Combining Elements

Sequence
n k => ŋ ɡ
'n' 'k' -> 'ŋ' 'ɡ';
Optional Element
a => ə / _ @consonant? $
'a' -> 'ə' in _ consonant? #;
Grouping
(@consonant @vowel)?
(consonant vowel)?
Repeated Element
Any Number
@consonant*
consonant*
Repeated Element
At Least One
@consonant+
consonant+
Repeated Element
Exact Number
@consonant*2
consonant{2}
Repeated Element
Range
@consonant*(2-4)
consonant{2-4}
Repeated Element
Maximum Number
@consonant*(-4)
consonant{0-4}
Repeated Element
Minimum Number
@consonant*(2-)
not available, use a range with any
reasonably large maximum
CaptureContent Binding
@consonant$1 => * / _ $1
(consonant)@_1 -> () in _ <_1>;
Note: When used as a matcher, use exact match <_1>(!) to replicate Lexurgy behavior.
Negation
!@consonant
!consonant
IntersectionConjunction
@stop&@alveolar
stop & alveolar
Negated IntersectionConjunction with Negation
@stop&!@alveolar
stop & !alveolar
UnchangedNo-Op Rule
rule:
  unchanged
rule _rule = !() -> ();
Note: No dedicated syntax in tadpole. Shown is a typical non-matching rule
Word BoundaryBetween Words
$$ => *
## -> ();

Control Flow

Simultaneous ExpressionSimultaneous Rule
rule:
  ɔ => ɑ
  ɑ => a
  rule _rule = {
    'ɔ' -> 'ɑ';
    'ɑ' -> 'a';
  }
Sequential BlockSequential Rule
rule:
  ɔ => ɑ
  then:
  ɑ => a
rule _rule = {
  'ɔ' -> 'ɑ';
  then
  'ɑ' -> 'a';
}
Hierarchical BlockFallback Rule
rule:
  @vowel => [+hightone] / {p, t, k} _
  else:
  @vowel => [+hightone] / $ @consonant _
rule _rule = {
  (vowel)@s -> [+hightone]@s in ('p'|'t'|'k') _;
  else
  (vowel)@s => [+hightone]@s in # consonant _;
}
Propagating RuleConverging Rule
rule propagate:
  aa => a
rule _rule = #{converging}{
  'a' 'a' -> 'a';
}
Left-to-Right Rule
rule ltr:
  ea => e
rule _rule = #{ltr} {
  'e' 'a' -> 'e';
}
Right-to-Left Rule
rule rtl:
  ae => e
rule _rule = #{rtl} {
  'a' 'e' -> 'e';
}
FilterFilter Rule
rule @vowel:
  a => e / _ i
rule _rule = #{filter vowel} {
  'a' -> 'e' in _ 'i';
}
Reusable ElementMacro
element scluster s @stop
rule:
  * => e / _ @scluster
macro matcher scluster = 's' stop;
rule _rule = () -> 'e' in _ $scluster;
Deferred RuleRule Macro
assim defer:
  @nasal => m / _ {p, b}
rule:
  :assim
macro rule assim = nasal -> 'm' in _ ('p'|'b');
rule _rule = $assim;
Cleanup RuleHook Rule
assim cleanup:
  @nasal => m / _ {p, b}
hooks post add {
  rule assim = nasal -> 'm' in _ ('p'|'b');
}
Cleanup OffDisabling Hook Rules
assim:
  off
hooks disable assim;
DeromanizerInput
deromanizer:
  kh => x
input deromanizer = "kh" -> 'x';
Literal DeromanizerInput with Segmentation
deromanizer literal:
  ʼ => ʔ
  then:
  k => kʼ
input deromanizer ={
  segmentation clear;
  rule = {
    'ʼ' -> 'ʔ';
    then
    'k' -> 'k' 'ʼ';
  }
  resegment = true;
}
Note: Semantics don’t fully match, additional scope annotations may be necessary for fully equivalent construct.
RomanizerOutput
romanizer:
  x => kh
output romanizer = 'x' -> 'kh';
Literal RomanizerOutput
Typically not applicable, may be equivalent to scope annotations on part of an output rule in some cases.
Intermediate RomanizerOutput
romanizer-some-name:
  x => kh
output some_name = 'x' -> 'kh';

Features

Binary FeatureFeature Definition
feature low, high
rule:
  [-low -high] => [+high] / _ $
feature low = +low -low;
feature high = +high -high;
rule _rule = [-low -high] => [+high] in _ #;
Note: Explicitly named default value may be required to fully match behavior
Univalent FeatureFeature Definition
feature +lateral
rule:
  [+lateral] => [-lateral] / _ $
feature lateral = +lateral -lateral
  default -lateral;
rule _rule = [+lateral]@f -> [-lateral]@f in _ #;
Multivalent FeatureFeature Definition
feature place(labial, alveolar, velar)
rule:
  [labial] => [alveolar] / _ $
feature place = labial alveolar velar;
rule _rule = [labial]@f -> [alveolar]@f / _ $
Feature VariableFeature Binding
[stop] => [$voicing] / _ [stop $voicing]
[stop]@f => [<v>]@f in _ [stop voicing@v];
Named Absent ValueDefault Value
feature tone(*lowtone, hightone)
feature tone = lowtone hightone
  default lowtone;
Negated Feature Value
[!labial]
[!labial]
DiacriticModifier
Diacritic ˈ [+ejective]
modifier 'ˈ' = [+ejective];
Diacritic, BeforeModifier, Before Position
Diacritic ⁿ (before) [+prenasalized]
modifier (before) 'ⁿ' = [+prenasalized];
Diacritic, After FirstModifier, At Position
Diacritic  ́ (first) [+hightone]
modifier (at 1) '\u{301}' = [+hightone];
Note: tadpole can also specify combining marks directly, but recommends using unicode escapes.
Floating DiacriticSoft Modifier
Diacritic  ́ (floating) [+hightone]
modifier (soft) '\u{301}' = [+hightone];
Exact MatchStrict Match
e!
'e'(!)
Inexact Capture ReferenceBinding Matcher
~$1
// for matchers
<_1>
// for replacers
<_1>(~)

Note: Default behavior of tadpole binding matchers matches this construct; Use <_1>(!) to replicate behavior of Lexurgy $1.

When used as replacer, use <_1>(~) to remove soft modifiers.

Syllables

Explicit Syllables
syllables:
  explicit
syllables explicit;
Syllable Boundary
n => * / _ .
'n' -> () in _ ^;
Negated Syllable Boundary
i => j / _ !. @vowel
'i' -> 'j' in _ !^ & vowel;
Note: Negated matchers always cover one symbol in tadpole, requiring slight modification.
Syllable ElementSyllable Matcher
<syl> => * / _ <syl> $
syl -> () in _ syl #;
Simple Automatic SyllablesAutomatic Syllables
syllables:
  @cons? @vowel @cons?
syllables match cons? vowel cons?;
Structured Automatic SyllablesAutomatic Syllables
syllables:
  @cons? :: @vowel :: @cons?
syllables match cons? vowel :> cons?;
Reluctant OnsetAutomatic Syllables
syllables:
  @cons? ?: @cons? :: @vowel :: @cons?
syllables match cons? <: cons? vowel :> cons?;
Clearing Syllables
syllables:
  clear
syllables clear;
Syllable-Level FeatureSyllable Feature
feature (syllable) +stress
syllables feature stress = +stress -stress
  default -stress;
Automatic Feature AssignmentIntrinsic Syllable Feature
syllables:
  @cons? :: @vowel :: @cons => [+heavy]
syllables = {
  match cons? vowel cons = [[+heavy]];
}