dotparse (empty) → 0.0.1
raw patch · 25 files changed
+3164/−0 lines, 25 filesdep +algebraic-graphsdep +basedep +bytestring
Dependencies added: algebraic-graphs, base, bytestring, chart-svg, containers, flatparse, neat-interpolation, numhask, numhask-space, optics-core, process-extras, template-haskell, text, these
Files
- dotparse.cabal +68/−0
- other/ex.svg +25/−0
- other/ex0.svg +12/−0
- other/ex1.svg +56/−0
- other/ex10.svg +22/−0
- other/ex11.svg +56/−0
- other/ex12.svg +26/−0
- other/ex13.svg +22/−0
- other/ex14.svg +62/−0
- other/ex15.svg +91/−0
- other/ex2.svg +32/−0
- other/ex3.svg +79/−0
- other/ex4.svg +49/−0
- other/ex5.svg +41/−0
- other/ex6.svg +48/−0
- other/ex7.svg +97/−0
- other/ex8.svg +93/−0
- other/ex9.svg +68/−0
- other/nh.svg +25/−0
- src/DotParse.hs +23/−0
- src/DotParse/Examples.hs +610/−0
- src/DotParse/Examples/NumHask.hs +246/−0
- src/DotParse/FlatParse.hs +226/−0
- src/DotParse/FlatParse/TH.hs +206/−0
- src/DotParse/Types.hs +881/−0
+ dotparse.cabal view
@@ -0,0 +1,68 @@+cabal-version: 2.4+name: dotparse+version: 0.0.1+synopsis: dot language parsing and printing.+description: This package provides parsing and printing of the dot language.++ .+ == Usage+ .+ >>> :set -XOverloadedLabels+ >>> :set -XOverloadedStrings+ >>> import DotParse+ >>> import Chart+ >>> import DotParse.Examples (exInt)+ >>> ex <- processGraph exInt+ >>> writeChartSvg "other/ex.svg" (graphToChartWith defaultChartConfig ex)+ .+ + .++category: project+author: Tony Day+maintainer: tonyday567@gmail.com+copyright: Tony Day (c) 2022+license: BSD-3-Clause+homepage: https://github.com/tonyday567/dotparse#readme+bug-reports: https://github.com/tonyday567/dotparse/issues+build-type: Simple+extra-doc-files: other/*.svg++source-repository head+ type: git+ location: https://github.com/tonyday567/dotparse++library+ hs-source-dirs: src+ default-extensions:+ ghc-options:+ -Wall -Wcompat -Wincomplete-record-updates+ -Wincomplete-uni-patterns -Wredundant-constraints -fwrite-ide-info+ -hiedir=.hie++ build-depends:+ , algebraic-graphs ^>=0.6+ , base >=4.7 && <5+ , bytestring ^>=0.11.3+ , chart-svg ^>=0.3+ , containers ^>=0.6+ , flatparse ^>=0.3.2+ , neat-interpolation ^>=0.5.1+ , numhask ^>=0.10+ , numhask-space ^>=0.10+ , optics-core ^>=0.4+ , process-extras ^>=0.7.4+ , template-haskell >=2.16 && < 2.20+ , text ^>=1.2+ , these ^>=1.1.1++ exposed-modules:+ DotParse+ DotParse.Examples+ DotParse.Examples.NumHask+ DotParse.FlatParse+ DotParse.FlatParse.TH+ DotParse.Types++ other-modules:+ default-language: Haskell2010
+ other/ex.svg view
@@ -0,0 +1,25 @@+<svg xmlns="http://www.w3.org/2000/svg" width="444.5569342690883" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-0.25 -489.73 435.64812 489.98012" height="500.0"><style>svg {+ color-scheme: light dark;+}+{+ .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {+ fill: #0d0d0d;+ }+ .ticklines g, .tickglyph g, .legendBorder g {+ stroke: #0d0d0d;+ }+ .legendBorder g {+ fill: #f0f0f0;+ }+}+@media (prefers-color-scheme:dark) {+ .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {+ fill: #f0f0f0;+ }+ .ticklines g, .tickglyph g, .legendBorder g {+ stroke: #f0f0f0;+ }+ .legendBorder g {+ fill: #0d0d0d;+ }+}</style><g class="chart"><g class="edges"><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 365.08,-231.92 C 369.74,-219.55 376.14,-202.55 380.83,-190.12 L 380.94,-189.83"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 345.88,-236.43 C 330.22,-222.58 304.18,-199.5500 288.4,-185.6 L 288.03,-185.27"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 352.92,-231.92 C 348.5200,-220.23 342.56,-204.4 337.96,-192.2100 L 337.85,-191.9200"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 373.16,-160.86 C 369.07,-157.94 364.48,-154.94 360.0,-152.59 C 314.22,-128.55 255.61,-110.4200 226.73,-102.2400 L 226.39,-102.15"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 380.92,-155.6200 C 376.26,-143.2600 369.86,-126.2600 365.17,-113.8300 L 365.06,-113.53"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 393.08,-155.6200 C 397.48,-143.9300 403.44,-128.11 408.04,-115.91 L 408.1500,-115.62"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 206.93,-114.5800 C 203.7400,-142.49 198.0,-199.54 198.0,-248.04 C 198.0,-326.33 198.0,-326.33 198.0,-326.33 C 198.0,-368.23 190.59,-379.02 174.0,-417.4800 C 168.08,-431.2 158.97,-445.51 151.82,-455.7900 L 151.48,-456.2800"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 219.82,-81.8180 C 230.38,-68.517 246.3700,-48.382 257.0,-35.004 L 257.25,-34.689"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 209.7,-78.213 C 210.15,-66.984 210.74,-52.3090 211.21,-40.653 L 211.22,-40.378"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 198.65,-81.47 C 189.33,-68.875 175.63,-50.3620 165.86,-37.1710 L 165.63,-36.861"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 194.12,-85.6940 C 177.33,-74.682 149.19,-56.222 125.0,-40.2960 C 121.09,-37.725 116.9000,-34.956 112.94,-32.344 L 112.56,-32.092"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 157.4200,-463.38 C 188.35,-450.0200 254.93,-421.2500 286.17,-407.76 L 286.53,-407.6"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 125.6700,-461.7600 C 102.19,-448.4 57.559,-423.0000 33.801,-409.4700 L 33.523,-409.32"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 136.37,-453.77 C 129.4000,-427.06 117.0000,-373.02 117.0000,-326.33 C 117.0000,-326.33 117.0000,-326.33 117.0000,-248.04 C 117.0000,-201.1400 114.55,-146.06 113.08,-117.2700 L 113.06,-116.9300"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 296.79,-382.47 C 292.18,-370.61 285.93,-354.5 281.31,-342.58 L 281.2,-342.3000"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 316.44,-387.21 C 331.91,-374.2300 357.26,-352.96 373.54,-339.3 L 373.92,-338.98"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 309.21,-382.47 C 313.56,-371.27 319.38,-356.2800 323.91,-344.61 L 324.02,-344.33"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 288.12,-312.73 C 303.78,-298.8800 329.82,-275.85 345.6,-261.89 L 345.97,-261.56"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 281.29,-308.21 C 285.95,-296.27 292.3,-280.01 297.1,-267.7100 L 297.21,-267.42"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 268.71,-308.21 C 264.11,-296.44 257.88,-280.47 253.1,-268.2400 L 252.99,-267.9500"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 121.5300,-78.586 C 128.3500,-66.5220 137.5,-50.339 144.3500,-38.226 L 144.51,-37.941"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 107.96,-76.697 C 105.56,-65.522 102.51,-51.375 100.09,-40.155 L 100.04,-39.89"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 155.27,-40.632 C 157.03,-69.326 160.0,-124.6400 160.0,-171.74 C 160.0,-326.33 160.0,-326.33 160.0,-326.33 C 160.0,-372.6000 150.26,-426.5 144.73,-453.4 L 144.6600,-453.7100"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 89.524,-39.429 C 80.174,-67.503 64.0,-123.1 64.0,-171.74 C 64.0,-326.33 64.0,-326.33 64.0,-326.33 C 64.0,-380.31 106.53,-433.6800 128.37,-457.52 L 128.63,-457.8000"/></g></g><g class="shapes"><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-249.04" cx="359.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-172.74" cx="387.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-96.445" cx="208.99999999999997" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-471.48" cx="141.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-399.48" cx="303.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-325.3299999999999" cx="275.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-172.74" cx="275.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-96.445" cx="359.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-20.148" cx="268.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-399.48" cx="18.0" r="18.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-325.3299999999999" cx="389.0" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-249.04" cx="304.0" r="19.49832"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-172.74" cx="330.99999999999994" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-96.445" cx="415.0" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-20.148" cx="212.0" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-96.445" cx="112.0" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-325.3299999999999" cx="330.99999999999994" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-249.04" cx="246.0" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-20.148" cx="154.0" r="20.14812"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="0.5" fill-opacity="0.2" stroke-opacity="1.0"><circle cy="-20.148" cx="96.0" r="20.14812"/></g></g><g class="labels"><g fill="rgb(-51%, 30%, 37%)" stroke="none" stroke-width="0.0" font-size="14.0" fill-opacity="1.0" text-anchor="middle"><text x="359.0" y="-245.33999999999997">0</text><text x="387.0" y="-169.04000000000002">1</text><text x="208.99999999999997" y="-92.745">2</text><text x="141.0" y="-467.78000000000003">3</text><text x="303.0" y="-395.78">4</text><text x="275.0" y="-321.63">5</text><text x="275.0" y="-169.04000000000002">6</text><text x="359.0" y="-92.745">7</text><text x="268.0" y="-16.448">8</text><text x="18.0" y="-395.78">9</text><text x="389.0" y="-321.63">10</text><text x="304.0" y="-245.33999999999997">11</text><text x="330.99999999999994" y="-169.04000000000002">12</text><text x="415.0" y="-92.745">13</text><text x="212.0" y="-16.448">14</text><text x="112.0" y="-92.745">15</text><text x="330.99999999999994" y="-321.63">16</text><text x="246.0" y="-245.33999999999997">17</text><text x="154.0" y="-16.448">18</text><text x="96.0" y="-16.448">19</text></g></g></g><g class="hud"></g></svg>
+ other/ex0.svg view
@@ -0,0 +1,12 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Pages: 1 -->+<svg width="8pt" height="8pt"+ viewBox="0.00 0.00 8.00 8.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 4)">+<polygon fill="white" stroke="transparent" points="-4,4 -4,-4 4,-4 4,4 -4,4"/>+</g>+</svg>
+ other/ex1.svg view
@@ -0,0 +1,56 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="188pt" height="116pt"+ viewBox="0.00 0.00 188.00 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-112 184,-112 184,4 -4,4"/>+<!-- A -->+<g id="node1" class="node">+<title>A</title>+<polygon fill="none" stroke="black" points="90,-108 63,-90 90,-72 117,-90 90,-108"/>+<text text-anchor="middle" x="90" y="-86.3" font-family="Times,serif" font-size="14.00">A</text>+</g>+<!-- B -->+<g id="node2" class="node">+<title>B</title>+<polygon fill="none" stroke="black" points="54,-36 0,-36 0,0 54,0 54,-36"/>+<text text-anchor="middle" x="27" y="-14.3" font-family="Times,serif" font-size="14.00">B</text>+</g>+<!-- A->B -->+<g id="edge1" class="edge">+<title>A->B</title>+<path fill="none" stroke="grey" stroke-dasharray="5,2" d="M80.43,-78.37C72.13,-69.14 59.79,-55.44 49.07,-43.52"/>+<polygon fill="grey" stroke="grey" points="51.6,-41.1 42.31,-36.01 46.4,-45.78 51.6,-41.1"/>+</g>+<!-- C -->+<g id="node3" class="node">+<title>C</title>+<ellipse fill="none" stroke="black" cx="90" cy="-18" rx="18" ry="18"/>+<text text-anchor="middle" x="90" y="-14.3" font-family="Times,serif" font-size="14.00">C</text>+</g>+<!-- A->C -->+<g id="edge2" class="edge">+<title>A->C</title>+<path fill="none" stroke="black" d="M88,-71.7C88,-63.98 88,-54.71 88,-46.11"/>+<path fill="none" stroke="transparent" d="M90,-71.7C90,-63.98 90,-54.71 90,-46.11"/>+<path fill="none" stroke="black" d="M92,-71.7C92,-63.98 92,-54.71 92,-46.11"/>+<polygon fill="black" stroke="black" points="93.5,-46.1 90,-36.1 86.5,-46.1 93.5,-46.1"/>+</g>+<!-- D -->+<g id="node4" class="node">+<title>D</title>+<ellipse fill="none" stroke="black" cx="153" cy="-18" rx="27" ry="18"/>+<text text-anchor="middle" x="153" y="-14.3" font-family="Times,serif" font-size="14.00">D</text>+</g>+<!-- A->D -->+<g id="edge3" class="edge">+<title>A->D</title>+<path fill="none" stroke="black" stroke-width="5" d="M99.57,-78.37C110.24,-66.51 127.58,-47.25 139.59,-33.89"/>+</g>+</g>+</svg>
+ other/ex10.svg view
@@ -0,0 +1,22 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: H Pages: 1 -->+<svg width="97pt" height="62pt"+ viewBox="0.00 0.00 97.00 62.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 58)">+<title>H</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-58 93,-58 93,4 -4,4"/>+<!-- aHtmlTable -->+<g id="node1" class="node">+<title>aHtmlTable</title>+<text text-anchor="start" x="18.5" y="-33.8" font-family="Times,serif" font-size="14.00">col 1</text>+<text text-anchor="start" x="57.5" y="-33.8" font-family="Times,serif" font-size="14.00">foo</text>+<text text-anchor="start" x="13.5" y="-12.8" font-family="Times,serif" font-size="14.00">COL 2</text>+<text text-anchor="start" x="58" y="-12.8" font-family="Times,serif" font-size="14.00">bar</text>+<polygon fill="none" stroke="blue" points="8,-4 8,-50 81,-50 81,-4 8,-4"/>+</g>+</g>+</svg>
+ other/ex11.svg view
@@ -0,0 +1,56 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Pages: 1 -->+<svg width="296pt" height="133pt"+ viewBox="0.00 0.00 296.00 133.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 129)">+<polygon fill="white" stroke="transparent" points="-4,4 -4,-129 292,-129 292,4 -4,4"/>+<!-- tbl -->+<g id="node1" class="node">+<title>tbl</title>+<polygon fill="none" stroke="blue" points="8,-99.5 8,-120.5 127,-120.5 127,-99.5 8,-99.5"/>+<text text-anchor="start" x="58" y="-106.3" font-family="Times,serif" font-size="14.00">foo</text>+<polygon fill="none" stroke="blue" points="127,-99.5 127,-120.5 202,-120.5 202,-99.5 127,-99.5"/>+<text text-anchor="start" x="155.5" y="-106.3" font-family="Times,serif" font-size="14.00">bar</text>+<polygon fill="none" stroke="blue" points="202,-99.5 202,-120.5 280,-120.5 280,-99.5 202,-99.5"/>+<text text-anchor="start" x="231" y="-106.3" font-family="Times,serif" font-size="14.00">baz</text>+<polygon fill="none" stroke="blue" points="8,-24.5 8,-99.5 127,-99.5 127,-24.5 8,-24.5"/>+<polygon fill="none" stroke="orange" points="14,-72.5 14,-93.5 52,-93.5 52,-72.5 14,-72.5"/>+<text text-anchor="start" x="19" y="-79.3" font-family="Times,serif" font-size="14.00">one  </text>+<polygon fill="none" stroke="orange" points="52,-72.5 52,-93.5 87,-93.5 87,-72.5 52,-72.5"/>+<text text-anchor="start" x="55" y="-79.3" font-family="Times,serif" font-size="14.00">two  </text>+<polygon fill="none" stroke="orange" points="87,-72.5 87,-93.5 121,-93.5 121,-72.5 87,-72.5"/>+<text text-anchor="start" x="90" y="-79.3" font-family="Times,serif" font-size="14.00">three</text>+<polygon fill="none" stroke="orange" points="14,-51.5 14,-72.5 52,-72.5 52,-51.5 14,-51.5"/>+<text text-anchor="start" x="19.5" y="-58.3" font-family="Times,serif" font-size="14.00">four </text>+<polygon fill="none" stroke="orange" points="52,-51.5 52,-72.5 87,-72.5 87,-51.5 52,-51.5"/>+<text text-anchor="start" x="57" y="-58.3" font-family="Times,serif" font-size="14.00">five </text>+<polygon fill="none" stroke="orange" points="87,-51.5 87,-72.5 121,-72.5 121,-51.5 87,-51.5"/>+<text text-anchor="start" x="92" y="-58.3" font-family="Times,serif" font-size="14.00">six  </text>+<polygon fill="none" stroke="orange" points="14,-30.5 14,-51.5 52,-51.5 52,-30.5 14,-30.5"/>+<text text-anchor="start" x="17" y="-37.3" font-family="Times,serif" font-size="14.00">seven</text>+<polygon fill="none" stroke="orange" points="52,-30.5 52,-51.5 87,-51.5 87,-30.5 52,-30.5"/>+<text text-anchor="start" x="55.5" y="-37.3" font-family="Times,serif" font-size="14.00">eight</text>+<polygon fill="none" stroke="orange" points="87,-30.5 87,-51.5 121,-51.5 121,-30.5 87,-30.5"/>+<text text-anchor="start" x="90" y="-37.3" font-family="Times,serif" font-size="14.00">nine </text>+<polygon fill="none" stroke="orange" points="13,-29.5 13,-94.5 122,-94.5 122,-29.5 13,-29.5"/>+<polygon fill="none" stroke="blue" points="127,-3.5 127,-99.5 280,-99.5 280,-3.5 127,-3.5"/>+<polygon fill="none" stroke="pink" points="130,-51.5 130,-96.5 175,-96.5 175,-51.5 130,-51.5"/>+<text text-anchor="start" x="141" y="-70.3" font-family="Times,serif" font-size="14.00">eins</text>+<polygon fill="none" stroke="pink" points="175,-51.5 175,-96.5 224,-96.5 224,-51.5 175,-51.5"/>+<text text-anchor="start" x="186" y="-70.3" font-family="Times,serif" font-size="14.00">zwei</text>+<polygon fill="none" stroke="pink" points="224,-6.5 224,-96.5 277,-96.5 277,-6.5 224,-6.5"/>+<text text-anchor="start" x="239.5" y="-55.3" font-family="Times,serif" font-size="14.00">drei</text>+<text text-anchor="start" x="235" y="-40.3" font-family="Times,serif" font-size="14.00">sechs</text>+<polygon fill="none" stroke="pink" points="130,-6.5 130,-51.5 175,-51.5 175,-6.5 130,-6.5"/>+<text text-anchor="start" x="141.5" y="-25.3" font-family="Times,serif" font-size="14.00">vier</text>+<polygon fill="none" stroke="pink" points="175,-6.5 175,-51.5 224,-51.5 224,-6.5 175,-6.5"/>+<text text-anchor="start" x="187.5" y="-25.3" font-family="Times,serif" font-size="14.00">fünf</text>+<polygon fill="none" stroke="blue" points="8,-3.5 8,-24.5 127,-24.5 127,-3.5 8,-3.5"/>+<text text-anchor="start" x="57.5" y="-10.3" font-family="Times,serif" font-size="14.00">abc</text>+</g>+</g>+</svg>
+ other/ex12.svg view
@@ -0,0 +1,26 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="62pt" height="79pt"+ viewBox="0.00 0.00 62.00 79.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 75)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-75 58,-75 58,4 -4,4"/>+<!-- some_node -->+<g id="node1" class="node">+<title>some_node</title>+<polygon fill="yellow" stroke="transparent" points="13,-45.5 13,-66.5 41,-66.5 41,-45.5 13,-45.5"/>+<polygon fill="none" stroke="black" points="13,-45.5 13,-66.5 41,-66.5 41,-45.5 13,-45.5"/>+<text text-anchor="start" x="16" y="-52.3" font-family="Times,serif" font-size="14.00">Foo</text>+<polygon fill="lightblue" stroke="transparent" points="13,-24.5 13,-45.5 41,-45.5 41,-24.5 13,-24.5"/>+<polygon fill="none" stroke="black" points="13,-24.5 13,-45.5 41,-45.5 41,-24.5 13,-24.5"/>+<text text-anchor="start" x="16.5" y="-31.3" font-family="Times,serif" font-size="14.00" fill="#0000ff">Bar</text>+<polygon fill="#f0e3ff" stroke="transparent" points="13,-3.5 13,-24.5 41,-24.5 41,-3.5 13,-3.5"/>+<polygon fill="none" stroke="black" points="13,-3.5 13,-24.5 41,-24.5 41,-3.5 13,-3.5"/>+<text text-anchor="start" x="16" y="-10.3" font-family="Times,serif" font-size="14.00" fill="#ff1020">Baz</text>+</g>+</g>+</svg>
+ other/ex13.svg view
@@ -0,0 +1,22 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: H Pages: 1 -->+<svg width="97pt" height="62pt"+ viewBox="0.00 0.00 97.00 62.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 58)">+<title>H</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-58 93,-58 93,4 -4,4"/>+<!-- aHtmlTable -->+<g id="node1" class="node">+<title>aHtmlTable</title>+<text text-anchor="start" x="18.5" y="-33.8" font-family="Times,serif" font-size="14.00">col 1</text>+<text text-anchor="start" x="57.5" y="-33.8" font-family="Times,serif" font-size="14.00">foo</text>+<text text-anchor="start" x="13.5" y="-12.8" font-family="Times,serif" font-size="14.00">COL 2</text>+<text text-anchor="start" x="58" y="-12.8" font-family="Times,serif" font-size="14.00">bar</text>+<path fill="none" stroke="black" d="M20,-4C20,-4 69,-4 69,-4 75,-4 81,-10 81,-16 81,-16 81,-38 81,-38 81,-44 75,-50 69,-50 69,-50 20,-50 20,-50 14,-50 8,-44 8,-38 8,-38 8,-16 8,-16 8,-10 14,-4 20,-4"/>+</g>+</g>+</svg>
+ other/ex14.svg view
@@ -0,0 +1,62 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: H Pages: 1 -->+<svg width="230pt" height="138pt"+ viewBox="0.00 0.00 230.00 138.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 134)">+<title>H</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-134 226,-134 226,4 -4,4"/>+<!-- parent -->+<g id="node1" class="node">+<title>parent</title>+<polygon fill="none" stroke="black" points="11,-102 11,-123 211,-123 211,-102 11,-102"/>+<text text-anchor="start" x="32.5" y="-108.8" font-family="Times,serif" font-size="14.00">The foo, the bar and the baz</text>+<polygon fill="none" stroke="black" points="11,-79 11,-100 69,-100 69,-79 11,-79"/>+<text text-anchor="start" x="14" y="-85.8" font-family="Times,serif" font-size="14.00">First port</text>+<polygon fill="none" stroke="black" points="71,-79 71,-100 145,-100 145,-79 71,-79"/>+<text text-anchor="start" x="74" y="-85.8" font-family="Times,serif" font-size="14.00">Second port</text>+<polygon fill="none" stroke="black" points="147,-79 147,-100 211,-100 211,-79 147,-79"/>+<text text-anchor="start" x="150" y="-85.8" font-family="Times,serif" font-size="14.00">Third port</text>+<polygon fill="none" stroke="black" points="8,-76 8,-126 214,-126 214,-76 8,-76"/>+</g>+<!-- child_one -->+<g id="node2" class="node">+<title>child_one</title>+<text text-anchor="start" x="32" y="-13.8" font-family="Times,serif" font-size="14.00">1</text>+<polygon fill="none" stroke="black" points="27,-5.5 27,-30.5 45,-30.5 45,-5.5 27,-5.5"/>+</g>+<!-- parent->child_one -->+<g id="edge1" class="edge">+<title>parent:port_one->child_one</title>+<path fill="none" stroke="black" d="M40,-78C40,-67.6 39.37,-56.18 38.62,-46.19"/>+<polygon fill="black" stroke="black" points="42.09,-45.69 37.77,-36.02 35.11,-46.28 42.09,-45.69"/>+</g>+<!-- child_two -->+<g id="node3" class="node">+<title>child_two</title>+<text text-anchor="start" x="104" y="-13.8" font-family="Times,serif" font-size="14.00">2</text>+<polygon fill="none" stroke="black" points="99,-5.5 99,-30.5 117,-30.5 117,-5.5 99,-5.5"/>+</g>+<!-- parent->child_two -->+<g id="edge2" class="edge">+<title>parent:port_two->child_two</title>+<path fill="none" stroke="black" d="M108,-78C108,-67.62 108,-56.21 108,-46.22"/>+<polygon fill="black" stroke="black" points="111.5,-46.04 108,-36.04 104.5,-46.04 111.5,-46.04"/>+</g>+<!-- child_three -->+<g id="node4" class="node">+<title>child_three</title>+<text text-anchor="start" x="176" y="-13.8" font-family="Times,serif" font-size="14.00">3</text>+<polygon fill="none" stroke="black" points="171,-5.5 171,-30.5 189,-30.5 189,-5.5 171,-5.5"/>+</g>+<!-- parent->child_three -->+<g id="edge3" class="edge">+<title>parent:port_three->child_three</title>+<path fill="none" stroke="black" d="M179,-78C179,-67.62 179.16,-56.21 179.35,-46.21"/>+<polygon fill="black" stroke="black" points="182.85,-46.11 179.56,-36.04 175.85,-45.96 182.85,-46.11"/>+</g>+</g>+</svg>
+ other/ex15.svg view
@@ -0,0 +1,91 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="199pt" height="328pt"+ viewBox="0.00 0.00 198.50 328.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 324)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-324 194.5,-324 194.5,4 -4,4"/>+<!-- task_menu -->+<g id="node1" class="node">+<title>task_menu</title>+<text text-anchor="start" x="15" y="-306.1" font-family="Sans serif" font-weight="bold" font-size="8.00">Task 1</text>+<text text-anchor="start" x="15" y="-291.1" font-family="Sans serif" font-size="8.00">Choose Menu</text>+<text text-anchor="start" x="15" y="-277.1" font-family="Sans serif" font-size="8.00" fill="darkgreen">done</text>+<polygon fill="none" stroke="black" points="11,-271 11,-316 69,-316 69,-271 11,-271"/>+</g>+<!-- task_ingredients -->+<g id="node2" class="node">+<title>task_ingredients</title>+<text text-anchor="start" x="12" y="-217.1" font-family="Sans serif" font-weight="bold" font-size="8.00">Task 2</text>+<text text-anchor="start" x="12" y="-202.1" font-family="Sans serif" font-size="8.00">Buy ingredients</text>+<text text-anchor="start" x="12" y="-188.1" font-family="Sans serif" font-size="8.00" fill="darkgreen">done</text>+<polygon fill="none" stroke="black" points="8,-182 8,-227 72,-227 72,-182 8,-182"/>+</g>+<!-- task_menu->task_ingredients -->+<g id="edge1" class="edge">+<title>task_menu->task_ingredients</title>+<path fill="none" stroke="black" d="M40,-266.87C40,-258.89 40,-249.93 40,-241.38"/>+<polygon fill="black" stroke="black" points="43.5,-241.25 40,-231.25 36.5,-241.25 43.5,-241.25"/>+</g>+<!-- task_cook -->+<g id="node4" class="node">+<title>task_cook</title>+<text text-anchor="start" x="76" y="-128.1" font-family="Sans serif" font-weight="bold" font-size="8.00">Task 5</text>+<text text-anchor="start" x="76" y="-113.1" font-family="Sans serif" font-size="8.00">Cook</text>+<text text-anchor="start" x="76" y="-99.1" font-family="Sans serif" font-size="8.00" fill="red">todo</text>+<polygon fill="none" stroke="black" points="71.5,-93 71.5,-138 104.5,-138 104.5,-93 71.5,-93"/>+</g>+<!-- task_ingredients->task_cook -->+<g id="edge2" class="edge">+<title>task_ingredients->task_cook</title>+<path fill="none" stroke="black" d="M54.14,-177.87C58.74,-169.53 63.92,-160.14 68.82,-151.26"/>+<polygon fill="black" stroke="black" points="72.03,-152.7 73.79,-142.25 65.9,-149.31 72.03,-152.7"/>+</g>+<!-- task_invitation -->+<g id="node3" class="node">+<title>task_invitation</title>+<text text-anchor="start" x="111" y="-217.1" font-family="Sans serif" font-weight="bold" font-size="8.00">Task 4</text>+<text text-anchor="start" x="111" y="-202.1" font-family="Sans serif" font-size="8.00">Send invitation</text>+<text text-anchor="start" x="111" y="-188.1" font-family="Sans serif" font-size="8.00" fill="darkgreen">done</text>+<polygon fill="none" stroke="black" points="106.5,-182 106.5,-227 167.5,-227 167.5,-182 106.5,-182"/>+</g>+<!-- task_invitation->task_cook -->+<g id="edge3" class="edge">+<title>task_invitation->task_cook</title>+<path fill="none" stroke="black" d="M122.56,-177.87C117.82,-169.45 112.47,-159.95 107.42,-150.98"/>+<polygon fill="black" stroke="black" points="110.46,-149.25 102.5,-142.25 104.36,-152.68 110.46,-149.25"/>+</g>+<!-- task_eat -->+<g id="node6" class="node">+<title>task_eat</title>+<text text-anchor="start" x="113" y="-39.1" font-family="Sans serif" font-weight="bold" font-size="8.00">Task 6</text>+<text text-anchor="start" x="113" y="-24.1" font-family="Sans serif" font-size="8.00">Eat</text>+<text text-anchor="start" x="113" y="-10.1" font-family="Sans serif" font-size="8.00" fill="red">todo</text>+<polygon fill="none" stroke="black" points="108.5,-4 108.5,-49 141.5,-49 141.5,-4 108.5,-4"/>+</g>+<!-- task_cook->task_eat -->+<g id="edge5" class="edge">+<title>task_cook->task_eat</title>+<path fill="none" stroke="black" d="M98.9,-88.87C102.41,-80.62 106.36,-71.34 110.1,-62.54"/>+<polygon fill="black" stroke="black" points="113.36,-63.82 114.05,-53.25 106.91,-61.08 113.36,-63.82"/>+</g>+<!-- task_table -->+<g id="node5" class="node">+<title>task_table</title>+<text text-anchor="start" x="146" y="-128.1" font-family="Sans serif" font-weight="bold" font-size="8.00">Task 3</text>+<text text-anchor="start" x="146" y="-113.1" font-family="Sans serif" font-size="8.00">Lay table</text>+<text text-anchor="start" x="146" y="-99.1" font-family="Sans serif" font-size="8.00" fill="red">todo</text>+<polygon fill="none" stroke="black" points="141.5,-93 141.5,-138 182.5,-138 182.5,-93 141.5,-93"/>+</g>+<!-- task_table->task_eat -->+<g id="edge4" class="edge">+<title>task_table->task_eat</title>+<path fill="none" stroke="black" d="M151.1,-88.87C147.59,-80.62 143.64,-71.34 139.9,-62.54"/>+<polygon fill="black" stroke="black" points="143.09,-61.08 135.95,-53.25 136.64,-63.82 143.09,-61.08"/>+</g>+</g>+</svg>
+ other/ex2.svg view
@@ -0,0 +1,32 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="578pt" height="78pt"+ viewBox="0.00 0.00 578.00 78.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 74)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-74 574,-74 574,4 -4,4"/>+<!-- node_A -->+<g id="node1" class="node">+<title>node_A</title>+<polygon fill="none" stroke="black" points="0,-0.5 0,-69.5 205,-69.5 205,-0.5 0,-0.5"/>+<text text-anchor="middle" x="51.5" y="-31.3" font-family="Arial" font-size="14.00">shape=record</text>+<polyline fill="none" stroke="black" points="103,-0.5 103,-69.5 "/>+<text text-anchor="middle" x="132" y="-54.3" font-family="Arial" font-size="14.00">above</text>+<polyline fill="none" stroke="black" points="103,-46.5 161,-46.5 "/>+<text text-anchor="middle" x="132" y="-31.3" font-family="Arial" font-size="14.00">middle</text>+<polyline fill="none" stroke="black" points="103,-23.5 161,-23.5 "/>+<text text-anchor="middle" x="132" y="-8.3" font-family="Arial" font-size="14.00">below</text>+<polyline fill="none" stroke="black" points="161,-0.5 161,-69.5 "/>+<text text-anchor="middle" x="183" y="-31.3" font-family="Arial" font-size="14.00">right</text>+</g>+<!-- node_B -->+<g id="node2" class="node">+<title>node_B</title>+<text text-anchor="middle" x="396.5" y="-31.3" font-family="Arial" font-size="14.00">shape=plaintext|{curly|braces and|bars without}|effect</text>+</g>+</g>+</svg>
+ other/ex3.svg view
@@ -0,0 +1,79 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="206pt" height="188pt"+ viewBox="0.00 0.00 206.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-184 202,-184 202,4 -4,4"/>+<!-- A -->+<g id="node1" class="node">+<title>A</title>+<ellipse fill="none" stroke="black" cx="99" cy="-162" rx="27" ry="18"/>+<text text-anchor="middle" x="99" y="-158.3" font-family="Times,serif" font-size="14.00">A</text>+</g>+<!-- B -->+<g id="node2" class="node">+<title>B</title>+<ellipse fill="none" stroke="black" cx="27" cy="-90" rx="27" ry="18"/>+<text text-anchor="middle" x="27" y="-86.3" font-family="Times,serif" font-size="14.00">B</text>+</g>+<!-- A->B -->+<g id="edge1" class="edge">+<title>A->B</title>+<path fill="none" stroke="black" d="M84.43,-146.83C74.25,-136.94 60.48,-123.55 48.97,-112.36"/>+<polygon fill="black" stroke="black" points="51.41,-109.85 41.8,-105.38 46.53,-114.87 51.41,-109.85"/>+</g>+<!-- C -->+<g id="node3" class="node">+<title>C</title>+<ellipse fill="none" stroke="black" cx="99" cy="-90" rx="27" ry="18"/>+<text text-anchor="middle" x="99" y="-86.3" font-family="Times,serif" font-size="14.00">C</text>+</g>+<!-- A->C -->+<g id="edge2" class="edge">+<title>A->C</title>+<path fill="none" stroke="black" d="M99,-143.7C99,-135.98 99,-126.71 99,-118.11"/>+<polygon fill="black" stroke="black" points="102.5,-118.1 99,-108.1 95.5,-118.1 102.5,-118.1"/>+</g>+<!-- D -->+<g id="node4" class="node">+<title>D</title>+<ellipse fill="none" stroke="black" cx="171" cy="-90" rx="27" ry="18"/>+<text text-anchor="middle" x="171" y="-86.3" font-family="Times,serif" font-size="14.00">D</text>+</g>+<!-- A->D -->+<g id="edge3" class="edge">+<title>A->D</title>+<path fill="none" stroke="black" d="M113.57,-146.83C123.75,-136.94 137.52,-123.55 149.03,-112.36"/>+<polygon fill="black" stroke="black" points="151.47,-114.87 156.2,-105.38 146.59,-109.85 151.47,-114.87"/>+</g>+<!-- F -->+<g id="node5" class="node">+<title>F</title>+<ellipse fill="none" stroke="black" cx="99" cy="-18" rx="27" ry="18"/>+<text text-anchor="middle" x="99" y="-14.3" font-family="Times,serif" font-size="14.00">F</text>+</g>+<!-- B->F -->+<g id="edge4" class="edge">+<title>B->F</title>+<path fill="none" stroke="black" d="M41.57,-74.83C51.75,-64.94 65.52,-51.55 77.03,-40.36"/>+<polygon fill="black" stroke="black" points="79.47,-42.87 84.2,-33.38 74.59,-37.85 79.47,-42.87"/>+</g>+<!-- C->F -->+<g id="edge5" class="edge">+<title>C->F</title>+<path fill="none" stroke="black" d="M99,-71.7C99,-63.98 99,-54.71 99,-46.11"/>+<polygon fill="black" stroke="black" points="102.5,-46.1 99,-36.1 95.5,-46.1 102.5,-46.1"/>+</g>+<!-- D->F -->+<g id="edge6" class="edge">+<title>D->F</title>+<path fill="none" stroke="black" d="M156.43,-74.83C146.25,-64.94 132.48,-51.55 120.97,-40.36"/>+<polygon fill="black" stroke="black" points="123.41,-37.85 113.8,-33.38 118.53,-42.87 123.41,-37.85"/>+</g>+</g>+</svg>
+ other/ex4.svg view
@@ -0,0 +1,49 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: L Pages: 1 -->+<svg width="137pt" height="242pt"+ viewBox="0.00 0.00 137.00 242.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 238)">+<title>L</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-238 133,-238 133,4 -4,4"/>+<!-- a -->+<g id="node1" class="node">+<title>a</title>+<polygon fill="none" stroke="black" points="0,-180.5 0,-233.5 129,-233.5 129,-180.5 0,-180.5"/>+<text text-anchor="start" x="8" y="-218.3" font-family="Arial" font-size="14.00">one</text>+<text text-anchor="start" x="8" y="-203.3" font-family="Arial" font-size="14.00">two three</text>+<text text-anchor="start" x="8" y="-188.3" font-family="Arial" font-size="14.00">four five six seven</text>+</g>+<!-- b -->+<g id="node2" class="node">+<title>b</title>+<polygon fill="none" stroke="black" points="0,-90.5 0,-143.5 129,-143.5 129,-90.5 0,-90.5"/>+<text text-anchor="middle" x="64.5" y="-128.3" font-family="Arial" font-size="14.00">one</text>+<text text-anchor="middle" x="64.5" y="-113.3" font-family="Arial" font-size="14.00">two three</text>+<text text-anchor="middle" x="64.5" y="-98.3" font-family="Arial" font-size="14.00">four five six seven</text>+</g>+<!-- a->b -->+<g id="edge1" class="edge">+<title>a->b</title>+<path fill="none" stroke="black" d="M64.5,-180.07C64.5,-171.84 64.5,-162.58 64.5,-153.78"/>+<polygon fill="black" stroke="black" points="68,-153.74 64.5,-143.74 61,-153.74 68,-153.74"/>+</g>+<!-- c -->+<g id="node3" class="node">+<title>c</title>+<polygon fill="none" stroke="black" points="0,-0.5 0,-53.5 129,-53.5 129,-0.5 0,-0.5"/>+<text text-anchor="end" x="121" y="-38.3" font-family="Arial" font-size="14.00">one</text>+<text text-anchor="end" x="121" y="-23.3" font-family="Arial" font-size="14.00">two three</text>+<text text-anchor="end" x="121" y="-8.3" font-family="Arial" font-size="14.00">four five six seven</text>+</g>+<!-- b->c -->+<g id="edge2" class="edge">+<title>b->c</title>+<path fill="none" stroke="black" d="M64.5,-90.07C64.5,-81.84 64.5,-72.58 64.5,-63.78"/>+<polygon fill="black" stroke="black" points="68,-63.74 64.5,-53.74 61,-63.74 68,-63.74"/>+</g>+</g>+</svg>
+ other/ex5.svg view
@@ -0,0 +1,41 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="181pt" height="139pt"+ viewBox="0.00 0.00 181.00 139.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 135)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-135 177,-135 177,4 -4,4"/>+<text text-anchor="middle" x="86.5" y="-115.8" font-family="Times,serif" font-size="14.00">The foo, the bar and the baz</text>+<!-- FOO -->+<g id="node1" class="node">+<title>FOO</title>+<text text-anchor="middle" x="86.5" y="-86.3" font-family="Times,serif" font-size="14.00">FOO</text>+</g>+<!-- BAR -->+<g id="node2" class="node">+<title>BAR</title>+<text text-anchor="middle" x="50.5" y="-14.3" font-family="Times,serif" font-size="14.00">BAR</text>+</g>+<!-- FOO->BAR -->+<g id="edge1" class="edge">+<title>FOO->BAR</title>+<path fill="none" stroke="black" d="M77.6,-71.7C73.5,-63.73 68.55,-54.1 64.01,-45.26"/>+<polygon fill="black" stroke="black" points="66.98,-43.4 59.3,-36.1 60.76,-46.6 66.98,-43.4"/>+</g>+<!-- BAZ -->+<g id="node3" class="node">+<title>BAZ</title>+<text text-anchor="middle" x="122.5" y="-14.3" font-family="Times,serif" font-size="14.00">BAZ</text>+</g>+<!-- FOO->BAZ -->+<g id="edge2" class="edge">+<title>FOO->BAZ</title>+<path fill="none" stroke="black" d="M95.4,-71.7C99.5,-63.73 104.45,-54.1 108.99,-45.26"/>+<polygon fill="black" stroke="black" points="112.24,-46.6 113.7,-36.1 106.02,-43.4 112.24,-46.6"/>+</g>+</g>+</svg>
+ other/ex6.svg view
@@ -0,0 +1,48 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="134pt" height="172pt"+ viewBox="0.00 0.00 134.00 172.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 168)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-168 130,-168 130,4 -4,4"/>+<text text-anchor="start" x="38.5" y="-149.8" font-family="Times,serif" font-size="14.00">The </text>+<text text-anchor="start" x="64.5" y="-149.8" font-family="Times,serif" font-weight="bold" font-size="14.00" fill="red">foo</text>+<text text-anchor="start" x="83.5" y="-149.8" font-family="Times,serif" font-size="14.00">,</text>+<text text-anchor="start" x="25.5" y="-131" font-family="Times,serif" font-size="14.00"> the </text>+<text text-anchor="start" x="50.5" y="-131" font-family="Times,serif" font-size="20.00">bar</text>+<text text-anchor="start" x="76.5" y="-131" font-family="Times,serif" font-size="14.00"> and</text>+<text text-anchor="start" x="40.5" y="-115.8" font-family="Times,serif" font-size="14.00"> the </text>+<text text-anchor="start" x="65.5" y="-115.8" font-family="Times,serif" font-style="italic" font-size="14.00">baz</text>+<!-- FOO -->+<g id="node1" class="node">+<title>FOO</title>+<text text-anchor="middle" x="63" y="-86.3" font-family="Times,serif" font-size="14.00">FOO</text>+</g>+<!-- BAR -->+<g id="node2" class="node">+<title>BAR</title>+<text text-anchor="middle" x="27" y="-14.3" font-family="Times,serif" font-size="14.00">BAR</text>+</g>+<!-- FOO->BAR -->+<g id="edge1" class="edge">+<title>FOO->BAR</title>+<path fill="none" stroke="black" d="M54.1,-71.7C50,-63.73 45.05,-54.1 40.51,-45.26"/>+<polygon fill="black" stroke="black" points="43.48,-43.4 35.8,-36.1 37.26,-46.6 43.48,-43.4"/>+</g>+<!-- BAZ -->+<g id="node3" class="node">+<title>BAZ</title>+<text text-anchor="middle" x="99" y="-14.3" font-family="Times,serif" font-size="14.00">BAZ</text>+</g>+<!-- FOO->BAZ -->+<g id="edge2" class="edge">+<title>FOO->BAZ</title>+<path fill="none" stroke="black" d="M71.9,-71.7C76,-63.73 80.95,-54.1 85.49,-45.26"/>+<polygon fill="black" stroke="black" points="88.74,-46.6 90.2,-36.1 82.52,-43.4 88.74,-46.6"/>+</g>+</g>+</svg>
+ other/ex7.svg view
@@ -0,0 +1,97 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: R Pages: 1 -->+<svg width="206pt" height="260pt"+ viewBox="0.00 0.00 206.00 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">+<title>R</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-256 202,-256 202,4 -4,4"/>+<!-- rA -->+<g id="node1" class="node">+<title>rA</title>+<ellipse fill="none" stroke="black" cx="27" cy="-162" rx="27" ry="18"/>+<text text-anchor="middle" x="27" y="-158.3" font-family="Times,serif" font-size="14.00">rA</text>+</g>+<!-- sA -->+<g id="node2" class="node">+<title>sA</title>+<ellipse fill="none" stroke="black" cx="99" cy="-162" rx="27" ry="18"/>+<text text-anchor="middle" x="99" y="-158.3" font-family="Times,serif" font-size="14.00">sA</text>+</g>+<!-- rA->sA -->+<g id="edge1" class="edge">+<title>rA->sA</title>+<path fill="none" stroke="black" d="M54,-162C56.61,-162 59.23,-162 61.84,-162"/>+<polygon fill="black" stroke="black" points="61.93,-165.5 71.93,-162 61.93,-158.5 61.93,-165.5"/>+</g>+<!-- vB -->+<g id="node5" class="node">+<title>vB</title>+<ellipse fill="none" stroke="black" cx="99" cy="-90" rx="27" ry="18"/>+<text text-anchor="middle" x="99" y="-86.3" font-family="Times,serif" font-size="14.00">vB</text>+</g>+<!-- sA->vB -->+<g id="edge2" class="edge">+<title>sA->vB</title>+<path fill="none" stroke="black" d="M99,-143.7C99,-135.98 99,-126.71 99,-118.11"/>+<polygon fill="black" stroke="black" points="102.5,-118.1 99,-108.1 95.5,-118.1 102.5,-118.1"/>+</g>+<!-- tA -->+<g id="node3" class="node">+<title>tA</title>+<ellipse fill="none" stroke="black" cx="171" cy="-162" rx="27" ry="18"/>+<text text-anchor="middle" x="171" y="-158.3" font-family="Times,serif" font-size="14.00">tA</text>+</g>+<!-- uB -->+<g id="node4" class="node">+<title>uB</title>+<ellipse fill="none" stroke="black" cx="27" cy="-90" rx="27" ry="18"/>+<text text-anchor="middle" x="27" y="-86.3" font-family="Times,serif" font-size="14.00">uB</text>+</g>+<!-- uB->vB -->+<g id="edge4" class="edge">+<title>uB->vB</title>+<path fill="none" stroke="black" d="M54,-90C56.61,-90 59.23,-90 61.84,-90"/>+<polygon fill="black" stroke="black" points="61.93,-93.5 71.93,-90 61.93,-86.5 61.93,-93.5"/>+</g>+<!-- wB -->+<g id="node6" class="node">+<title>wB</title>+<ellipse fill="none" stroke="black" cx="171" cy="-90" rx="27" ry="18"/>+<text text-anchor="middle" x="171" y="-86.3" font-family="Times,serif" font-size="14.00">wB</text>+</g>+<!-- wB->tA -->+<g id="edge6" class="edge">+<title>wB->tA</title>+<path fill="none" stroke="black" d="M171,-108.1C171,-115.79 171,-125.05 171,-133.67"/>+<polygon fill="black" stroke="black" points="167.5,-133.7 171,-143.7 174.5,-133.7 167.5,-133.7"/>+</g>+<!-- u -->+<g id="node8" class="node">+<title>u</title>+<ellipse fill="none" stroke="black" cx="171" cy="-18" rx="27" ry="18"/>+<text text-anchor="middle" x="171" y="-14.3" font-family="Times,serif" font-size="14.00">u</text>+</g>+<!-- wB->u -->+<g id="edge5" class="edge">+<title>wB->u</title>+<path fill="none" stroke="black" d="M171,-71.7C171,-63.98 171,-54.71 171,-46.11"/>+<polygon fill="black" stroke="black" points="174.5,-46.1 171,-36.1 167.5,-46.1 174.5,-46.1"/>+</g>+<!-- t -->+<g id="node7" class="node">+<title>t</title>+<ellipse fill="none" stroke="black" cx="27" cy="-234" rx="27" ry="18"/>+<text text-anchor="middle" x="27" y="-230.3" font-family="Times,serif" font-size="14.00">t</text>+</g>+<!-- t->rA -->+<g id="edge3" class="edge">+<title>t->rA</title>+<path fill="none" stroke="black" d="M27,-215.7C27,-207.98 27,-198.71 27,-190.11"/>+<polygon fill="black" stroke="black" points="30.5,-190.1 27,-180.1 23.5,-190.1 30.5,-190.1"/>+</g>+</g>+</svg>
+ other/ex8.svg view
@@ -0,0 +1,93 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: Q Pages: 1 -->+<svg width="426pt" height="260pt"+ viewBox="0.00 0.00 426.44 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">+<title>Q</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-256 422.44,-256 422.44,4 -4,4"/>+<g id="clust1" class="cluster">+<title>cluster_R</title>+<polygon fill="none" stroke="black" points="8,-64 8,-116 402,-116 402,-64 8,-64"/>+</g>+<!-- nd_1 -->+<g id="node1" class="node">+<title>nd_1</title>+<ellipse fill="none" stroke="black" cx="191" cy="-234" rx="37.09" ry="18"/>+<text text-anchor="middle" x="191" y="-230.3" font-family="Times,serif" font-size="14.00">Node 1</text>+</g>+<!-- nd_2 -->+<g id="node2" class="node">+<title>nd_2</title>+<ellipse fill="none" stroke="black" cx="191" cy="-162" rx="37.09" ry="18"/>+<text text-anchor="middle" x="191" y="-158.3" font-family="Times,serif" font-size="14.00">Node 2</text>+</g>+<!-- nd_1->nd_2 -->+<g id="edge2" class="edge">+<title>nd_1->nd_2</title>+<path fill="none" stroke="black" d="M191,-215.7C191,-207.98 191,-198.71 191,-190.11"/>+<polygon fill="black" stroke="black" points="194.5,-190.1 191,-180.1 187.5,-190.1 194.5,-190.1"/>+</g>+<!-- nd_3 -->+<g id="node5" class="node">+<title>nd_3</title>+<ellipse fill="none" stroke="black" cx="199" cy="-90" rx="37.09" ry="18"/>+<text text-anchor="middle" x="199" y="-86.3" font-family="Times,serif" font-size="14.00">Node 3</text>+</g>+<!-- nd_2->nd_3 -->+<g id="edge3" class="edge">+<title>nd_2->nd_3</title>+<path fill="none" stroke="black" d="M192.98,-143.7C193.86,-135.98 194.92,-126.71 195.9,-118.11"/>+<polygon fill="black" stroke="black" points="199.39,-118.44 197.05,-108.1 192.43,-117.64 199.39,-118.44"/>+</g>+<!-- nd_3_a -->+<g id="node3" class="node">+<title>nd_3_a</title>+<ellipse fill="none" stroke="black" cx="332" cy="-162" rx="86.38" ry="18"/>+<text text-anchor="middle" x="332" y="-158.3" font-family="Times,serif" font-size="14.00">Above Right Node 3</text>+</g>+<!-- nd_3_r -->+<g id="node6" class="node">+<title>nd_3_r</title>+<ellipse fill="none" stroke="black" cx="324" cy="-90" rx="69.59" ry="18"/>+<text text-anchor="middle" x="324" y="-86.3" font-family="Times,serif" font-size="14.00">Right of Node 3</text>+</g>+<!-- nd_3_a->nd_3_r -->+<g id="edge1" class="edge">+<title>nd_3_a->nd_3_r</title>+<path fill="none" stroke="black" d="M330.02,-143.7C329.14,-135.98 328.08,-126.71 327.1,-118.11"/>+<polygon fill="black" stroke="black" points="330.57,-117.64 325.95,-108.1 323.61,-118.44 330.57,-117.64"/>+</g>+<!-- nd_3_l -->+<g id="node4" class="node">+<title>nd_3_l</title>+<ellipse fill="none" stroke="black" cx="80" cy="-90" rx="64.19" ry="18"/>+<text text-anchor="middle" x="80" y="-86.3" font-family="Times,serif" font-size="14.00">Left of Node 3</text>+</g>+<!-- nd_3_l->nd_3 -->+<g id="edge5" class="edge">+<title>nd_3_l->nd_3</title>+<path fill="none" stroke="grey" d="M144.61,-90C150.28,-90 155.94,-90 161.61,-90"/>+</g>+<!-- nd_3->nd_3_r -->+<g id="edge6" class="edge">+<title>nd_3->nd_3_r</title>+<path fill="none" stroke="grey" d="M236.11,-90C242.17,-90 248.24,-90 254.31,-90"/>+</g>+<!-- nd_4 -->+<g id="node7" class="node">+<title>nd_4</title>+<ellipse fill="none" stroke="black" cx="199" cy="-18" rx="37.09" ry="18"/>+<text text-anchor="middle" x="199" y="-14.3" font-family="Times,serif" font-size="14.00">Node 4</text>+</g>+<!-- nd_3->nd_4 -->+<g id="edge4" class="edge">+<title>nd_3->nd_4</title>+<path fill="none" stroke="black" d="M199,-71.7C199,-63.98 199,-54.71 199,-46.11"/>+<polygon fill="black" stroke="black" points="202.5,-46.1 199,-36.1 195.5,-46.1 202.5,-46.1"/>+</g>+</g>+</svg>
+ other/ex9.svg view
@@ -0,0 +1,68 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">+<!-- Generated by graphviz version 2.49.3 (20211023.0002)+ -->+<!-- Title: D Pages: 1 -->+<svg width="461pt" height="177pt"+ viewBox="0.00 0.00 461.00 177.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 173)">+<title>D</title>+<polygon fill="white" stroke="transparent" points="-4,4 -4,-173 457,-173 457,4 -4,4"/>+<g id="clust1" class="cluster">+<title>cluster_p</title>+<polygon fill="none" stroke="black" points="8,-8 8,-161 445,-161 445,-8 8,-8"/>+<text text-anchor="middle" x="226.5" y="-145.8" font-family="Times,serif" font-size="14.00">Parent</text>+</g>+<g id="clust2" class="cluster">+<title>cluster_c1</title>+<polygon fill="none" stroke="black" points="96,-16 96,-130 437,-130 437,-16 96,-16"/>+<text text-anchor="middle" x="266.5" y="-114.8" font-family="Times,serif" font-size="14.00">Child one</text>+</g>+<g id="clust3" class="cluster">+<title>cluster_gc_1</title>+<polygon fill="none" stroke="black" points="318,-24 318,-99 429,-99 429,-24 318,-24"/>+<text text-anchor="middle" x="373.5" y="-83.8" font-family="Times,serif" font-size="14.00">Grand-Child one</text>+</g>+<g id="clust4" class="cluster">+<title>cluster_gc_2</title>+<polygon fill="none" stroke="black" points="168,-24 168,-99 310,-99 310,-24 168,-24"/>+<text text-anchor="middle" x="239" y="-83.8" font-family="Times,serif" font-size="14.00">Grand-Child two</text>+</g>+<g id="clust5" class="cluster">+<title>cluster_c2</title>+<polygon fill="none" stroke="black" points="16,-24 16,-99 88,-99 88,-24 16,-24"/>+<text text-anchor="middle" x="52" y="-83.8" font-family="Times,serif" font-size="14.00">Child two</text>+</g>+<!-- a -->+<g id="node1" class="node">+<title>a</title>+<ellipse fill="none" stroke="black" cx="131" cy="-50" rx="27" ry="18"/>+<text text-anchor="middle" x="131" y="-46.3" font-family="Times,serif" font-size="14.00">a</text>+</g>+<!-- b -->+<g id="node2" class="node">+<title>b</title>+<ellipse fill="none" stroke="black" cx="373" cy="-50" rx="27" ry="18"/>+<text text-anchor="middle" x="373" y="-46.3" font-family="Times,serif" font-size="14.00">b</text>+</g>+<!-- c -->+<g id="node3" class="node">+<title>c</title>+<ellipse fill="none" stroke="black" cx="275" cy="-50" rx="27" ry="18"/>+<text text-anchor="middle" x="275" y="-46.3" font-family="Times,serif" font-size="14.00">c</text>+</g>+<!-- d -->+<g id="node4" class="node">+<title>d</title>+<ellipse fill="none" stroke="black" cx="203" cy="-50" rx="27" ry="18"/>+<text text-anchor="middle" x="203" y="-46.3" font-family="Times,serif" font-size="14.00">d</text>+</g>+<!-- e -->+<g id="node5" class="node">+<title>e</title>+<ellipse fill="none" stroke="black" cx="52" cy="-50" rx="27" ry="18"/>+<text text-anchor="middle" x="52" y="-46.3" font-family="Times,serif" font-size="14.00">e</text>+</g>+</g>+</svg>
+ other/nh.svg view
@@ -0,0 +1,25 @@+<svg xmlns="http://www.w3.org/2000/svg" width="1044.6129846153847" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-0.5000399999999985 -324.5 678.99844 325.0" height="500.0"><style>svg {+ color-scheme: light dark;+}+{+ .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {+ fill: #0d0d0d;+ }+ .ticklines g, .tickglyph g, .legendBorder g {+ stroke: #0d0d0d;+ }+ .legendBorder g {+ fill: #f0f0f0;+ }+}+@media (prefers-color-scheme:dark) {+ .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {+ fill: #f0f0f0;+ }+ .ticklines g, .tickglyph g, .legendBorder g {+ stroke: #f0f0f0;+ }+ .legendBorder g {+ fill: #0d0d0d;+ }+}</style><g class="chart"><g class="edges"><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 261.71,-107.24 C 234.9900,-119.71 198.5900,-136.69 173.91,-148.21 L 173.62,-148.34"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 142.14,-252.3000 C 134.45,-263.07 124.6,-276.87 116.9000,-287.64 L 116.72,-287.9"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 185.57,-252.12 C 205.09,-262.8900 230.21,-276.73 249.85,-287.56 L 250.31,-287.81"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 376.48,-180.1600 C 375.6900,-199.21 372.0100,-230.15 357.5,-252.0000 C 347.61,-266.8900 331.99,-278.84 317.47,-287.6 L 317.13,-287.8000"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 465.63,-36.124 C 446.95,-47.208 422.75,-61.5610 404.29,-72.516 L 403.8500,-72.774"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 376.5,-108.3 C 376.5,-119.07 376.5,-132.87 376.5,-143.64 L 376.5,-143.9"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 349.23,-104.13 C 345.98,-105.5100 342.69,-106.8400 339.5,-108.0000 C 308.87,-119.16 219.46,-142.43 173.89,-154.07 L 173.62,-154.13"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 196.94,-108.3 C 186.63,-119.07 173.43,-132.87 163.11,-143.64 L 162.87,-143.9"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 376.5,-36.303 C 376.5,-47.069 376.5,-60.866 376.5,-71.642 L 376.5,-71.896"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 230.79,-180.12 C 215.26,-190.8900 195.29,-204.7300 179.67,-215.56 L 179.3000,-215.81"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 261.93,-180.3000 C 265.93,-191.07 271.05,-204.8700 275.05,-215.64 L 275.15,-215.9000"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 281.5,-252.3000 C 281.5,-263.07 281.5,-276.87 281.5,-287.64 L 281.5,-287.9"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 140.48,-108.3 C 141.71,-119.07 143.2800,-132.87 144.52,-143.64 L 144.55,-143.9"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 131.67,-33.503 C 134.99,-34.3890 138.29,-35.2310 141.5,-36.0 C 228.49,-56.813 254.19,-45.118 339.5,-72.0 C 342.64,-72.988 345.85,-74.178 349.02,-75.464 L 349.32,-75.589"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 85.48,-36.185 C 87.094,-54.712 91.3430,-84.678 102.5,-108.0000 C 108.8,-121.1700 119.1,-133.83 128.14,-143.4700 L 128.57,-143.93"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 292.65,-36.124 C 309.72,-46.887 331.67,-60.732 348.84,-71.555 L 349.24,-71.81"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 148.48,-180.3000 C 149.71,-191.07 151.28,-204.8700 152.52,-215.64 L 152.55,-215.9000"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 123.76,-180.3000 C 109.61,-191.07 91.476,-204.8700 77.314,-215.64 L 76.98,-215.9000"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 55.1,-107.24 C 74.311,-118.5400 99.821,-133.54 119.01,-144.83 L 119.46,-145.09"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 66.86,-252.3000 C 74.549,-263.07 84.404,-276.87 92.101,-287.64 L 92.283,-287.9"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 220.02,-32.535 C 223.22,-33.729 226.41,-34.9 229.5,-36.0 C 277.9500,-53.2750 291.61,-53.2310 339.5,-72.0 C 342.56,-73.199 345.73,-74.524 348.87,-75.889 L 349.17,-76.021"/></g><g fill="rgb(0%, 0%, 0%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.0" stroke-opacity="1.0"><path d="M 555.07,-36.0340 C 507.09,-50.2640 440.79,-69.93 403.97,-80.854 L 403.53,-80.982"/></g></g><g class="shapes"><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="71.99992" width="65.00016" y="-324.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="262.00012" width="68.99976000000004" y="-108.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="112.9992" width="83.0016" y="-252.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="344.49996" width="64.00008000000003" y="-180.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="460.50016000000005" width="67.99968000000001" y="-36.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="349.5" width="54.0" y="-108.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="183.50012" width="59.99975999999998" y="-108.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="310.5012" width="131.99760000000003" y="-36.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="225.50012" width="59.99976000000001" y="-180.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="233.5012" width="95.9976" y="-324.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="214.5004" width="133.99919999999997" y="-252.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="111.5" width="54.0" y="-108.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="37.4984" width="94.00319999999999" y="-36.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="238.5" width="54.0" y="-36.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="119.5" width="54.0" y="-180.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="-3.999999999848569e-5" width="55.00008" y="-108.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="14.500399999999999" width="79.9992" y="-252.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="151.00012" width="68.99975999999998" y="-36.0" height="36.0"/></g><g fill="rgb(2%, 73%, 80%)" stroke="rgb(-51%, 30%, 37%)" stroke-width="1.0" fill-opacity="0.2" stroke-opacity="1.0"><rect x="547.0016" width="130.9967999999999" y="-36.0" height="36.0"/></g></g><g class="labels"><g fill="rgb(-51%, 30%, 37%)" stroke="none" stroke-width="0.0" font-size="14.0" fill-opacity="1.0" text-anchor="middle"><text x="104.5" y="-302.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Additive.html#t:Additive">Additive</a></text><text x="296.5" y="-86.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Metric.html#t:Direction">Direction</a></text><text x="154.5" y="-230.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Distributive.html#t:Distributive">Distributive</a></text><text x="376.5" y="-158.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Multiplicative.html#t:Divisive">Divisive</a></text><text x="494.50000000000006" y="-14.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Field.html#t:ExpField">ExpField</a></text><text x="376.5" y="-86.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Field.html#t:Field">Field</a></text><text x="213.5" y="-86.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Data-Integral.html#t:Integral">Integral</a></text><text x="376.5" y="-14.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Field.html#t:LowerBoundedField">LowerBoundedField</a></text><text x="255.5" y="-158.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Module.html#t:Module">Module</a></text><text x="281.5" y="-302.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Multiplicative.html#t:Multiplicative">Multiplicative</a></text><text x="281.5" y="-230.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Module.html#t:MultiplicativeAction">MultiplicativeAction</a></text><text x="138.5" y="-86.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Metric.html#t:Norm">Norm</a></text><text x="84.5" y="-14.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Field.html#t:QuotientField">QuotientField</a></text><text x="265.5" y="-14.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Data-Rational.html#t:Ratio">Ratio</a></text><text x="146.5" y="-158.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Ring.html#t:Ring">Ring</a></text><text x="27.5" y="-86.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Metric.html#t:Signed">Signed</a></text><text x="54.5" y="-230.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Additive.html#t:Subtractive">Subtractive</a></text><text x="185.5" y="-14.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Field.html#t:TrigField">TrigField</a></text><text x="612.5" y="-14.3"><a href="https://hackage.haskell.org/package/numhask/docs/NumHask-Algebra-Field.html#t:UpperBoundedField">UpperBoundedField</a></text></g></g></g><g class="hud"></g></svg>
+ src/DotParse.hs view
@@ -0,0 +1,23 @@+{-# OPTIONS_HADDOCK prune #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Parser & Printer for the dot language of <http://www.graphviz.org/doc/info/lang.html graphviz>+--+-- See "DotParse.Examples" for usage.+--+module DotParse+ ( module DotParse.Types,+ module DotParse.FlatParse,+ module FlatParse.Basic,+ module NeatInterpolation,+ )+where++import DotParse.FlatParse+import DotParse.Types+import FlatParse.Basic hiding (cut, lines)+import NeatInterpolation+import Prelude hiding (replicate)
+ src/DotParse/Examples.hs view
@@ -0,0 +1,610 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# OPTIONS_GHC -Wno-name-shadowing #-}+{-# OPTIONS_GHC -Wno-unused-local-binds #-}++-- | Examples of conversion from dot ByteStrings+module DotParse.Examples where++import qualified Algebra.Graph as G+import Control.Monad+import Data.ByteString hiding (empty, head, length, map, zip, zipWith)+import Data.Proxy+import Data.Text.Encoding (encodeUtf8)+import DotParse+import Optics.Core+import Prelude hiding (replicate)++-- $setup+-- >>> import DotParse+-- >>> import Data.Proxy+-- >>> :set -XOverloadedStrings++-- * examples++-- | minimal definition+--+-- >>> runDotParser ex0 :: Graph+-- Graph {strict = Last {getLast = Just NoMergeEdges}, directed = Last {getLast = Just UnDirected}, graphid = Last {getLast = Nothing}, nodeAttributes = fromList [], graphAttributes = fromList [], edgeAttributes = fromList [], globalAttributes = fromList [], nodes = [], edges = [], subgraphs = []}+--+-- >>> testDotParser (Proxy :: Proxy Graph) defaultDotConfig ex0+ex0 :: ByteString+ex0 =+ encodeUtf8+ [trimming|+graph {}+|]++-- | Examples from https://renenyffenegger.ch/notes/tools/Graphviz/examples/index+--+-- >>> testDotParser (Proxy :: Proxy Graph) defaultDotConfig ex1+--+-- +ex1 :: ByteString+ex1 =+ encodeUtf8+ [trimming|+digraph D {+ A [shape=diamond]+ B [shape=box]+ C [shape=circle]+ A -> B [style=dashed, color=grey]+ A -> C [color="black:invis:black"]+ A -> D [penwidth=5, arrowhead=none]+ }+|]++-- |+-- >>> testDotParser (Proxy :: Proxy Graph) defaultDotConfig ex2+--+-- +ex2 :: ByteString+ex2 =+ encodeUtf8+ [trimming|+digraph D {++ node [fontname="Arial"];++ node_A [shape=record label="shape=record|{above|middle|below}|right"];+ node_B [shape=plaintext label="shape=plaintext|{curly|braces and|bars without}|effect"];++}+|]++-- |+-- >>> testDotParser (Proxy :: Proxy Graph) defaultDotConfig ex3+--+-- +ex3 :: ByteString+ex3 =+ encodeUtf8+ [trimming|+digraph D {+ A -> {B, C, D} -> {F}+}+|]++-- |+--+-- +ex4 :: ByteString+ex4 =+ encodeUtf8+ [trimming|+digraph L {++ node [shape=record fontname=Arial];++ a [label="one\ltwo three\lfour five six seven\l"]+ b [label="one\ntwo three\nfour five six seven"]+ c [label="one\rtwo three\rfour five six seven\r"]++ a -> b -> c++}+|]++-- |+--+-- +ex5 :: ByteString+ex5 =+ encodeUtf8+ [trimming|+digraph D {++ label = "The foo, the bar and the baz";+ labelloc = "t"; // place the label at the top (b seems to be default)++ node [shape=plaintext]++ FOO -> {BAR, BAZ};+++}+|]++-- |+--+-- +ex6 :: ByteString+ex6 =+ encodeUtf8+ [trimming|+digraph D {++ label = <The <font color='red'><b>foo</b></font>,<br/> the <font point-size='20'>bar</font> and<br/> the <i>baz</i>>;+ labelloc = "t"; // place the label at the top (b seems to be default)++ node [shape=plaintext]++ FOO -> {BAR, BAZ};++}+|]++-- |+--+-- +ex7 :: ByteString+ex7 =+ encodeUtf8+ [trimming|+digraph R {++ { rank=same rA sA tA }+ { rank=same uB vB wB }+++ rA -> sA;+ sA -> vB;+ t -> rA;+ uB -> vB;+ wB -> u;+ wB -> tA;++}+|]++-- |+--+-- +ex8 :: ByteString+ex8 =+ encodeUtf8+ [trimming|+digraph Q {++ nd_1 [label = "Node 1"];+ nd_2 [label = "Node 2"];+ nd_3_a [label = "Above Right Node 3"];+ nd_3_l [label = "Left of Node 3"];+ nd_3 [label = "Node 3"];+ nd_3_r [label = "Right of Node 3"];+ nd_4 [label = "Node 4"];+++ nd_3_a -> nd_3_r;+ nd_1 -> nd_2 -> nd_3 -> nd_4;++ subgraph cluster_R {++ {rank=same nd_3_l nd_3 nd_3_r}++ nd_3_l -> nd_3 -> nd_3_r [color=grey arrowhead=none];++ }++}+|]++-- |+--+-- +ex9 :: ByteString+ex9 =+ encodeUtf8+ [trimming|+digraph D {++ subgraph cluster_p {+ label = "Parent";++ subgraph cluster_c1 {+ label = "Child one";+ a;++ subgraph cluster_gc_1 {+ label = "Grand-Child one";+ b;+ }+ subgraph cluster_gc_2 {+ label = "Grand-Child two";+ c;+ d;+ }++ }++ subgraph cluster_c2 {+ label = "Child two";+ e;+ }+ }+}+|]++-- |+--+-- +ex10 :: ByteString+ex10 =+ encodeUtf8+ [trimming|+digraph H {++ aHtmlTable [+ shape=plaintext+ color=blue // The color of the border of the table+ label=<++ <table border='1' cellborder='0'>+ <tr><td>col 1</td><td>foo</td></tr>+ <tr><td>COL 2</td><td>bar</td></tr>+ </table>++ >];++}|]++-- |+--+-- +ex11 :: ByteString+ex11 =+ encodeUtf8+ [trimming|+digraph {++ tbl [++ shape=plaintext+ label=<++ <table border='0' cellborder='1' color='blue' cellspacing='0'>+ <tr><td>foo</td><td>bar</td><td>baz</td></tr>+ <tr><td cellpadding='4'>+ <table color='orange' cellspacing='0'>+ <tr><td>one </td><td>two </td><td>three</td></tr>+ <tr><td>four </td><td>five </td><td>six </td></tr>+ <tr><td>seven</td><td>eight</td><td>nine </td></tr>+ </table>+ </td>+ <td colspan='2' rowspan='2'>+ <table color='pink' border='0' cellborder='1' cellpadding='10' cellspacing='0'>+ <tr><td>eins</td><td>zwei</td><td rowspan='2'>drei<br/>sechs</td></tr>+ <tr><td>vier</td><td>fünf</td> </tr>+ </table>+ </td>+ </tr>++ <tr><td>abc</td></tr>++ </table>++ >];++}+|]++-- |+--+-- +ex12 :: ByteString+ex12 =+ encodeUtf8+ [trimming|+digraph D {++ node [shape=plaintext]++ some_node [+ label=<+ <table border="0" cellborder="1" cellspacing="0">+ <tr><td bgcolor="yellow">Foo</td></tr>+ <tr><td bgcolor="lightblue"><font color="#0000ff">Bar</font></td></tr>+ <tr><td bgcolor="#f0e3ff"><font color="#ff1020">Baz</font></td></tr>+ </table>>+ ];+}+|]++-- |+--+-- +ex13 :: ByteString+ex13 =+ encodeUtf8+ [trimming|+digraph H {++ aHtmlTable [+ shape=plaintext+ label=<++ <table border='1' cellborder='0' style='rounded'>+ <tr><td>col 1</td><td>foo</td></tr>+ <tr><td>COL 2</td><td>bar</td></tr>+ </table>++ >];++}+|]++-- |+--+-- +ex14 :: ByteString+ex14 =+ encodeUtf8+ [trimming|+digraph H {++ parent [+ shape=plaintext+ label=<+ <table border='1' cellborder='1'>+ <tr><td colspan="3">The foo, the bar and the baz</td></tr>+ <tr><td port='port_one'>First port</td><td port='port_two'>Second port</td><td port='port_three'>Third port</td></tr>+ </table>+ >];++ child_one [+ shape=plaintext+ label=<+ <table border='1' cellborder='0'>+ <tr><td>1</td></tr>+ </table>+ >];++ child_two [+ shape=plaintext+ label=<+ <table border='1' cellborder='0'>+ <tr><td>2</td></tr>+ </table>+ >];++ child_three [+ shape=plaintext+ label=<+ <table border='1' cellborder='0'>+ <tr><td>3</td></tr>+ </table>+ >];++ parent:port_one -> child_one;+ parent:port_two -> child_two;+ parent:port_three -> child_three;++}+|]++-- |+--+-- +ex15 :: ByteString+ex15 =+ encodeUtf8+ [trimming|+digraph D {++ node [shape=plaintext fontname="Sans serif" fontsize="8"];++ task_menu [ label=<+ <table border="1" cellborder="0" cellspacing="1">+ <tr><td align="left"><b>Task 1</b></td></tr>+ <tr><td align="left">Choose Menu</td></tr>+ <tr><td align="left"><font color="darkgreen">done</font></td></tr>+ </table>>];++ task_ingredients [ label=<+ <table border="1" cellborder="0" cellspacing="1">+ <tr><td align="left"><b>Task 2</b></td></tr>+ <tr><td align="left">Buy ingredients</td></tr>+ <tr><td align="left"><font color="darkgreen">done</font></td></tr>+ </table>>];++ task_invitation [ label=<+ <table border="1" cellborder="0" cellspacing="1">+ <tr><td align="left"><b>Task 4</b></td></tr>+ <tr><td align="left">Send invitation</td></tr>+ <tr><td align="left"><font color="darkgreen">done</font></td></tr>+ </table>>];++ task_cook [ label=<+ <table border="1" cellborder="0" cellspacing="1">+ <tr><td align="left"><b>Task 5</b></td></tr>+ <tr><td align="left">Cook</td></tr>+ <tr><td align="left"><font color="red">todo</font></td></tr>+ </table>>];++ task_table[ label=<+ <table border="1" cellborder="0" cellspacing="1">+ <tr><td align="left"><b>Task 3</b></td></tr>+ <tr><td align="left">Lay table</td></tr>+ <tr><td align="left"><font color="red">todo</font></td></tr>+ </table>>];++ task_eat[ label=<+ <table border="1" cellborder="0" cellspacing="1">+ <tr><td align="left"><b>Task 6</b></td></tr>+ <tr><td align="left">Eat</td></tr>+ <tr><td align="left"><font color="red">todo</font></td></tr>+ </table>>];+++ task_menu -> task_ingredients;+ task_ingredients -> task_cook;+ task_invitation -> task_cook;+ task_table -> task_eat;+ task_cook -> task_eat;++}+|]++-- | Test all the examples+testAll :: IO ()+testAll =+ zipWithM_+ (>>)+ ( putStrLn+ <$> [ "ex0",+ "ex1",+ "ex2",+ "ex3",+ "ex4",+ "ex5",+ "ex6",+ "ex7",+ "ex8",+ "ex9",+ "ex10",+ "ex11",+ "ex12",+ "ex13",+ "ex14",+ "ex15"+ ]+ )+ ( testDotParser (Proxy :: Proxy Graph) defaultDotConfig+ <$> [ex0, ex1, ex2, ex3, ex4, ex5, ex6, ex7, ex8, ex9, ex10, ex11, ex12, ex13, ex14, ex15]+ )++-- | Render all the examples+svgAll :: IO ()+svgAll =+ zipWithM_+ (>>)+ ( putStrLn+ <$> [ "ex0",+ "ex1",+ "ex2",+ "ex3",+ "ex4",+ "ex5",+ "ex6",+ "ex7",+ "ex8",+ "ex9",+ "ex10",+ "ex11",+ "ex12",+ "ex13",+ "ex14",+ "ex15"+ ]+ )+ ( zipWith+ (\b f -> processDotWith Directed ["-Tsvg", "-oother/" <> f <> ".svg"] b)+ [ex0, ex1, ex2, ex3, ex4, ex5, ex6, ex7, ex8, ex9, ex10, ex11, ex12, ex13, ex14, ex15]+ [ "ex0",+ "ex1",+ "ex2",+ "ex3",+ "ex4",+ "ex5",+ "ex6",+ "ex7",+ "ex8",+ "ex9",+ "ex10",+ "ex11",+ "ex12",+ "ex13",+ "ex14",+ "ex15"+ ]+ )++-- | algebraic graph example+exGInt :: G.Graph Int+exGInt =+ G.edges $+ [(v, (v + 1) `mod` 6) | v <- [0 .. 5]]+ ++ [(v, v + k) | v <- [0 .. 5], k <- [6, 12]]+ ++ [(2, 18), (2, 19), (15, 18), (15, 19), (18, 3), (19, 3)]++-- |+--+-- > exInt = defaultGraph & addStatements (toStatements Directed (packUTF8 . show <$> exGInt))+-- > import qualified Data.ByteString.Char8 as B+-- > g <- processGraph exInt+-- > B.putStrLn $ dotPrint g+-- digraph {+-- graph [bb="0,0,495.65,493.78";overlap=false;size="1!";splines=spline]+-- node [height=0.5;label="\N";shape=circle]+-- edge [arrowsize=0]+-- 0 [pos="384.5,475.78";width=0.5]+-- 1 [pos="357.5,401.63";width=0.5]+-- 0 -> 1 [pos="e,363.57,418.85 378.51,458.77 374.1,446.99 368.12,431.02 363.67,419.13"]+-- 6 [pos="411.5,401.63";width=0.5]+-- 0 -> 6 [pos="e,405.43,418.85 390.49,458.77 394.9,446.99 400.87,431.02 405.32,419.13"]+-- 12 [height=0.55967;pos="467.5,401.63";width=0.55967]+-- 0 -> 12 [pos="e,452.8,415.41 397.83,463.19 412.75,450.22 436.85,429.27 452.43,415.73"]+-- 2 [pos="330.5,325.33";width=0.5]+-- 1 -> 2 [pos="e,336.35,342.42 351.64,384.51 347.15,372.14 340.97,355.15 336.45,342.72"]+-- 7 [pos="384.5,325.33";width=0.5]+-- 1 -> 7 [pos="e,378.65,342.42 363.36,384.51 367.85,372.14 374.03,355.15 378.54,342.72"]+-- 13 [height=0.55967;pos="440.5,325.33";width=0.55967]+-- 1 -> 13 [pos="e,425.95,339.36 370.47,389.02 385.4,375.66 409.87,353.75 425.58,339.69"]+-- 3 [pos="263.5,249.04";width=0.5]+-- 2 -> 3 [pos="e,275.26,263.08 318.83,311.39 306.7,297.94 287.81,277 275.55,263.4"]+-- 8 [pos="419.5,249.04";width=0.5]+-- 2 -> 8 [pos="e,406.15,261.18 344.02,313.05 360.71,299.11 388.95,275.54 405.75,261.51"]+-- 14 [height=0.55967;pos="475.5,249.04";width=0.55967]+-- 2 -> 14 [pos="e,459.28,261.56 344.39,313.55 348.48,310.63 353.06,307.61 357.5,305.19 394.93,284.71 408.73,289.04 446.5,269.19 450.64,267.01 454.93,\+-- 264.4 458.9,261.81"]+-- 18 [height=0.55967;pos="239.5,96.445";width=0.55967]+-- 2 -> 18 [pos="e,221.18,105.3 313.92,317.87 277.75,302.66 192.9,260.73 166.5,192.89 160,176.2 158.52,168.63 166.5,152.59 177.74,130.02 203.11,114.24 \+-- 220.76,105.5"]+-- 19 [height=0.55967;pos="335.5,96.445";width=0.55967]+-- 2 -> 19 [pos="e,335.94,116.84 331.52,307.33 332.98,282.28 335.56,234 336.5,192.89 336.91,174.98 336.66,170.5 336.5,152.59 336.39,140.81 336.16,\+-- 127.62 335.94,117.09"]+-- 4 [pos="101.5,172.74";width=0.5]+-- 3 -> 4 [pos="e,117.56,181.11 247.37,240.64 216.44,226.46 149.09,195.57 117.92,181.27"]+-- 9 [pos="193.5,172.74";width=0.5]+-- 3 -> 9 [pos="e,205.67,186.66 251.62,235.43 238.93,221.96 218.89,200.69 205.97,186.98"]+-- 15 [height=0.55967;pos="287.5,172.74";width=0.55967]+-- 3 -> 15 [pos="e,281.6,192.01 268.82,231.55 272.58,219.93 277.61,204.35 281.51,192.29"]+-- 5 [pos="48.498,96.445";width=0.5]+-- 4 -> 5 [pos="e,58.506,111.47 91.279,157.42 81.908,144.28 68.101,124.92 58.727,111.78"]+-- 10 [height=0.55967;pos="104.5,96.445";width=0.55967]+-- 4 -> 10 [pos="e,103.72,116.67 102.19,154.51 102.65,143.28 103.24,128.61 103.71,116.95"]+-- 16 [height=0.55967;pos="162.5,96.445";width=0.55967]+-- 4 -> 16 [pos="e,150.12,112.52 112.69,158.11 123.2,145.31 138.91,126.18 149.86,112.83"]+-- 5 -> 0 [pos="e,366.23,475.02 49.439,114.6 50.887,142.55 53.498,199.64 53.498,248.04 53.498,326.33 53.498,326.33 53.498,326.33 53.498,464.3 295.89,\+-- 474.85 365.82,475.02"]+-- 11 [height=0.54162;pos="19.498,20.148";width=0.54162]+-- 5 -> 11 [pos="e,26.284,38.534 42.206,79.323 37.545,67.382 31.197,51.119 26.397,38.823"]+-- 17 [height=0.55967;pos="77.498,20.148";width=0.55967]+-- 5 -> 17 [pos="e,70.506,39.061 54.791,79.323 59.386,67.552 65.62,51.579 70.394,39.349"]+-- 15 -> 18 [pos="e,250.12,113.89 276.85,155.25 268.95,143.04 258.24,126.45 250.31,114.18"]+-- 15 -> 19 [pos="e,324.88,113.89 298.15,155.25 306.04,143.04 316.76,126.45 324.69,114.18"]+-- 18 -> 3 [pos="e,260.79,231.06 242.53,116.49 247.24,145.99 256.21,202.31 260.74,230.72"]+-- 19 -> 3 [pos="e,277.53,237.38 334.82,116.79 333.41,136.85 329.16,168.62 316.5,192.89 307.11,210.88 290.05,227.04 277.82,237.15"]+-- }+exInt :: Graph+exInt = defaultGraph & addStatements (toStatements Directed (packUTF8 . show <$> exGInt))
+ src/DotParse/Examples/NumHask.hs view
@@ -0,0 +1,246 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}++{-# HLINT ignore "Use ?~" #-}++-- | Example of Dot graph construction for the NumHask class heirarchy.+module DotParse.Examples.NumHask where++import qualified Algebra.Graph as G+import Chart+import Data.Bifunctor+import qualified Data.Map.Strict as Map+import Data.Monoid+import Data.Text (Text, pack)+import DotParse+import GHC.IO.Unsafe+import Optics.Core+import Prelude hiding (replicate)++-- $setup+-- >>> import DotParse+-- >>> :set -XOverloadedStrings++data Class+ = Magma+ | Unital+ | Associative+ | Commutative+ | Invertible+ | Idempotent+ | Absorbing+ | Group+ | AbelianGroup+ | Additive+ | Subtractive+ | Multiplicative+ | Divisive+ | Distributive+ | Semiring+ | Ring+ | IntegralDomain+ | Field+ | ExpField+ | QuotientField+ | UpperBoundedField+ | LowerBoundedField+ | TrigField+ | -- Higher-kinded numbers+ AdditiveAction+ | SubtractiveAction+ | MultiplicativeAction+ | DivisiveAction+ | Module+ | -- Lattice+ JoinSemiLattice+ | MeetSemiLattice+ | Lattice+ | BoundedJoinSemiLattice+ | BoundedMeetSemiLattice+ | BoundedLattice+ | -- Number Types+ Integral+ | Ratio+ | -- Measure+ Signed+ | Norm+ | Basis+ | Direction+ | Epsilon+ deriving (Show, Eq, Ord)++data Family+ = Addition+ | Multiplication+ | Actor+ deriving (Show, Eq, Ord)++data Dependency = Dependency+ { _class :: Class,+ _dep :: Class,+ _op :: Maybe Family+ }+ deriving (Show, Eq, Ord)++dependencies :: [Dependency]+dependencies =+ [ Dependency Unital Magma Nothing,+ Dependency Associative Magma Nothing,+ Dependency Commutative Magma Nothing,+ Dependency Invertible Magma Nothing,+ Dependency Idempotent Magma Nothing,+ Dependency Absorbing Magma Nothing,+ Dependency Group Unital Nothing,+ Dependency Group Invertible Nothing,+ Dependency Group Associative Nothing,+ Dependency AbelianGroup Unital Nothing,+ Dependency AbelianGroup Invertible Nothing,+ Dependency AbelianGroup Associative Nothing,+ Dependency AbelianGroup Commutative Nothing,+ Dependency Additive Commutative (Just Addition),+ Dependency Additive Unital (Just Addition),+ Dependency Additive Associative (Just Addition),+ Dependency Subtractive Invertible (Just Addition),+ Dependency Subtractive Additive (Just Addition),+ Dependency Multiplicative Unital (Just Multiplication),+ Dependency Multiplicative Associative (Just Multiplication),+ Dependency Multiplicative Commutative (Just Multiplication),+ Dependency Divisive Invertible (Just Multiplication),+ Dependency Divisive Multiplicative (Just Multiplication),+ Dependency Distributive Additive (Just Addition),+ Dependency Distributive Multiplicative (Just Multiplication),+ Dependency Distributive Absorbing Nothing,+ Dependency Ring Distributive Nothing,+ Dependency Ring Subtractive (Just Addition),+ Dependency IntegralDomain Ring Nothing,+ Dependency Field Ring Nothing,+ Dependency Field Divisive (Just Multiplication),+ Dependency ExpField Field Nothing,+ Dependency QuotientField Field Nothing,+ Dependency QuotientField Ring Nothing,+ Dependency TrigField Field Nothing,+ Dependency UpperBoundedField Field Nothing,+ Dependency LowerBoundedField Field Nothing,+ -- higher-kinded relationships+ Dependency AdditiveAction Additive (Just Actor),+ Dependency SubtractiveAction Subtractive (Just Actor),+ Dependency MultiplicativeAction Multiplicative (Just Actor),+ Dependency DivisiveAction Divisive (Just Actor),+ Dependency Module Distributive (Just Actor),+ Dependency Module MultiplicativeAction Nothing,+ -- Lattice+ Dependency JoinSemiLattice Associative Nothing,+ Dependency JoinSemiLattice Commutative Nothing,+ Dependency JoinSemiLattice Idempotent Nothing,+ Dependency MeetSemiLattice Associative Nothing,+ Dependency MeetSemiLattice Commutative Nothing,+ Dependency MeetSemiLattice Idempotent Nothing,+ Dependency Lattice JoinSemiLattice Nothing,+ Dependency Lattice MeetSemiLattice Nothing,+ Dependency BoundedJoinSemiLattice JoinSemiLattice Nothing,+ Dependency BoundedJoinSemiLattice Unital Nothing,+ Dependency BoundedMeetSemiLattice MeetSemiLattice Nothing,+ Dependency BoundedMeetSemiLattice Unital Nothing,+ Dependency BoundedLattice BoundedJoinSemiLattice Nothing,+ Dependency BoundedLattice BoundedMeetSemiLattice Nothing,+ Dependency Signed Ring Nothing,+ Dependency Norm Ring Nothing,+ Dependency Basis Ring Nothing,+ Dependency Direction Ring Nothing,+ Dependency Epsilon Subtractive Nothing,+ Dependency Epsilon MeetSemiLattice Nothing,+ Dependency Integral Ring Nothing,+ Dependency Ratio Field Nothing+ ]++classesNH :: [Class]+classesNH =+ [ Additive,+ Subtractive,+ Multiplicative,+ Divisive,+ Distributive,+ Ring,+ Field,+ ExpField,+ QuotientField,+ TrigField,+ Signed,+ Norm,+ Direction,+ MultiplicativeAction,+ Module,+ UpperBoundedField,+ LowerBoundedField,+ Integral,+ Ratio+ ]++classesModule :: [(Class, Text)]+classesModule =+ [ (Additive, "NumHask-Algebra-Additive"),+ (Subtractive, "NumHask-Algebra-Additive"),+ (Multiplicative, "NumHask-Algebra-Multiplicative"),+ (Divisive, "NumHask-Algebra-Multiplicative"),+ (Distributive, "NumHask-Algebra-Distributive"),+ (Ring, "NumHask-Algebra-Ring"),+ (Field, "NumHask-Algebra-Field"),+ (ExpField, "NumHask-Algebra-Field"),+ (QuotientField, "NumHask-Algebra-Field"),+ (TrigField, "NumHask-Algebra-Field"),+ (Signed, "NumHask-Algebra-Metric"),+ (Norm, "NumHask-Algebra-Metric"),+ (Direction, "NumHask-Algebra-Metric"),+ (MultiplicativeAction, "NumHask-Algebra-Module"),+ (Module, "NumHask-Algebra-Module"),+ (UpperBoundedField, "NumHask-Algebra-Field"),+ (LowerBoundedField, "NumHask-Algebra-Field"),+ (Integral, "NumHask-Data-Integral"),+ (Ratio, "NumHask-Data-Rational")+ ]++dependenciesNH :: [Dependency] -> [Dependency]+dependenciesNH = filter (\(Dependency x0 x1 _) -> x0 `elem` classesNH && x1 `elem` classesNH)++-- | NumHask Classes as an algebraic graph+graphNHG :: G.Graph Class+graphNHG =+ G.edges ((\(Dependency x y _) -> (x, y)) <$> dependenciesNH dependencies)+ <> G.vertices classesNH++-- | NumHask statements in a dot Graph with box shapes for the nodes.+dotGraphNH :: Directed -> Graph+dotGraphNH d =+ defaultGraph+ & #directed .~ Last (Just d)+ & addStatements (toStatements d (packUTF8 . show <$> graphNHG))+ & attL NodeType (ID "shape") .~ Just (ID "box")+ & gattL (ID "rankdir") .~ Just (IDQuoted "BT")++-- | 'dotGraphNH' after being positionally processed via 'processGraph'+dotGraphNH' :: Directed -> Graph+dotGraphNH' d = unsafePerformIO $ processGraph (dotGraphNH d)+{-# NOINLINE dotGraphNH' #-}++-- | Convert a node ID to a label for chart-svg charts+--+-- Doing this directly in dot doesn't quite work because the engines get the width of the link wrong.+toLink :: ID -> Text+toLink i = [trimming|<a href="https://hackage.haskell.org/package/numhask/docs/$m.html#t:$t">$t</a>|]+ where+ t = pack (label i)+ m = Map.fromList (first (pack . show) <$> classesModule) Map.! t++-- | A chart-svg chart with label links+--+-- > writeChartSvg "other/nh.svg" (graphToChart toLink (dotGraphNH' Directed))+--+-- +writeNHChart :: IO ()+writeNHChart = writeChartSvg "other/nh.svg" (graphToChartWith (defaultChartConfig & #labelf .~ toLink) (dotGraphNH' Directed))
+ src/DotParse/FlatParse.hs view
@@ -0,0 +1,226 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}++{-# HLINT ignore "Use <$>" #-}++-- | Lower-level flatparse parsers+module DotParse.FlatParse+ ( Error (..),+ prettyError,+ keyword,+ keyword',+ symbol,+ symbol',+ ws,+ token,+ ident,+ cut,+ cut',+ testParser,+ runParser_,+ int,+ double,+ signed,+ quoted,+ htmlLike,+ sepP,+ wrapSquareP,+ wrapSquarePrint,+ wrapCurlyP,+ wrapCurlyPrint,+ wrapQuotePrint,+ pointP,+ Spline (..),+ splineP,+ rectP,+ boolP,+ nonEmptyP,+ )+where++import Data.Bool+import Data.ByteString hiding (empty, head, length, map, zip, zipWith)+import qualified Data.ByteString.Char8 as B+import Data.Char hiding (isDigit)+import Data.List.NonEmpty+import DotParse.FlatParse.TH hiding (merge)+import FlatParse.Basic hiding (cut, lines)+import GHC.Generics+import NumHask.Space+import Prelude hiding (replicate)++-- $setup+-- >>> import DotParse+-- >>> import FlatParse.Basic++-- | Run parser, print pretty error on failure.+testParser :: Show a => Parser Error a -> ByteString -> IO ()+testParser p b =+ case runParser p b of+ Err e -> B.putStrLn $ prettyError b e+ OK a _ -> print a+ Fail -> B.putStrLn "uncaught parse error"++-- | run a Parser, erroring on leftovers, Fail or Err+runParser_ :: Parser Error a -> ByteString -> a+runParser_ p b = case runParser p b of+ OK r "" -> r+ OK _ x -> error $ unpackUTF8 $ "leftovers: " <> x+ Fail -> error "Fail"+ Err e -> error $ unpackUTF8 $ prettyError b e++-- * parsing++digit :: Parser Error Int+digit = (\c -> ord c - ord '0') <$> satisfyASCII isDigit++-- | (unsigned) Int parser+int :: Parser Error Int+int = token do+ (place, n) <- chainr (\n (!place, !acc) -> (place * 10, acc + place * n)) digit (pure (1, 0))+ case place of+ 1 -> empty+ _ -> pure n++digits :: Parser Error (Int, Int)+digits = chainr (\n (!place, !acc) -> (place * 10, acc + place * n)) digit (pure (1, 0))++-- |+-- >>> runParser double "1.234x"+-- OK 1.234 "x"+--+-- >>> runParser double "."+-- Fail+--+-- >>> runParser double "123"+-- OK 123.0 ""+--+-- >>> runParser double ".123"+-- OK 0.123 ""+--+-- >>> runParser double "123."+-- OK 123.0 ""+double :: Parser Error Double+double = token do+ (placel, nl) <- digits+ optioned+ ($(char '.') *> digits)+ ( \(placer, nr) ->+ case (placel, placer) of+ (1, 1) -> empty+ _ -> pure $ fromIntegral nl + fromIntegral nr / fromIntegral placer+ )+ ( case placel of+ 1 -> empty+ _ -> pure $ fromIntegral nl+ )++-- |+-- >>> runParser (signed double) "-1.234x"+-- OK (-1.234) "x"+signed :: Num b => Parser e b -> Parser e b+signed p = optioned $(char '-') (const (((-1) *) <$> p)) p++-- | Looks ahead for a "/"" that may be in the quoted string.+-- >>> runParser quoted (packUTF8 "\"hello\"")+-- OK "hello" ""+--+-- >>> runParser quoted (packUTF8 "\"hello/\"\"")+-- OK "hello\"" ""+quoted :: Parser Error String+quoted =+ $(symbol "\"") *> many unquoteQuote <* $(symbol' "\"")++unquoteQuote :: Parser Error Char+unquoteQuote = do+ next <- satisfy (/= '"')+ case next of+ '/' -> branch (lookahead $(char '"')) ('"' <$ $(char '"')) (pure '/')+ x -> pure x++-- | optional separators+sepP :: Parser e ()+sepP =+ token+ $( switch+ [|+ case _ of+ ";" -> pure ()+ "," -> pure ()+ |]+ )++-- | parse wrapping square brackets+wrapSquareP :: Parser Error a -> Parser Error a+wrapSquareP p =+ $(symbol "[") *> p <* $(symbol' "]")++-- | print wrapping square brackets+wrapSquarePrint :: ByteString -> ByteString+wrapSquarePrint b = "[" <> b <> "]"++-- | print wrapping quotes+wrapQuotePrint :: ByteString -> ByteString+wrapQuotePrint b = "\"" <> b <> "\""++-- | parse wrapping square brackets+wrapCurlyP :: Parser Error a -> Parser Error a+wrapCurlyP p = $(symbol "{") *> p <* $(symbol' "}")++-- | print wrapping curly brackets+wrapCurlyPrint :: ByteString -> ByteString+wrapCurlyPrint b = "{" <> b <> "}"++-- | comma separated Point+pointP :: Parser Error (Point Double)+pointP = token $ Point <$> double <*> ($(symbol ",") *> double)++-- | dot specification of a cubic spline (and an arrow head which is ignored here)+data Spline = Spline {splineEnd :: Maybe (Point Double), splineStart :: Maybe (Point Double), splineP1 :: Point Double, splineTriples :: [(Point Double, Point Double, Point Double)]} deriving (Eq, Show, Generic)++-- |+-- http://www.graphviz.org/docs/attr-types/splineType/+splineP :: Parser Error Spline+splineP =+ Spline+ <$> optional ($(symbol "e,") *> pointP)+ <*> optional ($(symbol "s") *> pointP)+ <*> pointP+ <*> some ((,,) <$> pointP <*> pointP <*> pointP)++-- | comma separated rectangle or bounding box+rectP :: Parser Error (Rect Double)+rectP = token $ do+ x <- double+ _ <- $(symbol ",")+ y <- double+ _ <- $(symbol ",")+ z <- double+ _ <- $(symbol ",")+ w <- double+ pure $ Rect x z y w++-- | true | false+boolP :: Parser Error Bool+boolP =+ (True <$ $(symbol "true"))+ <|> (False <$ $(symbol "false"))++-- | NonEmpty version of many+nonEmptyP :: Parser e a -> Parser e () -> Parser e (NonEmpty a)+nonEmptyP p sep = token $ do+ s <- p+ xs <- many (optional sep *> p)+ pure (s :| xs)
+ src/DotParse/FlatParse/TH.hs view
@@ -0,0 +1,206 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -Wno-name-shadowing #-}+{-# OPTIONS_GHC -Wno-unused-local-binds #-}++-- | TH stage restriction guff for flatparsing+module DotParse.FlatParse.TH where++import Data.ByteString hiding (head, length, reverse)+import qualified Data.ByteString.Char8 as B+import Data.Functor+import FlatParse.Basic+import Language.Haskell.TH++-- | Consume whitespace.+ws :: Parser e ()+ws =+ $( switch+ [|+ case _ of+ -- order matters+ " " -> ws+ "\\\n" -> ws+ "\\\\\\n" -> ws+ "\n" -> ws+ "\t" -> ws+ "\r" -> ws+ ";" -> ws+ "//" -> lineComment+ "/*" -> multilineComment+ _ -> pure ()+ |]+ )++-- | Consume whitespace after running a parser.+token :: Parser e a -> Parser e a+token p = p <* ws+{-# INLINE token #-}++-- | Parse a line comment.+lineComment :: Parser e ()+lineComment =+ optioned+ anyWord8+ ( \case+ 10 -> ws+ _ -> lineComment+ )+ (pure ())++-- | Parse a potentially nested multiline comment.+multilineComment :: Parser e ()+multilineComment = go (1 :: Int)+ where+ go 0 = ws+ go n =+ $( switch+ [|+ case _ of+ "*/" -> go (n - 1)+ "/*" -> go (n + 1)+ _ -> branch anyWord8 (go n) (pure ())+ |]+ )++-- | Parse a HTML-Like string by counting the angle brackets+htmlLike :: Parser e String+htmlLike = ws *> $(char '<') *> go (1 :: Int) "<"+ where+ go 0 acc = ws $> reverse acc+ go n acc =+ ($(char '>') *> go (n - 1) ('>' : acc))+ <|> ($(char '<') *> go (n + 1) ('<' : acc))+ <|> (anyChar >>= (\c -> go n (c : acc)))++-- | First character of a dot identifier.+isValidStartChar :: Char -> Bool+isValidStartChar c =+ ('A' <= c && c <= 'Z')+ || ('a' <= c && c <= 'z')+ || ('\200' <= c && c <= '\377')+ || (c == '_')++-- | character of a dot identifier.+isValidChar :: Char -> Bool+isValidChar c = isValidStartChar c || isDigit c++-- | Read a starting character of an identifier.+identStartChar :: Parser e Char+identStartChar = satisfy isValidStartChar++-- | Read a non-starting character of an identifier.+identChar :: Parser e Char+identChar = satisfy isValidChar++-- | Parse a non-keyword string.+symbol :: String -> Q Exp+symbol str = [|token $(string str)|]++-- | Parse a keyword string.+keyword :: String -> Q Exp+keyword str = [|token ($(string str) `notFollowedBy` identChar)|]++-- | Parser a non-keyword string, throw precise error on failure.+symbol' :: String -> Q Exp+symbol' str = [|$(symbol str) `cut'` packUTF8 str|]++-- | Parse a keyword string, throw precise error on failure.+keyword' :: String -> Q Exp+keyword' str = [|$(keyword str) `cut'` packUTF8 str|]++-- | Parse an identifier.+ident :: Parser e ByteString+ident =+ token $+ byteStringOf $+ identStartChar *> many_ identChar++-- | Parse an identifier, throw a precise error on failure.+ident' :: Parser Error ByteString+ident' = ident `cut'` "identifier"++-- | A parsing error.+data Error+ = -- | A precisely known error, like leaving out "in" from "let".+ Precise Pos ByteString+ | -- | An imprecise error, when we expect a number of different things,+ -- but parse something else.+ Imprecise Pos [ByteString]+ deriving (Eq, Show)++-- | position of error+errorPos :: Error -> Pos+errorPos (Precise p _) = p+errorPos (Imprecise p _) = p++-- | Merge two errors. Inner errors (which were thrown at points with more consumed inputs)+-- are preferred. If errors are thrown at identical input positions, we prefer precise errors+-- to imprecise ones.+--+-- The point of prioritizing inner and precise errors is to suppress the deluge of "expected"+-- items, and instead try to point to a concrete issue to fix.+merge :: Error -> Error -> Error+merge e e' = case (errorPos e, errorPos e') of+ (p, p') | p < p' -> e'+ (p, p') | p > p' -> e+ (p, _) -> case (e, e') of+ (Precise {}, _) -> e+ (_, Precise {}) -> e'+ (Imprecise _ es, Imprecise _ es') -> Imprecise p (es ++ es')+{-# NOINLINE merge #-} -- merge is "cold" code, so we shouldn't inline it.++-- | Pretty print an error. The `ByteString` input is the source file. The offending line from the+-- source is displayed in the output.+prettyError :: ByteString -> Error -> ByteString+prettyError b e =+ let pos :: Pos+ pos = case e of+ Imprecise pos _ -> pos+ Precise pos _ -> pos+ ls = B.lines b+ (l, c) = head $ posLineCols b [pos]+ line = if l < length ls then ls !! l else ""+ linum = packUTF8 $ show l+ lpad = B.replicate (B.length linum) ' '++ err (Precise _ e) = e+ err (Imprecise _ es) = imprec es++ imprec :: [ByteString] -> ByteString+ imprec [] = error "impossible"+ imprec [e] = e+ imprec (e : es) = e <> go es+ where+ go [] = ""+ go [e] = " or " <> e+ go (e : es) = ", " <> e <> go es+ in packUTF8 (show l) <> ":" <> packUTF8 (show c) <> ":\n"+ <> lpad+ <> "|\n"+ <> linum+ <> "| "+ <> line+ <> "\n"+ <> lpad+ <> "| "+ <> B.replicate c ' '+ <> "^\n"+ <> "parse error: expected "+ <> err e++-- | Imprecise cut: we slap a list of items on inner errors.+cut :: Parser Error a -> [ByteString] -> Parser Error a+cut p es = do+ pos <- getPos+ cutting p (Imprecise pos es) merge++-- | Precise cut: we propagate at most a single error.+cut' :: Parser Error a -> ByteString -> Parser Error a+cut' p e = do+ pos <- getPos+ cutting p (Precise pos e) merge
+ src/DotParse/Types.hs view
@@ -0,0 +1,881 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# HLINT ignore "Use unwords" #-}+{-# HLINT ignore "Use <$>" #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# OPTIONS_GHC -Wno-name-shadowing #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}+{-# OPTIONS_HADDOCK not-home #-}++-- | Abstract Grammar for the dot language.+-- http://www.graphviz.org/doc/info/lang.html+module DotParse.Types+ ( DotConfig (..),+ defaultDotConfig,+ DotParse (..),+ testDotParser,+ runDotParser,+ Error (..),+ prettyError,+ Graph (..),+ gattL,+ attL,+ defaultGraph,+ processDotWith,+ processDot,+ processGraph,+ processGraphWith,++ -- * components+ Strict (..),+ defStrict,+ Directed (..),+ defDirected,+ ID (..),+ label,+ Compass (..),+ Port (..),+ AttributeType (..),+ AttributeStatement (..),+ NodeStatement (..),+ EdgeID (..),+ EdgeOp (..),+ fromDirected,+ EdgeStatement (..),+ edgeID,+ edgeIDs,+ edgeIDsNamed,+ Statement (..),+ addStatement,+ addStatements,+ SubGraphStatement (..),++ -- * Graph Extraction+ bbL,+ nodesPortL,+ nodesL,+ edgesL,+ nodesA,+ edgesA,+ nodePos,+ nodeWidth,+ edgeSpline,+ edgeWidth,+ NodeInfo (..),+ nodeInfo,+ EdgeInfo (..),+ edgeInfo,+ splinePath,++ -- * Conversion+ graphToChartWith,+ graphToChart,+ ChartConfig (..),+ defaultChartConfig,+ toStatements,+ toDotGraph,+ toDotGraphWith,+ )+where++import qualified Algebra.Graph as G+import Chart+import Control.Monad+import Data.Bool+import Data.ByteString hiding (any, empty, filter, head, length, map, zip, zipWith)+import qualified Data.ByteString.Char8 as B+import Data.List.NonEmpty hiding (filter, head, length, map, zip, zipWith, (!!))+import Data.Map.Merge.Strict+import qualified Data.Map.Strict as Map+import Data.Maybe+import Data.Monoid+import Data.Proxy+import Data.Text (Text)+import qualified Data.Text as Text+import Data.Text.Encoding (encodeUtf8)+import Data.These+import DotParse.FlatParse+import FlatParse.Basic hiding (cut, lines)+import GHC.Generics+import NeatInterpolation+import Optics.Core+import System.Exit+import System.Process.ByteString+import Prelude hiding (replicate)++-- $setup+-- >>> import DotParse+-- >>> import qualified Data.Map as Map+-- >>> :set -XOverloadedStrings++-- | printing options, for separators.+data DotConfig = DotConfig+ { topLevelSep :: ByteString,+ statementSep :: ByteString,+ attSep :: ByteString,+ subGraphSep :: ByteString+ }+ deriving (Eq, Show, Generic)++-- | default separators+defaultDotConfig :: DotConfig+defaultDotConfig = DotConfig " " "\n " ";" ";"++-- | A parser & printer class for a graphviz graph and components of its dot language+class DotParse a where+ dotPrint :: DotConfig -> a -> ByteString+ dotParse :: Parser Error a++-- | dotParse and then dotPrint:+--+-- - pretty printing error on failure.+--+-- - This is not an exact parser/printer, so the test re-parses the dotPrint, which should be idempotent+testDotParser :: forall a. (DotParse a) => Proxy a -> DotConfig -> ByteString -> IO ()+testDotParser _ cfg b =+ case runParser dotParse b :: Result Error a of+ Err e -> B.putStrLn $ prettyError b e+ OK a left -> do+ when (left /= "") (B.putStrLn $ "parsed with leftovers: " <> left)+ case runParser dotParse (dotPrint cfg a) :: Result Error a of+ Err e -> B.putStrLn $ "round trip error: " <> prettyError (dotPrint cfg a) e+ Fail -> B.putStrLn "uncaught round trip parse error"+ OK _ left' -> do+ when (left' /= "") (B.putStrLn $ "round trip parse with left overs" <> left)+ Fail -> B.putStrLn "uncaught parse error"++-- | run a dotParse erroring on leftovers, Fail or Err+runDotParser :: (DotParse a) => ByteString -> a+runDotParser = runParser_ dotParse++-- | Representation of a full graphviz graph, as per the dot language specification+data Graph = Graph+ { strict :: Last Strict,+ directed :: Last Directed,+ graphid :: Last ID,+ nodeAttributes :: Map.Map ID ID,+ graphAttributes :: Map.Map ID ID,+ edgeAttributes :: Map.Map ID ID,+ globalAttributes :: Map.Map ID ID,+ nodes :: [NodeStatement],+ edges :: [EdgeStatement],+ subgraphs :: [SubGraphStatement]+ }+ deriving (Eq, Show, Generic)++instance Semigroup Graph where+ (Graph m d i na ga ea gs ns es ss) <> (Graph m' d' i' na' ga' ea' gs' ns' es' ss') =+ Graph (m <> m') (d <> d') (i <> i') (na <> na') (ga <> ga') (ea <> ea') (gs <> gs') (ns <> ns') (es <> es') (ss <> ss')++instance Monoid Graph where+ mempty = Graph mempty mempty mempty mempty mempty mempty mempty mempty mempty mempty++-- | global attributes lens+gattL :: ID -> Lens' Graph (Maybe ID)+gattL k = #globalAttributes % at k++-- | attributes lens+attL :: AttributeType -> ID -> Lens' Graph (Maybe ID)+attL GraphType k = #graphAttributes % at k+attL NodeType k = #nodeAttributes % at k+attL EdgeType k = #edgeAttributes % at k++outercalate :: ByteString -> [ByteString] -> ByteString+outercalate _ [] = mempty+outercalate a xs = a <> intercalate a xs <> a++instance DotParse Graph where+ dotPrint cfg (Graph me d i na ga ea gs ns es ss) =+ intercalate (cfg ^. #topLevelSep) $+ bool [] ["strict"] (me == Last (Just MergeEdges))+ <> bool ["digraph"] ["graph"] (d == Last (Just UnDirected))+ <> maybe [] ((: []) . dotPrint cfg) (getLast i)+ <> [ wrapCurlyPrint $+ outercalate+ (cfg ^. #statementSep)+ ( [dotPrint cfg (AttributeStatement NodeType na)]+ <> [dotPrint cfg (AttributeStatement GraphType ga)]+ <> [dotPrint cfg (AttributeStatement EdgeType ea)]+ <> (dotPrint cfg . GlobalAttributeStatement <$> Map.toList gs)+ <> (dotPrint cfg <$> ns)+ <> (dotPrint cfg <$> es)+ <> (dotPrint cfg <$> ss)+ )+ ]++ dotParse = token $ do+ me <- dotParse+ d <- dotParse+ i <- optional dotParse+ ss <- wrapCurlyP (many dotParse)+ let g =+ (mempty :: Graph)+ & #strict .~ Last (Just me)+ & #directed .~ Last (Just d)+ & #graphid .~ Last i+ pure $ addStatements ss g++-- * Dot Grammar++-- | MergeEdges (strict)+data Strict = MergeEdges | NoMergeEdges deriving (Eq, Show, Generic)++instance DotParse Strict where+ dotPrint _ MergeEdges = "strict"+ dotPrint _ NoMergeEdges = ""++ dotParse = token $ optioned $(keyword "strict") (const $ pure MergeEdges) (pure NoMergeEdges)++-- | Default Strict is NoMergeEdges+defStrict :: Last Strict -> Strict+defStrict (Last Nothing) = NoMergeEdges+defStrict (Last (Just x)) = x++-- | Directed (digraph | graph)+data Directed = Directed | UnDirected deriving (Eq, Show, Generic)++instance DotParse Directed where+ dotPrint _ Directed = "digraph"+ dotPrint _ UnDirected = "graph"++ dotParse =+ token $+ (Directed <$ $(keyword "digraph"))+ <|> (UnDirected <$ $(keyword "graph"))++-- | Default Directed is Directed+defDirected :: Last Directed -> Directed+defDirected (Last Nothing) = Directed+defDirected (Last (Just x)) = x++-- | A dot statement as per the dot language specification.+data Statement = StatementNode NodeStatement | StatementEdge EdgeStatement | StatementGlobalAttribute GlobalAttributeStatement | StatementAttribute AttributeStatement | StatementSubGraph SubGraphStatement deriving (Eq, Show, Generic)++instance DotParse Statement where+ dotPrint cfg (StatementNode x) = dotPrint cfg x+ dotPrint cfg (StatementEdge x) = dotPrint cfg x+ dotPrint cfg (StatementAttribute x) = dotPrint cfg x+ dotPrint cfg (StatementGlobalAttribute x) = dotPrint cfg x+ dotPrint cfg (StatementSubGraph x) = dotPrint cfg x++ dotParse =+ token $+ -- Order is important+ (StatementEdge <$> dotParse)+ <|> (StatementAttribute <$> dotParse)+ <|> (StatementGlobalAttribute <$> dotParse)+ <|> (StatementSubGraph <$> dotParse)+ <|> (StatementNode <$> dotParse)++-- | Identifier as per the dot language specifications.+--+-- >>> runDotParser "0" :: ID+-- IDInt 0+--+-- >>> runDotParser "-.123" :: ID+-- IDDouble (-0.123)+--+-- >>> runParser dotParse "apple_1'" :: Result Error ID+-- OK (ID "apple_1") "'"+--+-- >>> :set -XQuasiQuotes+-- >>> runParser dotParse "\"hello\"" :: Result Error ID+-- OK (IDQuoted "hello") ""+--+-- >>> runDotParser "<The <font color='red'><b>foo</b></font>,<br/> the <font point-size='20'>bar</font> and<br/> the <i>baz</i>>" :: ID+-- IDHtml "<The <font color='red'><b>foo</b></font>,<br/> the <font point-size='20'>bar</font> and<br/> the <i>baz</i>>"+data ID = ID ByteString | IDInt Int | IDDouble Double | IDQuoted ByteString | IDHtml ByteString deriving (Eq, Show, Generic, Ord)++instance DotParse ID where+ dotPrint _ (ID s) = s+ dotPrint _ (IDInt i) = packUTF8 (show i)+ dotPrint _ (IDDouble x) = packUTF8 (show x)+ dotPrint _ (IDQuoted x) =+ wrapQuotePrint x+ dotPrint _ (IDHtml s) = s++ -- order matters+ dotParse =+ (ID <$> ident)+ <|> (IDInt <$> (signed int `notFollowedBy` $(char '.')))+ <|> (IDDouble <$> signed double)+ <|> (IDQuoted . packUTF8 <$> quoted)+ <|> (IDHtml . packUTF8 <$> htmlLike)++-- | ID as the equivalent plain String+--+-- note that the dot language identifier equivalence law is:+--+-- > x == y if label x == label y+label :: ID -> String+label (ID s) = unpackUTF8 s+label (IDInt i) = show i+label (IDDouble d) = show d+label (IDQuoted q) = unpackUTF8 q+label (IDHtml h) = unpackUTF8 h++-- | Attribute key-value pair of identifiers+--+-- >>> runDotParser "shape=diamond" :: (ID,ID)+-- (ID "shape",ID "diamond")+--+-- >>> runDotParser "fontname=\"Arial\"" :: (ID,ID)+-- (ID "fontname",IDQuoted "Arial")+instance DotParse (ID, ID) where+ dotPrint cfg (x0, x1) = dotPrint cfg x0 <> "=" <> dotPrint cfg x1++ dotParse = token $+ do+ x0 <- token dotParse+ _ <- token $(symbol "=")+ x1 <- dotParse+ pure (x0, x1)++-- | Attribute collections+--+-- >>> runDotParser "[shape=diamond; color=blue] [label=label]" :: Map.Map ID ID+-- fromList [(ID "color",ID "blue"),(ID "label",ID "label"),(ID "shape",ID "diamond")]+--+-- A given entity can have multiple attribute lists. For simplicity, these are mconcat'ed on parsing.+instance DotParse (Map.Map ID ID) where+ dotPrint cfg as =+ bool+ (wrapSquarePrint (intercalate (cfg ^. #attSep) $ dotPrint cfg <$> Map.toList as))+ mempty+ (as == Map.empty)++ dotParse =+ Map.fromList . mconcat . fmap toList+ <$> token (many (wrapSquareP (nonEmptyP dotParse sepP)) <|> ([] <$ wrapSquareP ws))++-- | Compass instructions which are optionally associated with an identifier+data Compass = CompassN | CompassNE | CompassE | CompassSE | CompassS | CompassSW | CompassW | CompassNW | CompassC | Compass_ deriving (Eq, Show, Generic)++instance DotParse Compass where+ dotPrint _ CompassN = "n"+ dotPrint _ CompassNE = "ne"+ dotPrint _ CompassE = "e"+ dotPrint _ CompassSE = "se"+ dotPrint _ CompassS = "s"+ dotPrint _ CompassSW = "sw"+ dotPrint _ CompassW = "w"+ dotPrint _ CompassNW = "nw"+ dotPrint _ CompassC = "c"+ dotPrint _ Compass_ = "_"++ dotParse =+ token+ $( switch+ [|+ case _ of+ "n" -> pure CompassN+ "ne" -> pure CompassNE+ "e" -> pure CompassE+ "se" -> pure CompassSE+ "s" -> pure CompassS+ "sw" -> pure CompassSW+ "w" -> pure CompassW+ "nw" -> pure CompassNW+ "c" -> pure CompassC+ "_" -> pure Compass_+ |]+ )++-- | Port instructions which are optionally associated with an identifier+newtype Port = Port {portID :: These ID Compass} deriving (Eq, Show, Generic)++instance DotParse Port where+ dotPrint cfg (Port (This i)) = ": " <> dotPrint cfg i+ dotPrint cfg (Port (That c)) = ": " <> dotPrint cfg c+ dotPrint cfg (Port (These i c)) = ": " <> dotPrint cfg i <> " : " <> dotPrint cfg c++ dotParse =+ token $+ ((\x0 x1 -> Port (These x0 x1)) <$> ($(symbol ":") *> dotParse) <*> ($(symbol ":") *> dotParse))+ <|> (Port . This <$> ($(symbol ":") *> dotParse))+ <|> (Port . That <$> ($(symbol ":") *> dotParse))++-- | A top-level attribute+--+-- >>> runDotParser "rankdir=\"BT\"" :: Statement+-- StatementGlobalAttribute (GlobalAttributeStatement {globalAttributeStatement = (ID "rankdir",IDQuoted "BT")})+newtype GlobalAttributeStatement = GlobalAttributeStatement {globalAttributeStatement :: (ID, ID)} deriving (Eq, Show, Generic)++instance DotParse GlobalAttributeStatement where+ dotPrint cfg (GlobalAttributeStatement s) = dotPrint cfg s+ dotParse = GlobalAttributeStatement <$> dotParse++-- | Category of attribute+data AttributeType = GraphType | NodeType | EdgeType deriving (Eq, Show, Generic)++instance DotParse AttributeType where+ dotPrint _ GraphType = "graph"+ dotPrint _ NodeType = "node"+ dotPrint _ EdgeType = "edge"++ dotParse =+ token+ (GraphType <$ $(keyword "graph"))+ <|> (NodeType <$ $(keyword "node"))+ <|> (EdgeType <$ $(keyword "edge"))++-- | Top-level attribute statement+--+-- >>> runDotParser "graph [overlap=false, splines=spline, size=\"1!\"];" :: Statement+-- StatementAttribute (AttributeStatement {attributeType = GraphType, attributes = fromList [(ID "overlap",ID "false"),(ID "size",IDQuoted "1!"),(ID "splines",ID "spline")]})+data AttributeStatement = AttributeStatement {attributeType :: AttributeType, attributes :: Map.Map ID ID} deriving (Eq, Show, Generic)++instance DotParse AttributeStatement where+ dotPrint cfg (AttributeStatement t as) =+ intercalate+ " "+ [dotPrint cfg t, dotPrint cfg as]++ dotParse = AttributeStatement <$> dotParse <*> dotParse++-- | Node statement+--+-- >>> runDotParser "A [shape=diamond; color=blue]" :: Statement+-- StatementNode (NodeStatement {nodeID = ID "A", port = Nothing, nodeAttrs = fromList [(ID "color",ID "blue"),(ID "shape",ID "diamond")]})+data NodeStatement = NodeStatement {nodeID :: ID, port :: Maybe Port, nodeAttrs :: Map.Map ID ID} deriving (Eq, Show, Generic)++instance DotParse NodeStatement where+ dotPrint cfg (NodeStatement i p as) =+ intercalate " " $+ [dotPrint cfg i]+ <> (dotPrint cfg <$> maybeToList p)+ <> [dotPrint cfg as]++ dotParse = NodeStatement <$> dotParse <*> optional dotParse <*> dotParse++-- | An edge can be specified in as a NodeID or as a SubGraph+data EdgeID+ = EdgeID ID (Maybe Port)+ | EdgeSubGraph SubGraphStatement+ deriving (Eq, Show, Generic)++instance DotParse EdgeID where+ dotPrint cfg (EdgeID e p) =+ mconcat $ [dotPrint cfg e] <> (dotPrint cfg <$> maybeToList p)+ dotPrint cfg (EdgeSubGraph s) = dotPrint cfg s++ dotParse =+ (EdgeID <$> dotParse <*> optional dotParse)+ <|> (EdgeSubGraph <$> dotParse)++-- | An edgeop is -> in directed graphs and -- in undirected graphs.+data EdgeOp = EdgeDirected | EdgeUndirected deriving (Eq, Show, Generic)++instance DotParse EdgeOp where+ dotPrint _ EdgeDirected = "->"+ dotPrint _ EdgeUndirected = "--"++ dotParse =+ token+ $( switch+ [|+ case _ of+ "->" -> pure EdgeDirected+ "--" -> pure EdgeUndirected+ |]+ )++-- | generate an EdgeOp given the type of graph.+fromDirected :: Directed -> EdgeOp+fromDirected Directed = EdgeDirected+fromDirected UnDirected = EdgeUndirected++-- | Edge statement+--+-- >>> runDotParser "A -> B [style=dashed, color=grey]" :: Statement+-- StatementEdge (EdgeStatement {edgeOp = EdgeDirected, leftEdge = EdgeID (ID "A") Nothing, rightEdges = EdgeID (ID "B") Nothing :| [], edgeAttrs = fromList [(ID "color",ID "grey"),(ID "style",ID "dashed")]})+data EdgeStatement = EdgeStatement {edgeOp :: EdgeOp, leftEdge :: EdgeID, rightEdges :: NonEmpty EdgeID, edgeAttrs :: Map.Map ID ID} deriving (Eq, Show, Generic)++instance DotParse EdgeStatement where+ dotPrint cfg (EdgeStatement l rs xs as) =+ intercalate+ " "+ ( [intercalate (" " <> dotPrint cfg l <> " ") (dotPrint cfg <$> (rs : toList xs))]+ <> [dotPrint cfg as]+ )++ dotParse = token $ do+ l <- dotParse+ o0 <- dotParse+ r0 <- dotParse+ ors <- many ((,) <$> dotParse <*> dotParse)+ as <- dotParse+ bool+ (pure (EdgeStatement o0 l (r0 :| (snd <$> ors)) as))+ empty+ (any ((/= o0) . fst) ors)++-- | The edge ID or subgraph ID (if any)+edgeID :: EdgeID -> Maybe ID+edgeID (EdgeID i _) = Just i+edgeID (EdgeSubGraph (SubGraphStatement i _)) = i++-- | edge IDs+edgeIDsNamed :: EdgeStatement -> [(ID, ID)]+edgeIDsNamed e = [(x, y) | (Just x, Just y) <- edgeIDs e]++-- | list of edges in a given EdgeStatement, including anonymous SugGraphs+edgeIDs :: EdgeStatement -> [(Maybe ID, Maybe ID)]+edgeIDs e = zip (id0 : id1) id1+ where+ id0 = edgeID (view #leftEdge e)+ id1 = edgeID <$> toList (view #rightEdges e)++-- | A subgraph statement.+--+-- Note: each subgraph must have a unique name+--+-- >>> runDotParser "subgraph A {A, B, C}" :: Statement+-- StatementSubGraph (SubGraphStatement {subgraphID = Just (ID "A"), subgraphStatements = [StatementNode (NodeStatement {nodeID = ID "A", port = Nothing, nodeAttrs = fromList []}),StatementNode (NodeStatement {nodeID = ID "B", port = Nothing, nodeAttrs = fromList []}),StatementNode (NodeStatement {nodeID = ID "C", port = Nothing, nodeAttrs = fromList []})]})+data SubGraphStatement = SubGraphStatement {subgraphID :: Maybe ID, subgraphStatements :: [Statement]} deriving (Eq, Show, Generic)++instance DotParse SubGraphStatement where+ dotPrint cfg (SubGraphStatement x xs) =+ intercalate " " $+ maybe+ []+ (\x' -> [intercalate " " ["subgraph", dotPrint cfg x']])+ x+ <> (: []) (wrapCurlyPrint (intercalate (cfg ^. #subGraphSep) $ dotPrint cfg <$> xs))++ dotParse = token $ do+ x <- optional ($(keyword "subgraph") *> dotParse)+ pure (SubGraphStatement x) <*> wrapCurlyP (many (optional sepP *> dotParse))++-- | add a graphviz statement to a 'Graph'+addStatement :: Statement -> Graph -> Graph+addStatement (StatementNode n) g = g & #nodes %~ (<> [n])+addStatement (StatementEdge e) g = g & #edges %~ (<> [e])+addStatement (StatementSubGraph s) g = g & #subgraphs %~ (<> [s])+addStatement (StatementAttribute (AttributeStatement GraphType as)) g = g & #graphAttributes %~ (<> as)+addStatement (StatementAttribute (AttributeStatement NodeType as)) g = g & #nodeAttributes %~ (<> as)+addStatement (StatementAttribute (AttributeStatement EdgeType as)) g = g & #edgeAttributes %~ (<> as)+addStatement (StatementGlobalAttribute (GlobalAttributeStatement s)) g = g & #globalAttributes %~ (<> Map.fromList [s])++-- | add a list of graphviz statements to a 'Graph'+addStatements :: [Statement] -> Graph -> Graph+addStatements ss g = Prelude.foldr addStatement g ss++-- | default dot graph as a ByteString+defaultBS :: ByteString+defaultBS =+ encodeUtf8+ [trimming|+digraph {+ node [shape=circle+ ,height=0.5];+ graph [overlap=false+ ,splines=spline+ ,size="1!"];+ edge [arrowsize=0];+ }+|]++-- | A default dot graph+--+-- >>> import qualified Data.ByteString.Char8 as B+-- >>> B.putStrLn $ dotPrint defaultDotConfig defaultGraph+-- digraph {+-- node [height=0.5;shape=circle]+-- graph [overlap=false;size="1!";splines=spline]+-- edge [arrowsize=0]+-- }+defaultGraph :: Graph+defaultGraph = runDotParser defaultBS++-- | run a dot string through graphviz, supplying arguments and collecting stdout+processDotWith :: Directed -> [String] -> ByteString -> IO ByteString+processDotWith d args i = do+ let cmd = case d of+ Directed -> "dot"+ UnDirected -> "neato"+ (r, input, e) <- readProcessWithExitCode cmd args i+ bool+ (error $ unpackUTF8 e)+ (pure input)+ (r == ExitSuccess)++-- | run a dot string through graphviz, collecting the augmented dot string output+processDot :: Directed -> ByteString -> IO ByteString+processDot d = processDotWith d ["-Tdot"]++-- | Augment a Graph via the graphviz process+processGraphWith :: DotConfig -> Graph -> IO Graph+processGraphWith cfg g =+ runDotParser <$> processDot (defDirected $ view #directed g) (dotPrint cfg g)++-- | Augment a Graph via the graphviz process+processGraph :: Graph -> IO Graph+processGraph g =+ runDotParser <$> processDot (defDirected $ view #directed g) (dotPrint defaultDotConfig g)++instance DotParse (Point Double) where+ dotPrint _ (Point x y) =+ intercalate "," $+ packUTF8 . show <$> [x, y]++ dotParse = token pointP++pointI :: Iso' ID (Point Double)+pointI =+ iso+ (runParser_ pointP . packUTF8 . label)+ (IDQuoted . dotPrint defaultDotConfig)++instance DotParse (Rect Double) where+ dotPrint _ (Rect x z y w) =+ intercalate "," $+ packUTF8 . show <$> [x, y, z, w]++ dotParse = token rectP++rectI :: Iso' ID (Rect Double)+rectI =+ iso+ (runParser_ rectP . packUTF8 . label)+ (IDQuoted . dotPrint defaultDotConfig)++-- | Bounding box ID lens+bb_ :: Lens' Graph (Maybe ID)+bb_ = #graphAttributes % at (ID "bb")++-- | Bounding Box lens as a 'Rect'+bbL :: Lens' Graph (Maybe (Rect Double))+bbL = lens (preview (bb_ % _Just % rectI)) (\g r -> set bb_ (review rectI <$> r) g)++-- | nodes lens+nodesPortL :: Lens' Graph (Map.Map ID (Maybe Port, Map.Map ID ID))+nodesPortL =+ lens+ ( \g ->+ g & view #nodes+ & fmap (\x -> (view #nodeID x, (view #port x, view #nodeAttrs x)))+ & Map.fromList+ )+ (\g m -> g & #nodes .~ ((\(n, (p, a)) -> NodeStatement n p a) <$> Map.toList m))++-- | nodes lens ignoring/forgetting port information+nodesL :: Lens' Graph (Map.Map ID (Map.Map ID ID))+nodesL =+ lens+ ( \g ->+ g & view #nodes+ & fmap (\x -> (view #nodeID x, view #nodeAttrs x))+ & Map.fromList+ )+ (\g m -> g & #nodes .~ ((\(n, a) -> NodeStatement n Nothing a) <$> Map.toList m))++-- | edges lens ignoring/forgetting port information+edgesL :: Lens' Graph (Map.Map (ID, ID) (Map.Map ID ID))+edgesL =+ lens getEdges_ setEdges_++-- | edge & attribute map+-- ignores anonymous subgraphs+getEdges_ :: Graph -> Map.Map (ID, ID) (Map.Map ID ID)+getEdges_ g =+ Map.fromList $+ mconcat $+ fmap+ (\(xs, a) -> (,a) <$> xs)+ [(edgeIDsNamed e, view #edgeAttrs e) | e <- view #edges g]++setEdges_ :: Graph -> Map.Map (ID, ID) (Map.Map ID ID) -> Graph+setEdges_ g m =+ g+ & #edges+ .~ ( ( \((x0, x1), as) ->+ EdgeStatement+ (fromDirected (defDirected $ view #directed g))+ (EdgeID x0 Nothing)+ (EdgeID x1 Nothing :| [])+ as+ )+ <$> Map.toList m+ )++-- | A specific attribute for all nodes in a graph+nodesA :: ID -> Graph -> Map.Map ID (Maybe ID)+nodesA a g = fmap (Map.lookup a) (view nodesL g)++-- | node position (as a Point)+nodePos :: Graph -> Map.Map ID (Maybe (Point Double))+nodePos = fmap (fmap (view pointI)) . nodesA (ID "pos")++--++-- | Specific attribute for all edges+edgesA :: Graph -> ID -> Map.Map (ID, ID) (Maybe ID)+edgesA g a = fmap (Map.lookup a) (view edgesL g)++-- | node width attributes+nodeWidth :: Graph -> Map.Map ID (Maybe Double)+nodeWidth g =+ fmap+ ( \case+ Just (IDDouble x') -> Just x'+ _ -> Nothing+ )+ $ nodesA (ID "width") g++-- | edge width attributes+edgeWidth :: Graph -> Map.Map (ID, ID) (Maybe Double)+edgeWidth g =+ fmap+ ( \case+ Just (IDDouble x') -> Just x'+ _ -> Nothing+ )+ $ edgesA g (ID "width")++-- | edge path attributes+edgeSpline :: Graph -> Map.Map (ID, ID) (Maybe Spline)+edgeSpline g =+ fmap+ ( \case+ Just (IDQuoted x') -> Just (runParser_ splineP x')+ _ -> Nothing+ )+ $ edgesA g (ID "pos")++-- | typical node information after processing a dot bytestring.+data NodeInfo = NodeInfo {nlabel :: ID, nwidth :: Double, pos :: Point Double} deriving (Eq, Show, Generic)++-- | Create a list of NodeInfo from a graph.+nodeInfo :: Graph -> Double -> [NodeInfo]+nodeInfo g w = [NodeInfo x (fromMaybe w (join w')) p | (x, (Just p, w')) <- xs]+ where+ xs =+ Map.toList $+ merge+ (mapMissing (\_ v -> (v, Nothing)))+ dropMissing+ (zipWithMatched (\_ x y -> (x, Just y)))+ (nodePos g)+ (nodeWidth g)++-- | typical edge information after processing a dot bytestring.+data EdgeInfo = EdgeInfo {elabel :: (ID, ID), ewidth :: Double, curve :: [PathData Double]} deriving (Eq, Show, Generic)++-- | Create a list of EdgeInfo from a graph+edgeInfo :: Graph -> Double -> [EdgeInfo]+edgeInfo g w = [EdgeInfo (x, y) (fromMaybe w (join w')) (splinePath p) | ((x, y), (Just p, w')) <- xs]+ where+ xs =+ Map.toList $+ merge+ (mapMissing (\_ v -> (v, Nothing)))+ dropMissing+ (zipWithMatched (\_ x y -> (x, Just y)))+ (edgeSpline g)+ (edgeWidth g)++-- |+--+-- https://graphviz.org/docs/attr-types/splineType/+-- format of the example is end point point and then triples (5,8,11 lengths are 1, 2 and 3 cubics)+splinePath :: Spline -> [PathData Double]+splinePath sp = s' <> p1' <> cs <> e'+ where+ s' = maybe [] (\s -> [StartP s, LineP $ view #splineP1 sp]) (view #splineStart sp)+ e' = maybe [] (\e -> [LineP e]) (view #splineEnd sp)+ p1' = [StartP (view #splineP1 sp)]+ cs = (\(x, y, z) -> CubicP x y z) <$> view #splineTriples sp++-- | create Statements from a (no edge label) algebraic graph+toStatements :: Directed -> G.Graph ByteString -> [Statement]+toStatements d g =+ ((\x -> StatementNode $ NodeStatement (IDQuoted x) Nothing Map.empty) <$> G.vertexList g)+ <> ( ( \(x, y) ->+ StatementEdge $+ EdgeStatement+ (fromDirected d)+ (EdgeID (IDQuoted x) Nothing)+ (fromList [EdgeID (IDQuoted y) Nothing])+ Map.empty+ )+ <$> G.edgeList g+ )++-- | Various configutaion parameters for the chart-svg Chart+data ChartConfig = ChartConfig+ { chartHeight :: Double,+ chartScale :: Double,+ edgeSize :: Double,+ chartColor :: Colour,+ chartBackgroundColor :: Colour,+ nodeHeight :: Double,+ nodeSize :: Double,+ vshift :: Double,+ textSize :: Double,+ labelf :: ID -> Text+ }+ deriving (Generic)++-- | default parameters+defaultChartConfig :: ChartConfig+defaultChartConfig = ChartConfig 500 72 0.5 (over lightness' (* 0.5) (palette1 0)) (set opac' 0.2 (palette1 0)) 0.5 0.5 (-3.7) 14 (Text.pack . label)++-- | convert a 'Graph' processed via the graphviz commands to a 'ChartSvg'+--+-- >>> import Chart+-- >>> import DotParse.Examples (exInt)+-- >>> ex <- processGraph exInt+-- >>> writeChartSvg "other/ex.svg" (graphToChartWith defaultChartConfig ex)+--+-- +graphToChartWith :: ChartConfig -> Graph -> ChartSvg+graphToChartWith cfg g =+ mempty+ & #charts .~ named "edges" ps <> named "shapes" c0 <> named "labels" [ts]+ & #svgOptions % #svgHeight .~ (cfg ^. #chartHeight)+ & #hudOptions .~ (mempty & #chartAspect .~ ChartAspect)+ where+ glyphs w = case view (attL NodeType (ID "shape")) g of+ Just (ID "circle") -> defaultGlyphStyle & #shape .~ CircleGlyph & #size .~ (cfg ^. #chartScale) * w & #borderSize .~ (cfg ^. #edgeSize) & #borderColor .~ (cfg ^. #chartColor) & #color .~ (cfg ^. #chartBackgroundColor)+ Just (ID "box") -> defaultGlyphStyle & #shape .~ RectSharpGlyph (h / w) & #size .~ 72 * w & #borderSize .~ 1 & #borderColor .~ (cfg ^. #chartColor) & #color .~ (cfg ^. #chartBackgroundColor)+ -- defaults to circle+ _ -> defaultGlyphStyle & #shape .~ CircleGlyph & #size .~ 72 * w & #borderSize .~ 1 & #borderColor .~ (cfg ^. #chartColor) & #color .~ (cfg ^. #chartBackgroundColor)+ h = maybe (cfg ^. #nodeHeight) (runParser_ double . packUTF8 . label) (view (attL NodeType (ID "height")) g)+ vshift' = cfg ^. #vshift+ -- node information+ ns = nodeInfo g (cfg ^. #nodeSize)+ -- edge information+ es = edgeInfo g (cfg ^. #edgeSize)+ -- paths+ ps = fmap (\(EdgeInfo _ w p) -> PathChart (defaultPathStyle & #borderSize .~ (2 * w) & #borderColor .~ (cfg ^. #chartColor) & #color .~ transparent) p) es+ -- circles+ c0 = fmap (\(NodeInfo _ w p) -> GlyphChart (glyphs w) [p]) ns+ -- labels+ ts =+ TextChart (defaultTextStyle & #size .~ (cfg ^. #textSize) & #color .~ (cfg ^. #chartColor)) ((\(NodeInfo l _ (Point x y)) -> ((cfg ^. #labelf) l, Point x (vshift' + y))) <$> ns)++-- | convert a 'Graph' processed via the graphviz commands to a 'ChartSvg' using the default ChartConfig.+graphToChart :: Graph -> ChartSvg+graphToChart = graphToChartWith defaultChartConfig++-- | Convert an algebraic graph to a dotparse graph.+toDotGraphWith :: Directed -> Graph -> G.Graph ByteString -> Graph+toDotGraphWith d g gg = g & #directed .~ Last (Just d) & addStatements (toStatements d gg)++-- | Convert an algebraic graph to a dotparse graph, starting with the 'defaultGraph'.+toDotGraph :: G.Graph ByteString -> Graph+toDotGraph = toDotGraphWith Directed defaultGraph