Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lady Red / Christopher Beacham - A Medieval DSL...

Lady Red / Christopher Beacham - A Medieval DSL? Parsing Heraldic Blazons with Python!

Medieval European Nobility was obsessed with Lineage. They created a Heraldic System to track families, which assigned each family a unique Coat of Arms.

Any painting of the Coat of Arms was not the official version. The official version was a "Blazon" - a precise, terse description in heraldic language. This heraldic language reads like English, Latin, French, and XML had a baby. It's a fully recursive language with a formal grammar, variable assignment, positional arguments, and also, Lions, Bears, and Pythons.

Here's an example: Sable, on a fesse or three lions gules

In this talk, we look at parsing this Medieval Domain Specific Language with Python. Along the way, we'll learn a little history, and the tools for parsing and writing your own DSL.

https://us.pycon.org/2019/schedule/presentation/157/

PyCon 2019

May 04, 2019
Tweet

More Decks by PyCon 2019

Other Decks in Programming

Transcript

  1. BLAZON FOR UK ▸ Quarterly, First and Fourth Gules three

    lions passant guardant in pale Or armed and langued Azure (for England), Second quarter Or a lion rampant within a double tressure flory counter-flory Gules (for Scotland), Third quarter Azure a harp Or stringed Argent (for Ireland), the whole surrounded by the Garter; for a Crest, upon the Royal helm the imperial crown Proper, thereon a lion statant guardant Or imperially crowned Proper; Mantling Or and ermine; for Supporters, dexter a lion rampant guardant Or crowned as the Crest, sinister a unicorn Argent armed, crined and unguled Proper, gorged with a coronet Or composed of crosses patée and fleurs de lys a chain affixed thereto passing between the forelegs and reflexed over the back also Or; Motto 'Dieu et mon Droit' in the compartment below the shield, with the Union rose, shamrock and thistle engrafted on the same stem.
  2. ▸ Arms are heritable the way land is, not the

    way a name is. Don’t get tricked by scammy websites! You likely have not inherited arms unless you also have a castle. ▸ Rules vary from country to country and across time ▸ Blazon is a remarkably consistent and rule-based language, CONSIDERING ▸ It was written over a span of 500 years ▸ in the High Middle Ages ▸ by groups constantly at war with each other. ▸ I have SIMPLIFIED somewhat (a lot)
  3. of the field and Or, the sinister inverted Azure, Two

    serpents erect addorsed entwined,
  4. Let’s Start Parsing! ▸ We’ll start trying to build a

    parser for Blazon ▸ Plenty of python parsers - ▸ ANTLR / Lrparsing / PLY / Pyleri … MANY more! ▸ Lark is our parser library ( github.com/lark-parser/lark ) ▸ Easy interface ▸ Several parser implementations with different characteristics ▸ Rules are in Backus-Naur form (BNF), which is pretty standard ▸ Supports left recursive rules ▸ Good documentation
  5. from lark import Lark l = Lark('''LCASE_LETTER: "a".."z" UCASE_LETTER: "A".."Z"

    LETTER: UCASE_LETTER | LCASE_LETTER WORD: LETTER+ start: WORD "," WORD "!" %ignore " " // Disregard spaces in text ''') print( l.parse("Hello, World!") ) Tree(start, [Token(WORD, 'Hello'), Token(WORD, 'World')])
  6. Parsing Tinctures COLOUR: "Azure"i // Blue | "Gules"i // Red

    | "Purpure"i // Purple | "Sable"i // Black | "Vert"i // Green | "Proper"i // Natural METAL: “Or"i // Gooooold | "Argent"i // Silver or White tincture: METAL | COLOUR
  7. Furs fur: ERMINE | VAIR | fur tincture AND tincture

    | tincture INFIX_FUR tincture // Stoat Fur design (black and white spots). ERMINE: "Ermine"i | "Ermines"i | "Erminois"i | "Pean"i VAIR: "Vairy"i | "Vair"i // Bell-shaped pattern | "Potent"i // Tetris T's alternating | “Counter-Potent"i // Pluses alternating INFIX_FUR: "Ermined"i AND: "And"i tincture: METAL | COLOUR | fur
  8. Heraldic Abstract Syntax Tree (HaST) Vairy or and gules start

    arms field tincture fur fur vair tincture or and tincture gules
  9. Ordinaries ORDINARY: "Bend"i // Diagonal Stripe | "Chevron"i // Check

    mark | "Chief"i // Stripe on top | "Fesse"i | "Fess"i // Horizontal Stripe | "Pale"i // Vertical Stripe | "Saltire"i // Giant X | "Cross"i // Cross Source: Wikipedia
  10. Subordinaries SUBORDINARY: "Pall"i | "Pile"i | "Pile reversed"i | "Quarter"i

    // square on the upper left, can have a recursive coat | "Canton "i | "Bordure"i | "Border"i | "Orle"i | "Bars"i | “Fret”i | “Escrutcheon” // Mini shield! | "Flaunches"i | "Label"i | "Gyron"i | "Gore"i // Looks like a flipping page | "Dance"i // Wavey line // variations on diamonds | "Lozenge"i | "Fusil"i | "Mascle"i // ball or circle - variants denote color variations | "Roundel"i | “Annulet"i | "Bezant"i | “Hurt"i | "Billet"i // vertical rectangle … Lots more
  11. Argent; on a saltire gules five rustres argent, in chief

    a lion rampant of the second Ermine, on bend azure 3 mullets or Arms of Dalrymple of Woodhead, Scotland
  12. ordinary: ORDINARY | SUBORDINARY ordinary_charge: number? tincture? ordinary "s"? tincture?

    arrangement? ON: "on"i | "in"i | "all in"i | “within”i | “charged with” | “charged on”i | “each charged of”i charge_group: charge_group AND charge_group | charge_group “,”? ON subgroup | ON charge_group subgroup subgroup: charge_group arms: field | field “,”? charge_group | charge_group
  13. start arms field tincture Argent charge_group charge_group charge_group charge number

    a ordinary saltire attitude general_attitude tincture Gules relation charged of subgroup charge_group charge number five object escutcheon attitude general_attitude tincture Azure relation charged each of subgroup charge_group charge numberfive ordinary bezant attitude general_attitude tincture Argent arrangement Argent, a saltire Gules, charged of five escutcheons Azure, charged each of five bezants Argent, set in cross. Arms of Dukes of Braganza (Portugal)
  14. ANIMALS / Objects animal: HUMAN | BEAST | BIRD |

    REPTILE HUMAN: "Man"i | "Men"i | "Old Man"i BEAST: "Lion"i | "Wolf"i | "Leopard"i | "Bear"i | "Bull"i | "Calf"i | "Buck"i | "Stag"i | "Dog"i | "Cat"i | “Sea-lion"i | "Cockatrice"i BIRD: "Eagle"i | "Martlet"i | "Swan"i | "Raven"i REPTILE: "Serpent"i | "Firedrake"i | "Salamander"i | “Wyvern”i OBJECT: “Harp”i | “Fleur-de-lis”i … And so on, forever for a million objects, tools, individual monsters, legendary buildings, etc
  15. ATTITUDE attitude: "Rampant"i // Standing on it's hind legs! |

    "Passant"i // Walking, one upraised arm | "Couchant"i // Sitting like a sphinx | "Gardant"i | "Guardant"i // With head facing the viewer | "Regardant"i // With head facing behind itself | "Coward"i // Tail between legs | "Running"i | "Sejant"i // Seated | "Salient"i // Leaping | "Dormant"i // Sleeping | "Demi-"i // only the front half of an animal | "Muzzled"i | "Combatant"i // Facing each other | "Addorsed"i // Facing away from each other | "Tripping"i | "Leaping"i | "Swimming"i | "Volant"i // soaring | "Double-headed"i // two headed! cool | "Erect"i | attitude AND attitude charge: number? attitude* _charge_focus "s"? attitude*
  16. Quarterly Sable and Gules Arms of Royal House of HohenZollern

    Arms of Castile and León Quarterly: 1 and 4 Castile, 2 and 3 León Castile: Gules a triple-towered castle Or masoned Sable and ajoure Azure León: Argent a lion rampant purpure, langued and armed gules crowned or
  17. Quartering field: tincture | lines arms: field | field ","

    charge_group | field charge_group | charge_group quarter: (num (AND num)? arms ) COMMENT? “,"? lines: “Quarterly"i ["of"i num] “:”? quarter+ | "Quarterly"? "Per"i ordinary_charge quarter+ Marshalled Arms of European Union
  18. start arms field lines quarter num first and num fourth

    arms field lines arms field tincture Gules charge num three animal Lion attitude passant attitude gardant ordinary_charge ordinary pale ordinary_attitude general_attitude tincture Or attitude accessory accessory armed and accessory langued tincture Azure (for England) Quarterly, first and fourth Gules three Lions passant gardant in pale Or armed and langued Azure (for England), second quarter Or a Lion rampant within a double tressure flory-counter-flory Gules (for Scotland), third quarter Azure a Harp Or stringed Argent (for Ireland) Arms of UK (In England)
  19. quarter num second arms field lines arms field tincture Or

    charge num a animal Lion attitude rampant ordinary_charge num number ordinary tressure ordinary_attitude general_attitude tincture variation multipattern flory-counter-flory field tincture Gules (for Scotland) Quarterly, first and fourth Gules three Lions passant gardant in pale Or armed and langued Azure (for England), second quarter Or a Lion rampant within a double tressure flory-counter-flory Gules (for Scotland), third quarter Azure a Harp Or stringed Argent (for Ireland) Arms of UK (In England)
  20. quarter num third arms field tincture Azure charge num number

    a object Harp attitude attitude attitude general_attitude tincture Or attitude accessory stringed attitude general_attitude tincture Argent (for Ireland) Quarterly, first and fourth Gules three Lions passant gardant in pale Or armed and langued Azure (for England), second quarter Or a Lion rampant within a double tressure flory-counter-flory Gules (for Scotland), third quarter Azure a Harp Or stringed Argent (for Ireland) Arms of UK (In England)
  21. Sable, bend Or Sable, bend gules TINCTURE ON TINCTURE NOT

    ALLOWED! Rule of Tincture METAL ON TINCTURE ALLOWED!
  22. Or, an eagle displayed Sable armed beaked and langued Gules

    Argent, a cross potent between four plain crosslets Or METAL ON METAL NOT ALLOWED! TINCTURE ON METAL - ALLOWED! Arms of Kingdom of Jerusalem (11th Century) Arms of Germany (Contemporary)
  23. Rule of Tincture ▸ No metal may be on metal,

    no tincture on tincture ▸ Textured/varied fields can have anything on them ▸ “Proper” charges can be on anything ▸ Applies to some ordinaries but not field divisions ▸ More prominent in some countries (Scotland) than others (France)
  24. Blazon Parse Tree Abstract Syntax Tree PARSE SIMPLIFY VALIDATE /

    BUILD RENDER Native Representation (Python Object) Output Image!
  25. Blazon Parse Tree Abstract Syntax Tree PARSE SIMPLIFY VALIDATE /

    BUILD RENDER Native Representation (Python Object) Output Image! Didn’t Do This Part (Yet)
  26. Python Grammer if_stmt: 'if' test ':' suite ('elif' test ':'

    suite)* ['else' ':' suite] while_stmt: 'while' test ':' suite ['else' ':' suite] https://docs.python.org/3/reference/grammar.html
  27. Python Grammer if_stmt: 'if' test ':' suite ('elif' test ':'

    suite)* ['else' ':' suite] while_stmt: 'while' test ':' suite ['else' ':' suite] suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT test: or_test ['if' or_test 'else' test] | lambdef or_test: and_test ('or' and_test)* and_test: not_test ('and' not_test)* not_test: 'not' not_test | comparison comparison: expr (comp_op expr)* https://docs.python.org/3/reference/grammar.html
  28. Python Grammer stmt: simple_stmt | compound_stmt simple_stmt: small_stmt (';' small_stmt)*

    [';'] NEWLINE small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt) compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt https://docs.python.org/3/reference/grammar.html
  29. Python Grammer classdef: 'class' NAME ['(' [arglist] ')'] ':' suite

    simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt) compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt https://docs.python.org/3/reference/grammar.html
  30. QUESTIONS? Arms Of Zheleznogorsk (Russian Plutonium Production Town) Learn More!

    Drawshield.net Great resource - can fully render a coat of arms from a blazon! 
 Reddit’s /r/heraldry Active community around Heraldry. Holds monthly contests Wikipedia Very complete and readable coverage of blazon and all aspects of Heraldry Really Old Books You’re ultimately going to need to read a lot of very old books on heraldry as soon as you try to do anything complicated