<html><head><link rel="stylesheet" href="resource://content-accessible/plaintext.css"><style media="screen" id="__markdown-viewer__md_css">/*
* Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
@media (prefers-color-scheme: dark) {
:root {
--color-prettylights-syntax-comment: #8b949e;
--color-prettylights-syntax-constant: #79c0ff;
--color-prettylights-syntax-entity: #d2a8ff;
--color-prettylights-syntax-storage-modifier-import: #c9d1d9;
--color-prettylights-syntax-entity-tag: #7ee787;
--color-prettylights-syntax-keyword: #ff7b72;
--color-prettylights-syntax-string: #a5d6ff;
--color-prettylights-syntax-variable: #ffa657;
--color-prettylights-syntax-brackethighlighter-unmatched: #f85149;
--color-prettylights-syntax-invalid-illegal-text: #f0f6fc;
--color-prettylights-syntax-invalid-illegal-bg: #8e1519;
--color-prettylights-syntax-carriage-return-text: #f0f6fc;
--color-prettylights-syntax-carriage-return-bg: #b62324;
--color-prettylights-syntax-string-regexp: #7ee787;
--color-prettylights-syntax-markup-list: #f2cc60;
--color-prettylights-syntax-markup-heading: #1f6feb;
--color-prettylights-syntax-markup-italic: #c9d1d9;
--color-prettylights-syntax-markup-bold: #c9d1d9;
--color-prettylights-syntax-markup-deleted-text: #ffdcd7;
--color-prettylights-syntax-markup-deleted-bg: #67060c;
--color-prettylights-syntax-markup-inserted-text: #aff5b4;
--color-prettylights-syntax-markup-inserted-bg: #033a16;
--color-prettylights-syntax-markup-changed-text: #ffdfb6;
--color-prettylights-syntax-markup-changed-bg: #5a1e02;
--color-prettylights-syntax-markup-ignored-text: #c9d1d9;
--color-prettylights-syntax-markup-ignored-bg: #1158c7;
--color-prettylights-syntax-meta-diff-range: #d2a8ff;
--color-prettylights-syntax-brackethighlighter-angle: #8b949e;
--color-prettylights-syntax-sublimelinter-gutter-mark: #484f58;
--color-prettylights-syntax-constant-other-reference-link: #a5d6ff;
--color-fg-default: #c9d1d9;
--color-fg-muted: #8b949e;
--color-fg-subtle: #484f58;
--color-canvas-default: #0d1117;
--color-canvas-subtle: #161b22;
--color-border-default: #30363d;
--color-border-muted: #21262d;
--color-neutral-muted: rgba(110,118,129,0.4);
--color-accent-fg: #58a6ff;
--color-accent-emphasis: #1f6feb;
--color-danger-fg: #f85149;
}
}
@media (prefers-color-scheme: light) {
:root {
--color-prettylights-syntax-comment: #6e7781;
--color-prettylights-syntax-constant: #0550ae;
--color-prettylights-syntax-entity: #8250df;
--color-prettylights-syntax-storage-modifier-import: #24292f;
--color-prettylights-syntax-entity-tag: #116329;
--color-prettylights-syntax-keyword: #cf222e;
--color-prettylights-syntax-string: #0a3069;
--color-prettylights-syntax-variable: #953800;
--color-prettylights-syntax-brackethighlighter-unmatched: #82071e;
--color-prettylights-syntax-invalid-illegal-text: #f6f8fa;
--color-prettylights-syntax-invalid-illegal-bg: #82071e;
--color-prettylights-syntax-carriage-return-text: #f6f8fa;
--color-prettylights-syntax-carriage-return-bg: #cf222e;
--color-prettylights-syntax-string-regexp: #116329;
--color-prettylights-syntax-markup-list: #3b2300;
--color-prettylights-syntax-markup-heading: #0550ae;
--color-prettylights-syntax-markup-italic: #24292f;
--color-prettylights-syntax-markup-bold: #24292f;
--color-prettylights-syntax-markup-deleted-text: #82071e;
--color-prettylights-syntax-markup-deleted-bg: #FFEBE9;
--color-prettylights-syntax-markup-inserted-text: #116329;
--color-prettylights-syntax-markup-inserted-bg: #dafbe1;
--color-prettylights-syntax-markup-changed-text: #953800;
--color-prettylights-syntax-markup-changed-bg: #ffd8b5;
--color-prettylights-syntax-markup-ignored-text: #eaeef2;
--color-prettylights-syntax-markup-ignored-bg: #0550ae;
--color-prettylights-syntax-meta-diff-range: #8250df;
--color-prettylights-syntax-brackethighlighter-angle: #57606a;
--color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f;
--color-prettylights-syntax-constant-other-reference-link: #0a3069;
--color-fg-default: #24292f;
--color-fg-muted: #57606a;
--color-fg-subtle: #6e7781;
--color-canvas-default: #ffffff;
--color-canvas-subtle: #f6f8fa;
--color-border-default: #d0d7de;
--color-border-muted: hsla(210,18%,87%,1);
--color-neutral-muted: rgba(175,184,193,0.2);
--color-accent-fg: #0969da;
--color-accent-emphasis: #0969da;
--color-danger-fg: #cf222e;
}
}
:root {
color: var(--color-fg-default);
background-color: var(--color-canvas-default);
}
.markdownroot {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
margin: 0;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
font-size: 16px;
line-height: 1.5;
word-wrap: break-word;
}
.markdownroot .octicon {
display: inline-block;
fill: currentColor;
vertical-align: text-bottom;
}
.markdownroot h1:hover .anchor .octicon-link:before,
.markdownroot h2:hover .anchor .octicon-link:before,
.markdownroot h3:hover .anchor .octicon-link:before,
.markdownroot h4:hover .anchor .octicon-link:before,
.markdownroot h5:hover .anchor .octicon-link:before,
.markdownroot h6:hover .anchor .octicon-link:before {
width: 16px;
height: 16px;
content: ' ';
display: inline-block;
background-color: currentColor;
-webkit-mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");
mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");
}
.markdownroot details,
.markdownroot figcaption,
.markdownroot figure {
display: block;
}
.markdownroot summary {
display: list-item;
}
.markdownroot a {
background-color: transparent;
color: var(--color-accent-fg);
text-decoration: none;
}
.markdownroot a:active,
.markdownroot a:hover {
outline-width: 0;
}
.markdownroot abbr[title] {
border-bottom: none;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
.markdownroot b,
.markdownroot strong {
font-weight: 600;
}
.markdownroot dfn {
font-style: italic;
}
.markdownroot h1 {
margin: .67em 0;
font-weight: 600;
padding-bottom: .3em;
font-size: 2em;
border-bottom: 1px solid var(--color-border-muted);
}
.markdownroot mark {
background-color: #ff0;
color: var(--color-text-primary);
}
.markdownroot small {
font-size: 90%;
}
.markdownroot sub,
.markdownroot sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
.markdownroot sub {
bottom: -0.25em;
}
.markdownroot sup {
top: -0.5em;
}
.markdownroot img {
border-style: none;
max-width: 100%;
box-sizing: content-box;
background-color: var(--color-canvas-default);
}
.markdownroot code,
.markdownroot kbd,
.markdownroot pre,
.markdownroot samp {
font-family: monospace,monospace;
font-size: 1em;
}
.markdownroot figure {
margin: 1em 40px;
}
.markdownroot hr {
box-sizing: content-box;
overflow: hidden;
background: transparent;
border-bottom: 1px solid var(--color-border-muted);
height: .25em;
padding: 0;
margin: 24px 0;
background-color: var(--color-border-default);
border: 0;
}
.markdownroot html [type=button],
.markdownroot [type=reset],
.markdownroot [type=submit] {
-webkit-appearance: button;
}
.markdownroot [type=button]::-moz-focus-inner,
.markdownroot [type=reset]::-moz-focus-inner,
.markdownroot [type=submit]::-moz-focus-inner {
border-style: none;
padding: 0;
}
.markdownroot [type=button]:-moz-focusring,
.markdownroot [type=reset]:-moz-focusring,
.markdownroot [type=submit]:-moz-focusring {
outline: 1px dotted ButtonText;
}
.markdownroot [type=checkbox],
.markdownroot [type=radio] {
box-sizing: border-box;
padding: 0;
}
.markdownroot [type=number]::-webkit-inner-spin-button,
.markdownroot [type=number]::-webkit-outer-spin-button {
height: auto;
}
.markdownroot [type=search] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
.markdownroot [type=search]::-webkit-search-cancel-button,
.markdownroot [type=search]::-webkit-search-decoration {
-webkit-appearance: none;
}
.markdownroot ::-webkit-input-placeholder {
color: inherit;
opacity: .54;
}
.markdownroot ::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
.markdownroot a:hover {
text-decoration: underline;
}
.markdownroot hr::before {
display: table;
content: "";
}
.markdownroot hr::after {
display: table;
clear: both;
content: "";
}
.markdownroot table {
border-spacing: 0;
border-collapse: collapse;
display: block;
width: max-content;
max-width: 100%;
overflow: auto;
}
.markdownroot td,
.markdownroot th {
padding: 0;
}
.markdownroot details summary {
cursor: pointer;
}
.markdownroot details:not([open])>*:not(summary) {
display: none !important;
}
.markdownroot kbd {
display: inline-block;
padding: 3px 5px;
font: 11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
line-height: 10px;
color: var(--color-fg-default);
vertical-align: middle;
background-color: var(--color-canvas-subtle);
border: solid 1px var(--color-neutral-muted);
border-bottom-color: var(--color-neutral-muted);
border-radius: 6px;
box-shadow: inset 0 -1px 0 var(--color-neutral-muted);
}
.markdownroot h1,
.markdownroot h2,
.markdownroot h3,
.markdownroot h4,
.markdownroot h5,
.markdownroot h6 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: 600;
line-height: 1.25;
}
.markdownroot h2 {
font-weight: 600;
padding-bottom: .3em;
font-size: 1.5em;
border-bottom: 1px solid var(--color-border-muted);
}
.markdownroot h3 {
font-weight: 600;
font-size: 1.25em;
}
.markdownroot h4 {
font-weight: 600;
font-size: 1em;
}
.markdownroot h5 {
font-weight: 600;
font-size: .875em;
}
.markdownroot h6 {
font-weight: 600;
font-size: .85em;
color: var(--color-fg-muted);
}
.markdownroot p {
margin-top: 0;
margin-bottom: 10px;
}
.markdownroot blockquote {
margin: 0;
padding: 0 1em;
color: var(--color-fg-muted);
border-left: .25em solid var(--color-border-default);
}
.markdownroot ul,
.markdownroot ol {
margin-top: 0;
margin-bottom: 0;
padding-left: 2em;
}
.markdownroot ol ol,
.markdownroot ul ol {
list-style-type: lower-roman;
}
.markdownroot ul ul ol,
.markdownroot ul ol ol,
.markdownroot ol ul ol,
.markdownroot ol ol ol {
list-style-type: lower-alpha;
}
.markdownroot dd {
margin-left: 0;
}
.markdownroot tt,
.markdownroot code {
font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
font-size: 12px;
}
.markdownroot pre {
margin-top: 0;
margin-bottom: 0;
font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
font-size: 12px;
word-wrap: normal;
}
.markdownroot :-ms-input-placeholder {
color: var(--color-fg-subtle);
opacity: 1;
}
.markdownroot ::-ms-input-placeholder {
color: var(--color-fg-subtle);
opacity: 1;
}
.markdownroot ::placeholder {
color: var(--color-fg-subtle);
opacity: 1;
}
.markdownroot .pl-c {
color: var(--color-prettylights-syntax-comment);
}
.markdownroot .pl-c1,
.markdownroot .pl-s .pl-v {
color: var(--color-prettylights-syntax-constant);
}
.markdownroot .pl-e,
.markdownroot .pl-en {
color: var(--color-prettylights-syntax-entity);
}
.markdownroot .pl-smi,
.markdownroot .pl-s .pl-s1 {
color: var(--color-prettylights-syntax-storage-modifier-import);
}
.markdownroot .pl-ent {
color: var(--color-prettylights-syntax-entity-tag);
}
.markdownroot .pl-k {
color: var(--color-prettylights-syntax-keyword);
}
.markdownroot .pl-s,
.markdownroot .pl-pds,
.markdownroot .pl-s .pl-pse .pl-s1,
.markdownroot .pl-sr,
.markdownroot .pl-sr .pl-cce,
.markdownroot .pl-sr .pl-sre,
.markdownroot .pl-sr .pl-sra {
color: var(--color-prettylights-syntax-string);
}
.markdownroot .pl-v,
.markdownroot .pl-smw {
color: var(--color-prettylights-syntax-variable);
}
.markdownroot .pl-bu {
color: var(--color-prettylights-syntax-brackethighlighter-unmatched);
}
.markdownroot .pl-ii {
color: var(--color-prettylights-syntax-invalid-illegal-text);
background-color: var(--color-prettylights-syntax-invalid-illegal-bg);
}
.markdownroot .pl-c2 {
color: var(--color-prettylights-syntax-carriage-return-text);
background-color: var(--color-prettylights-syntax-carriage-return-bg);
}
.markdownroot .pl-sr .pl-cce {
font-weight: bold;
color: var(--color-prettylights-syntax-string-regexp);
}
.markdownroot .pl-ml {
color: var(--color-prettylights-syntax-markup-list);
}
.markdownroot .pl-mh,
.markdownroot .pl-mh .pl-en,
.markdownroot .pl-ms {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-heading);
}
.markdownroot .pl-mi {
font-style: italic;
color: var(--color-prettylights-syntax-markup-italic);
}
.markdownroot .pl-mb {
font-weight: bold;
color: var(--color-prettylights-syntax-markup-bold);
}
.markdownroot .pl-md {
color: var(--color-prettylights-syntax-markup-deleted-text);
background-color: var(--color-prettylights-syntax-markup-deleted-bg);
}
.markdownroot .pl-mi1 {
color: var(--color-prettylights-syntax-markup-inserted-text);
background-color: var(--color-prettylights-syntax-markup-inserted-bg);
}
.markdownroot .pl-mc {
color: var(--color-prettylights-syntax-markup-changed-text);
background-color: var(--color-prettylights-syntax-markup-changed-bg);
}
.markdownroot .pl-mi2 {
color: var(--color-prettylights-syntax-markup-ignored-text);
background-color: var(--color-prettylights-syntax-markup-ignored-bg);
}
.markdownroot .pl-mdr {
font-weight: bold;
color: var(--color-prettylights-syntax-meta-diff-range);
}
.markdownroot .pl-ba {
color: var(--color-prettylights-syntax-brackethighlighter-angle);
}
.markdownroot .pl-sg {
color: var(--color-prettylights-syntax-sublimelinter-gutter-mark);
}
.markdownroot .pl-corl {
text-decoration: underline;
color: var(--color-prettylights-syntax-constant-other-reference-link);
}
.markdownroot [data-catalyst] {
display: block;
}
.markdownroot g-emoji {
font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
font-size: 1em;
font-style: normal !important;
font-weight: 400;
line-height: 1;
vertical-align: -0.075em;
}
.markdownroot g-emoji img {
width: 1em;
height: 1em;
}
.markdownroot::before {
display: table;
content: "";
}
.markdownroot::after {
display: table;
clear: both;
content: "";
}
.markdownroot>*:first-child {
margin-top: 0 !important;
}
.markdownroot>*:last-child {
margin-bottom: 0 !important;
}
.markdownroot a:not([href]) {
color: inherit;
text-decoration: none;
}
.markdownroot .absent {
color: var(--color-danger-fg);
}
.markdownroot .anchor {
float: left;
padding-right: 4px;
margin-left: -20px;
line-height: 1;
}
.markdownroot .anchor:focus {
outline: none;
}
.markdownroot p,
.markdownroot blockquote,
.markdownroot ul,
.markdownroot ol,
.markdownroot dl,
.markdownroot table,
.markdownroot pre,
.markdownroot details {
margin-top: 0;
margin-bottom: 16px;
}
.markdownroot blockquote>:first-child {
margin-top: 0;
}
.markdownroot blockquote>:last-child {
margin-bottom: 0;
}
.markdownroot sup>a::before {
content: "[";
}
.markdownroot sup>a::after {
content: "]";
}
.markdownroot h1 .octicon-link,
.markdownroot h2 .octicon-link,
.markdownroot h3 .octicon-link,
.markdownroot h4 .octicon-link,
.markdownroot h5 .octicon-link,
.markdownroot h6 .octicon-link {
color: var(--color-fg-default);
vertical-align: middle;
visibility: hidden;
}
.markdownroot h1:hover .anchor,
.markdownroot h2:hover .anchor,
.markdownroot h3:hover .anchor,
.markdownroot h4:hover .anchor,
.markdownroot h5:hover .anchor,
.markdownroot h6:hover .anchor {
text-decoration: none;
}
.markdownroot h1:hover .anchor .octicon-link,
.markdownroot h2:hover .anchor .octicon-link,
.markdownroot h3:hover .anchor .octicon-link,
.markdownroot h4:hover .anchor .octicon-link,
.markdownroot h5:hover .anchor .octicon-link,
.markdownroot h6:hover .anchor .octicon-link {
visibility: visible;
}
.markdownroot h1 tt,
.markdownroot h1 code,
.markdownroot h2 tt,
.markdownroot h2 code,
.markdownroot h3 tt,
.markdownroot h3 code,
.markdownroot h4 tt,
.markdownroot h4 code,
.markdownroot h5 tt,
.markdownroot h5 code,
.markdownroot h6 tt,
.markdownroot h6 code {
padding: 0 .2em;
font-size: inherit;
}
.markdownroot ul.no-list,
.markdownroot ol.no-list {
padding: 0;
list-style-type: none;
}
.markdownroot ol[type="1"] {
list-style-type: decimal;
}
.markdownroot ol[type=a] {
list-style-type: lower-alpha;
}
.markdownroot ol[type=i] {
list-style-type: lower-roman;
}
.markdownroot div>ol:not([type]) {
list-style-type: decimal;
}
.markdownroot ul ul,
.markdownroot ul ol,
.markdownroot ol ol,
.markdownroot ol ul {
margin-top: 0;
margin-bottom: 0;
}
.markdownroot li>p {
margin-top: 16px;
}
.markdownroot li+li {
margin-top: .25em;
}
.markdownroot dl {
padding: 0;
}
.markdownroot dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: 600;
}
.markdownroot dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.markdownroot table th {
font-weight: 600;
}
.markdownroot table th,
.markdownroot table td {
padding: 6px 13px;
border: 1px solid var(--color-border-default);
}
.markdownroot table tr {
background-color: var(--color-canvas-default);
border-top: 1px solid var(--color-border-muted);
}
.markdownroot table tr:nth-child(2n) {
background-color: var(--color-canvas-subtle);
}
.markdownroot table img {
background-color: transparent;
}
.markdownroot img[align=right] {
padding-left: 20px;
}
.markdownroot img[align=left] {
padding-right: 20px;
}
.markdownroot .emoji {
max-width: none;
vertical-align: text-top;
background-color: transparent;
}
.markdownroot span.frame {
display: block;
overflow: hidden;
}
.markdownroot span.frame>span {
display: block;
float: left;
width: auto;
padding: 7px;
margin: 13px 0 0;
overflow: hidden;
border: 1px solid var(--color-border-default);
}
.markdownroot span.frame span img {
display: block;
float: left;
}
.markdownroot span.frame span span {
display: block;
padding: 5px 0 0;
clear: both;
color: var(--color-fg-default);
}
.markdownroot span.align-center {
display: block;
overflow: hidden;
clear: both;
}
.markdownroot span.align-center>span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: center;
}
.markdownroot span.align-center span img {
margin: 0 auto;
text-align: center;
}
.markdownroot span.align-right {
display: block;
overflow: hidden;
clear: both;
}
.markdownroot span.align-right>span {
display: block;
margin: 13px 0 0;
overflow: hidden;
text-align: right;
}
.markdownroot span.align-right span img {
margin: 0;
text-align: right;
}
.markdownroot span.float-left {
display: block;
float: left;
margin-right: 13px;
overflow: hidden;
}
.markdownroot span.float-left span {
margin: 13px 0 0;
}
.markdownroot span.float-right {
display: block;
float: right;
margin-left: 13px;
overflow: hidden;
}
.markdownroot span.float-right>span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: right;
}
.markdownroot code,
.markdownroot tt {
padding: .2em .4em;
margin: 0;
font-size: 85%;
background-color: var(--color-neutral-muted);
border-radius: 6px;
}
.markdownroot code br,
.markdownroot tt br {
display: none;
}
.markdownroot del code {
text-decoration: inherit;
}
.markdownroot pre code {
font-size: 100%;
}
.markdownroot pre>code {
padding: 0;
margin: 0;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.markdownroot .highlight {
margin-bottom: 16px;
}
.markdownroot .highlight pre {
margin-bottom: 0;
word-break: normal;
}
.markdownroot .highlight pre,
.markdownroot pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: var(--color-canvas-subtle);
border-radius: 6px;
}
.markdownroot pre code,
.markdownroot pre tt {
display: inline;
max-width: auto;
padding: 0;
margin: 0;
overflow: visible;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
.markdownroot .csv-data td,
.markdownroot .csv-data th {
padding: 5px;
overflow: hidden;
font-size: 12px;
line-height: 1;
text-align: left;
white-space: nowrap;
}
.markdownroot .csv-data .blob-num {
padding: 10px 8px 9px;
text-align: right;
background: var(--color-canvas-default);
border: 0;
}
.markdownroot .csv-data tr {
border-top: 0;
}
.markdownroot .csv-data th {
font-weight: 600;
background: var(--color-canvas-subtle);
border-top: 0;
}
.markdownroot .footnotes {
font-size: 12px;
color: var(--color-fg-muted);
border-top: 1px solid var(--color-border-default);
}
.markdownroot .footnotes ol {
padding-left: 16px;
}
.markdownroot .footnotes li {
position: relative;
}
.markdownroot .footnotes li:target::before {
position: absolute;
top: -8px;
right: -8px;
bottom: -8px;
left: -24px;
pointer-events: none;
content: "";
border: 2px solid var(--color-accent-emphasis);
border-radius: 6px;
}
.markdownroot .footnotes li:target {
color: var(--color-fg-default);
}
.markdownroot .footnotes .data-footnote-backref g-emoji {
font-family: monospace;
}
.markdownroot [hidden] {
display: none !important;
}
.markdownroot ::-webkit-calendar-picker-indicator {
filter: invert(50%);
}
</style><style media="print" id="__markdown-viewer__md_print_css">:root {
background: white;
color: black;
font: 8pt serif;
line-height: 1.5;
vertical-align: baseline;
}
body, .markdownRoot {
max-width: 100%;
margin: 0;
padding: 0;
}
* {
margin: 0;
padding: 0;
}
p {
margin: 0 0 .3rem 0;
}
ul, ol {
padding-left: 2em
}
a {
color: #666;
text-decoration: underline;
}
a[href]:after {
content: ' (' attr(href) ')';
font-size: 1rem;
}
img {
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
padding: 0 0 .2em 0;
}
h1, h2, h3, h4, h5, h6, dt {
/* break-after: avoid; */
break-inside: avoid;
}
/* Hack to fix break-after: https://stackoverflow.com/a/53742871 */
h1:after, h2:after, h3:after, h4:after, h5:after, h6:after, dt:after {
content: "";
display: block;
/* .2em of padding + 3em for 2 full lines */
height: 3.2em;
margin-bottom: -3.2em;
}
blockquote, pre, li, dt, dd {
break-inside: avoid;
}
</style><style id="__markdown-viewer__hljs_css">
@media (prefers-color-scheme: light) { .hljs-comment,.hljs-quote{color:#696969}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#d91e18}.hljs-built_in,.hljs-builtin-name,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#aa5d00}.hljs-attribute{color:#aa5d00}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:green}.hljs-section,.hljs-title{color:#007faa}.hljs-keyword,.hljs-selector-tag{color:#7928a1}.hljs{display:block;overflow-x:auto;background:#fefefe;color:#545454;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}@media screen and (-ms-high-contrast:active){.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-builtin-name,.hljs-bullet,.hljs-comment,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-quote,.hljs-string,.hljs-symbol,.hljs-type{color:highlight}.hljs-keyword,.hljs-selector-tag{font-weight:700}} }
@media (prefers-color-scheme: dark) { .hljs-comment,.hljs-quote{color:#d4d0ab}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ffa07a}.hljs-built_in,.hljs-builtin-name,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#f5ab35}.hljs-attribute{color:gold}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#abe338}.hljs-section,.hljs-title{color:#00e0e0}.hljs-keyword,.hljs-selector-tag{color:#dcc6e0}.hljs{display:block;overflow-x:auto;background:#2b2b2b;color:#f8f8f2;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}@media screen and (-ms-high-contrast:active){.hljs-addition,.hljs-attribute,.hljs-built_in,.hljs-builtin-name,.hljs-bullet,.hljs-comment,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-quote,.hljs-string,.hljs-symbol,.hljs-type{color:highlight}.hljs-keyword,.hljs-selector-tag{font-weight:700}} }</style><style id="__markdown-viewer__katex_css">@font-face{font-family:KaTeX_AMS;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:700}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:700}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:700}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:400}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:700}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:400}@font-face{font-family:"KaTeX_SansSerif";font-style:normal;font-weight:700}@font-face{font-family:"KaTeX_SansSerif";font-style:italic;font-weight:400}@font-face{font-family:"KaTeX_SansSerif";font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Script;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Size1;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Size2;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Size3;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Size4;font-style:normal;font-weight:400}@font-face{font-family:KaTeX_Typewriter;font-style:normal;font-weight:400}.katex{text-rendering:auto;font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.13.13"}.katex .katex-mathml{clip:rect(1px,1px,1px,1px);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-webkit-min-content;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.83333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.16666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.66666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.45666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.14666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.85714286em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.46857143em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.96285714em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.55428571em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.66666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.77777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.88888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.30444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.76444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.58333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.66666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72833333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.07333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.41666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.48611111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.55555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.44027778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.72777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.28935185em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.34722222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.40509259em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.46296296em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.52083333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20023148em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.43981481em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.24108004em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.28929605em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.33751205em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.38572806em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.43394407em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48216008em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57859209em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69431051em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.83317261em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.19961427em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.20096463em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.24115756em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.28135048em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.32154341em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.36173633em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.40192926em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.48231511em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.57877814em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.69453376em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.83360129em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}
</style><style id="__markdown-viewer__texmath_css">/* style for html inside of browsers */
.katex { font-size: 1em !important; } /* align KaTeX font-size to surrounding text */
eq { display: inline-block; }
eqn { display: block}
section.eqno {
display: flex;
flex-direction: row;
align-content: space-between;
align-items: center;
}
section.eqno > eqn {
width: 100%;
margin-left: 3em;
}
section.eqno > span {
width:3em;
text-align:right;
}
</style><style id="__markdown-viewer__menu_css">/* Style for the menu, possible positions/visibility */
#__markdown-viewer__tools {
margin:0;
padding:0;
background:#555;
color:#eee;
box-shadow:0 -1px rgba(0,0,0,.5) inset;
border-radius: .5em;
max-width: 25%;
min-width: 2.8em;
min-height: 3em;
z-index: 2147483647;
position: relative;
}
#__markdown-viewer__tools.floating {
float:right;
margin: 0 0 .5em .5em;
}
#__markdown-viewer__tools.fixed {
max-height: calc(100vh - 1em);
overflow-y: auto;
position:fixed;
top:.5em;
right:1em;
}
#__markdown-viewer__tools.hidden {
display:none;
}
@media print {
#__markdown-viewer__tools {
display: none;
}
}
#__markdown-viewer__tools a[href]:after {
content: "";
}
/* Style for the menu top */
label[for=__markdown-viewer__show-tools] {
display:block;
padding:0 18px 0 12px;
line-height:3em;
background:#333;
cursor:pointer;
border-radius: .5em;
min-height: 3em;
width: .9em;
position: absolute;
right: 0;
}
input#__markdown-viewer__show-tools:not(:checked) ~ label {
margin-left: -.9em;
}
input#__markdown-viewer__show-tools:checked ~ label {
}
label[for=__markdown-viewer__show-tools]:before{
}
label[for=__markdown-viewer__show-tools]:after {
content:"";
display:inline-block;
float:right;
margin-top:1.5em;
right:5px;
width:0;
height:0;
border-style: solid;
border-color: rgba(255,255,255,.5) transparent;
border-width: 4px 4px 0 4px;
transition:border-bottom .1s, border-top .1s .1s;
}
input#__markdown-viewer__show-tools:checked ~ label:after {
border-top-width:0;
border-bottom-width:4px;
transition:border-top .1s, border-bottom .1s .1s;
}
/* hide the input that tracks the menu's visibility */
input#__markdown-viewer__show-tools {
display:none;
}
/* style, and hide/show menu items based on the input being checked */
#__markdown-viewer__tools > .toggleable {
overflow:hidden;
transition-property:max-height, max-width, padding-top, padding-bottom, margin-top, margin-bottom;
transition-duration:0.5s;
}
input#__markdown-viewer__show-tools:checked ~ .toggleable {
/* maxes should be 'none' or infinite values, however those are not aniimatable, so just put something big enough. */
max-width: 2000px;
max-height: 2000px;
overflow-y: auto;
transition-timing-function:ease-in;
}
input#__markdown-viewer__show-tools:not(:checked) ~ .toggleable {
max-height:0;
max-width:0;
transition-timing-function:ease-out;
padding-top:0;
padding-bottom:0;
margin-top:0;
margin-bottom:0;
}
/* style the table of contents and its items */
#__markdown-viewer__toc {
display:block;
padding: .5em;
border:0;
}
#__markdown-viewer__toc::before {
content: "Table of Contents";
text-align: center;
display: block;
font-weight: bold;
text-decoration: underline;
}
#__markdown-viewer__toc {
margin-top: 2em;
}
#__markdown-viewer__tools.fixed input#__markdown-viewer__show-tools:checked ~ #__markdown-viewer__toc {
max-height: calc(100vh - 16em);
}
input#__markdown-viewer__show-tools:checked ~ #__markdown-viewer__toc::before {
position: absolute;
top: .5em;
left: 0;
right: 3em;
}
#__markdown-viewer__tools select {
max-width: 40%;
margin: 0 .5em;
}
#__markdown-viewer__tools select,
#__markdown-viewer__toc * {
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
}
#__markdown-viewer__tools a {
color: white;
text-decoration: none;
}
#__markdown-viewer__toc ul {
list-style: inside "• ";
padding: 0;
margin: 0;
}
#__markdown-viewer__toc ul ul {
padding-left: 1.5em;
}
/* Style the "Download Source" button at the end of the menu */
#__markdown-viewer__tools > p {
text-align:center;
padding: 0 .5em;
}
#__markdown-viewer__download {
/* appearance: button; */
-moz-appearance: button !important;
display:inline-block;
text-align: center;
text-decoration:none;
margin: .5em auto;
}
</style><style id="__markdown-viewer__custom_css"></style><meta name="viewport" content="width=device-width, initial-scale=1"><title>Chapter 3: A Larger Example with Multiple Abstract Syntax Types</title></head><body><div id="__markdown-viewer__tools" class="floating"><input type="checkbox" id="__markdown-viewer__show-tools"><label for="__markdown-viewer__show-tools"></label><div id="__markdown-viewer__toc" class="toggleable"><ul><li><a href="#chapter-3-a-larger-example-with-multiple-abstract-syntax-types">Chapter 3: A Larger Example with Multiple Abstract Syntax Types</a><ul><li><a href="#alternatives-to-consider">Alternatives to Consider</a></li></ul></li></ul></div><p class="toggleable">Pick a markdown and code style:<br><select id="__markdown-viewer__mdselect"><option value="sss">default</option><option value="github">github</option></select><select id="__markdown-viewer__hlselect"><option value="a11y-dark">a11y-dark</option><option value="a11y-light">a11y-light</option><option value="a11y-auto">a11y-auto</option><option value="agate">agate</option><option value="androidstudio">androidstudio</option><option value="an-old-hope">an-old-hope</option><option value="arduino-light">arduino-light</option><option value="arta">arta</option><option value="ascetic">ascetic</option><option value="atelier-cave-dark">atelier-cave-dark</option><option value="atelier-cave-light">atelier-cave-light</option><option value="atelier-cave-auto">atelier-cave-auto</option><option value="atelier-dune-dark">atelier-dune-dark</option><option value="atelier-dune-light">atelier-dune-light</option><option value="atelier-dune-auto">atelier-dune-auto</option><option value="atelier-estuary-dark">atelier-estuary-dark</option><option value="atelier-estuary-light">atelier-estuary-light</option><option value="atelier-estuary-auto">atelier-estuary-auto</option><option value="atelier-forest-dark">atelier-forest-dark</option><option value="atelier-forest-light">atelier-forest-light</option><option value="atelier-forest-auto">atelier-forest-auto</option><option value="atelier-heath-dark">atelier-heath-dark</option><option value="atelier-heath-light">atelier-heath-light</option><option value="atelier-heath-auto">atelier-heath-auto</option><option value="atelier-lakeside-dark">atelier-lakeside-dark</option><option value="atelier-lakeside-light">atelier-lakeside-light</option><option value="atelier-lakeside-auto">atelier-lakeside-auto</option><option value="atelier-plateau-dark">atelier-plateau-dark</option><option value="atelier-plateau-light">atelier-plateau-light</option><option value="atelier-plateau-auto">atelier-plateau-auto</option><option value="atelier-savanna-dark">atelier-savanna-dark</option><option value="atelier-savanna-light">atelier-savanna-light</option><option value="atelier-savanna-auto">atelier-savanna-auto</option><option value="atelier-seaside-dark">atelier-seaside-dark</option><option value="atelier-seaside-light">atelier-seaside-light</option><option value="atelier-seaside-auto">atelier-seaside-auto</option><option value="atelier-sulphurpool-dark">atelier-sulphurpool-dark</option><option value="atelier-sulphurpool-light">atelier-sulphurpool-light</option><option value="atelier-sulphurpool-auto">atelier-sulphurpool-auto</option><option value="atom-one-dark">atom-one-dark</option><option value="atom-one-dark-reasonable">atom-one-dark-reasonable</option><option value="atom-one-light">atom-one-light</option><option value="brown-paper">brown-paper</option><option value="codepen-embed">codepen-embed</option><option value="color-brewer">color-brewer</option><option value="darcula">darcula</option><option value="dark">dark</option><option value="default">default</option><option value="docco">docco</option><option value="dracula">dracula</option><option value="far">far</option><option value="foundation">foundation</option><option value="github">github</option><option value="github-gist">github-gist</option><option value="gml">gml</option><option value="googlecode">googlecode</option><option value="gradient-dark">gradient-dark</option><option value="grayscale">grayscale</option><option value="gruvbox-dark">gruvbox-dark</option><option value="gruvbox-light">gruvbox-light</option><option value="gruvbox-auto">gruvbox-auto</option><option value="hopscotch">hopscotch</option><option value="hybrid">hybrid</option><option value="idea">idea</option><option value="ir-black">ir-black</option><option value="isbl-editor-dark">isbl-editor-dark</option><option value="isbl-editor-light">isbl-editor-light</option><option value="isbl-editor-auto">isbl-editor-auto</option><option value="kimbie">kimbie</option><option value="kimbie">kimbie</option><option value="lightfair">lightfair</option><option value="lioshi">lioshi</option><option value="magula">magula</option><option value="mono-blue">mono-blue</option><option value="monokai">monokai</option><option value="monokai-sublime">monokai-sublime</option><option value="night-owl">night-owl</option><option value="nnfx">nnfx</option><option value="nnfx-dark">nnfx-dark</option><option value="nord">nord</option><option value="obsidian">obsidian</option><option value="ocean">ocean</option><option value="paraiso-dark">paraiso-dark</option><option value="paraiso-light">paraiso-light</option><option value="paraiso-auto">paraiso-auto</option><option value="pojoaque">pojoaque</option><option value="purebasic">purebasic</option><option value="qtcreator_dark">qtcreator_dark</option><option value="qtcreator_light">qtcreator_light</option><option value="qtcreator_auto">qtcreator_auto</option><option value="railscasts">railscasts</option><option value="rainbow">rainbow</option><option value="routeros">routeros</option><option value="school-book">school-book</option><option value="shades-of-purple">shades-of-purple</option><option value="solarized-dark">solarized-dark</option><option value="solarized-light">solarized-light</option><option value="solarized-auto">solarized-auto</option><option value="srcery">srcery</option><option value="sunburst">sunburst</option><option value="tomorrow">tomorrow</option><option value="tomorrow-night">tomorrow-night</option><option value="tomorrow-night-blue">tomorrow-night-blue</option><option value="tomorrow-night-bright">tomorrow-night-bright</option><option value="tomorrow-night-eighties">tomorrow-night-eighties</option><option value="vs">vs</option><option value="vs2015">vs2015</option><option value="xcode">xcode</option><option value="xt256">xt256</option><option value="zenburn">zenburn</option></select></p><p class="toggleable"><a id="__markdown-viewer__download" download="markdown.html" style="display: none;" href="blob:null/6c7af26b-56ee-41c6-a70a-637970844a96">Download as HTML</a></p></div><div class="markdownRoot"><h2 id="chapter-3-a-larger-example-with-multiple-abstract-syntax-types">Chapter 3: A Larger Example with Multiple Abstract Syntax Types</h2>
<p>The principal new feature, available since Rustlr version 0.2.5 (set Cargo
dependency accordingly), and
demonstrated by the third sample grammar is the ability to have more than
a single 'absyntype' that all semantic actions must return. Only
the 'topsym' of the grammar needs to return the absyntype. Each
terminal as well as non-terminal symbol can have a different type
attached as its semantic value. The semantic actions for each
non-terminal must return the type as declared for that
non-terminal.</p>
<p>A grammar declaration such as <em><code>nonterminal E Expr</code></em> or
<em><code>typedterminal int i32</code></em> associate types with individual grammar symbols. If
no type is associated, they will be assigned the declared
absyntype/valuetype. The type associated with the 'topsym' must be the same as the absyntype. <strong>All types must still implement the
Default trait.</strong></p>
<p>In demonstrating this feature we will also take the opportunity to define a
larger language. The grammar below defines a scaled-down version of Java
similar to the language in Andrew Appel's compiler textbooks.</p>
<p>For smaller grammars, using one abstract syntax type, along with the external state type, is
preferable. <strong>A downside of using different types is that it becomes
more difficult to use an alternative lexical analyzer that does not
come with Rustlr.</strong> Semantic values of different types are
accommodated on the parse stack by generating for each grammar an enum
<code>RetTypeEnum</code> that exists only within the generated parser module.
All values must be encoded variants of the enum before being
stacked, and extracted when popped from the stack. The generated parser becomes
less readable because of the extra coded needed. Rustlr's
lexer generation directives <code>lexname</code> and <code>lexvalue</code> will generate code that automatically encode/decode with
respect to the enum. Currently, no support is offered to translate
tokens produced by a lexer other than the built-in <a href="https://docs.rs/rustlr/latest/rustlr/lexer_interface/struct.StrTokenizer.html">StrTokenizer</a>. The best way to see how to
implement a different lexical analyzer is to examine the one that's
automatically generated for this grammar (look for <code>mjenumlexer</code>) and
follow what needs to be done. One has to adopt the lexer to the
Tokenizer trait as well as the specific enum generated for the
grammar.</p>
<p>We present the definition of the abstract syntax along with the grammar.
The files to examine are:</p>
<ol>
<li><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/src/enumabsyn.rs">Abstract Syntax Structures</a></li>
<li><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/mjenum.grammar">Grammar</a></li>
<li><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/src/mjenumparser.rs">Generated Parser/Lexer</a></li>
<li><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/src/main.rs">main.rs</a></li>
<li>Sample "minijava" programs <a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/QuickSort.mj">QuickSort.mj</a> and
<a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/BinaryTree.mj">BinaryTree.mj</a></li>
</ol>
<p>This time, before looking at the grammar first we first become
familiar with the abstract syntax structures defined <a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/src/enumabsyn.rs">here</a> with the core parts
reproduced below:</p>
<pre><code><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Expr</span></span><<span class="hljs-symbol">'t</span>>
{
Int(<span class="hljs-built_in">i32</span>),
Strlit(&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>),
Bool(<span class="hljs-built_in">bool</span>),
Var(&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>),
Thisptr,
Binop(&<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span>,LBox<Expr<<span class="hljs-symbol">'t</span>>>,LBox<Expr<<span class="hljs-symbol">'t</span>>>), <span class="hljs-comment">// includes index,</span>
Notexp(LBox<Expr<<span class="hljs-symbol">'t</span>>>),
Field(&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,LBox<Expr<<span class="hljs-symbol">'t</span>>>),
Newarray(LBox<Expr<<span class="hljs-symbol">'t</span>>>),
Newobj(&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>), <span class="hljs-comment">// String is the class name</span>
Callexp(LBox<Expr<<span class="hljs-symbol">'t</span>>>,&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,<span class="hljs-built_in">Vec</span><LBox<Expr<<span class="hljs-symbol">'t</span>>>>), <span class="hljs-comment">//expr version</span>
Nothing,
}
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Stat</span></span><<span class="hljs-symbol">'t</span>>
{
Whilest(LBox<Expr<<span class="hljs-symbol">'t</span>>>,LBox<Stat<<span class="hljs-symbol">'t</span>>>),
Ifstat(LBox<Expr<<span class="hljs-symbol">'t</span>>>,LBox<Stat<<span class="hljs-symbol">'t</span>>>,LBox<Stat<<span class="hljs-symbol">'t</span>>>),
Vardecst(&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,LBox<Expr<<span class="hljs-symbol">'t</span>>>), <span class="hljs-comment">//name, type, initial val</span>
Returnst(LBox<Expr<<span class="hljs-symbol">'t</span>>>),
Assignst(&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,LBox<Expr<<span class="hljs-symbol">'t</span>>>),
ArAssignst(LBox<Expr<<span class="hljs-symbol">'t</span>>>,LBox<Expr<<span class="hljs-symbol">'t</span>>>,LBox<Expr<<span class="hljs-symbol">'t</span>>>), <span class="hljs-comment">//a[i]=e</span>
Callstat(LBox<Expr<<span class="hljs-symbol">'t</span>>>,&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,<span class="hljs-built_in">Vec</span><LBox<Expr<<span class="hljs-symbol">'t</span>>>>), <span class="hljs-comment">//stat version </span>
Nopst, <span class="hljs-comment">// nop</span>
Blockst(<span class="hljs-built_in">Vec</span><LBox<Stat<<span class="hljs-symbol">'t</span>>>>),
}
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">VarDec</span></span><<span class="hljs-symbol">'t</span>> <span class="hljs-comment">// variable declaration</span>
{
<span class="hljs-keyword">pub</span> dname:&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,
<span class="hljs-keyword">pub</span> dtype:&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,
<span class="hljs-keyword">pub</span> initval:Expr<<span class="hljs-symbol">'t</span>>,
}
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MethodDec</span></span><<span class="hljs-symbol">'t</span>> <span class="hljs-comment">// method declaration</span>
{
<span class="hljs-keyword">pub</span> formals:<span class="hljs-built_in">Vec</span><LBox<VarDec<<span class="hljs-symbol">'t</span>>>>, <span class="hljs-comment">// formal args</span>
<span class="hljs-keyword">pub</span> body: <span class="hljs-built_in">Vec</span><LBox<Stat<<span class="hljs-symbol">'t</span>>>>, <span class="hljs-comment">// should be a Blockst</span>
<span class="hljs-keyword">pub</span> classname: &<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>, <span class="hljs-comment">// added later</span>
<span class="hljs-keyword">pub</span> methodname: &<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,
}
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ClassDec</span></span><<span class="hljs-symbol">'t</span>> <span class="hljs-comment">// class declaration</span>
{
<span class="hljs-keyword">pub</span> superclass:&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,
<span class="hljs-keyword">pub</span> classname:&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,
<span class="hljs-keyword">pub</span> vars: <span class="hljs-built_in">Vec</span><LBox<VarDec<<span class="hljs-symbol">'t</span>>>>,
<span class="hljs-keyword">pub</span> methods: <span class="hljs-built_in">Vec</span><LBox<MethodDec<<span class="hljs-symbol">'t</span>>>>,
}
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Declaration</span></span><<span class="hljs-symbol">'t</span>>
{
Mdec(MethodDec<<span class="hljs-symbol">'t</span>>),
Vdec(VarDec<<span class="hljs-symbol">'t</span>>),
Cdec(ClassDec<<span class="hljs-symbol">'t</span>>),
}
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Mainclass</span></span><<span class="hljs-symbol">'t</span>> <span class="hljs-comment">// main class can only contain a main</span>
{
<span class="hljs-keyword">pub</span> classname:&<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>,
<span class="hljs-keyword">pub</span> argvname: &<span class="hljs-symbol">'t</span> <span class="hljs-built_in">str</span>, <span class="hljs-comment">// name of &'t str[] arg to main</span>
<span class="hljs-keyword">pub</span> body : Stat<<span class="hljs-symbol">'t</span>>, <span class="hljs-comment">// body of main</span>
}
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Program</span></span><<span class="hljs-symbol">'t</span>> <span class="hljs-comment">// absyn value for TOPSYM</span>
{
<span class="hljs-keyword">pub</span> mainclass:LBox<Mainclass<<span class="hljs-symbol">'t</span>>>,
<span class="hljs-keyword">pub</span> otherclasses: <span class="hljs-built_in">Vec</span><LBox<ClassDec<<span class="hljs-symbol">'t</span>>>>,
}
</code></pre>
<p>We've omitted the <code>impl Default</code> segments, which are required for all types.
Essentially, the types distinguish between expressions (Expr), statements
(Stat) and declarations (for variables, methods and classes).<br>
The final type that's returned by the parser is <code>Program</code> which contains
a list of class definitions, one of which contains <code>main</code>.</p>
<p>The grammar is found below. <strong>Please note that the interpretation of semantic
labels of the form <code>E:a</code> has changed</strong>: 'a' no longer represent a <a href="https://docs.rs/rustlr/latest/rustlr/zc_parser/struct.StackedItem.html">StackedItem</a> but the semantic value that's been extracted from the .value field
of the StackedItem, which held the value as an enum variant. However, labels
of the form <code>E:[a]</code> still means that a refers to an <a href="https://docs.rs/rustlr/latest/rustlr/generic_absyn/struct.LBox.html">LBox</a> holding the
extracted value.
Rustlr will automatically detect if symbols of the grammar are declared to
hold types that are different from the declared <code>absyntype</code>, and use different
routines to generate the parser if there is only a single type. Thus grammars
written with a single absyntype will still work the same way they did
before Rustlr 0.2.5.</p>
<pre><code># Grammar <span class="hljs-keyword">for</span> <span class="hljs-string">"minijava"</span>
!<span class="hljs-keyword">use</span> rustlr::LBox;
!<span class="hljs-keyword">use</span> crate::enumabsyn::*;
!<span class="hljs-keyword">use</span> crate::enumabsyn::Declaration::*;
!<span class="hljs-keyword">use</span> crate::enumabsyn::Expr::*;
!<span class="hljs-keyword">use</span> crate::enumabsyn::Stat::*;
lifetime <span class="hljs-symbol">'lt</span>
absyntype Program<<span class="hljs-symbol">'lt</span>>
typedterminal ID &<span class="hljs-symbol">'lt</span> <span class="hljs-built_in">str</span>
typedterminal STRING &<span class="hljs-symbol">'lt</span> <span class="hljs-built_in">str</span>
typedterminal BOOL <span class="hljs-built_in">bool</span>
typedterminal INTEGER <span class="hljs-built_in">i32</span>
terminal class public <span class="hljs-keyword">static</span> void main <span class="hljs-built_in">String</span> extends <span class="hljs-keyword">return</span> length
terminal ( ) [ ] ; DOT ! , new this
terminal LBR RBR OROR
terminal int boolean <span class="hljs-keyword">if</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">while</span> == = + - * / < && MOD
nonterminal Program Program<<span class="hljs-symbol">'lt</span>>
nonterminal MainCl Mainclass<<span class="hljs-symbol">'lt</span>>
nonterminal ClassDec ClassDec<<span class="hljs-symbol">'lt</span>>
nonterminal ClassDecl <span class="hljs-built_in">Vec</span><LBox<ClassDec<<span class="hljs-symbol">'lt</span>>>>
nonterminal Extension &<span class="hljs-symbol">'lt</span> <span class="hljs-built_in">str</span>
nonterminal VarDec VarDec<<span class="hljs-symbol">'lt</span>>
nonterminal MethodDec MethodDec<<span class="hljs-symbol">'lt</span>>
nonterminal Decl <span class="hljs-built_in">Vec</span><LBox<Declaration<<span class="hljs-symbol">'lt</span>>>>
nonterminal FormalLst <span class="hljs-built_in">Vec</span><LBox<VarDec<<span class="hljs-symbol">'lt</span>>>>
nonterminal FormalRst <span class="hljs-built_in">Vec</span><LBox<VarDec<<span class="hljs-symbol">'lt</span>>>>
nonterminal Type &<span class="hljs-symbol">'lt</span> <span class="hljs-built_in">str</span>
nonterminal Stat Stat<<span class="hljs-symbol">'lt</span>>
nonterminal Stats <span class="hljs-built_in">Vec</span><LBox<Stat<<span class="hljs-symbol">'lt</span>>>>
nonterminal Exp Expr<<span class="hljs-symbol">'lt</span>>
nonterminal ExpLst <span class="hljs-built_in">Vec</span><LBox<Expr<<span class="hljs-symbol">'lt</span>>>>
nonterminal ExpRst <span class="hljs-built_in">Vec</span><LBox<Expr<<span class="hljs-symbol">'lt</span>>>>
topsym Program
resync ;
left + <span class="hljs-number">500</span>
left - <span class="hljs-number">510</span>
left * <span class="hljs-number">700</span>
left / <span class="hljs-number">710</span>
left && <span class="hljs-number">400</span>
left OROR <span class="hljs-number">350</span>
left ! <span class="hljs-number">450</span>
left == <span class="hljs-number">310</span>
left = <span class="hljs-number">800</span>
left < <span class="hljs-number">300</span>
left MOD <span class="hljs-number">705</span>
left DOT <span class="hljs-number">810</span>
# to deal with the dangling-<span class="hljs-keyword">else</span> problem, <span class="hljs-keyword">else</span> is given higher precedence
# than <span class="hljs-keyword">if</span>. Reduction by (Stat --> <span class="hljs-keyword">if</span> (Exp) Stat) will be delayed <span class="hljs-keyword">if</span> the
# the lookahead symbol is <span class="hljs-symbol">'else</span>'.
left <span class="hljs-keyword">if</span> <span class="hljs-number">30</span>
left <span class="hljs-keyword">else</span> <span class="hljs-number">40</span>
Program --> MainCl:[mc] ClassDecl:cs { Program {mainclass:mc, otherclasses:cs } }
MainCl ==> class ID:cn LBR public <span class="hljs-keyword">static</span> void main ( <span class="hljs-built_in">String</span> [ ] ID:an ) LBR Stats:thebody RBR RBR {
Mainclass{classname:cn,
argvname:an,
body: Blockst(thebody),
}
} <==
ClassDecl --> { <span class="hljs-built_in">Vec</span>::new() }
ClassDecl --> ClassDecl:cs ClassDec:[cl] { cs.push(cl); cs }
ClassDec ==> class ID:name Extension:sup LBR Decl:ds RBR {
<span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> vdecs=<span class="hljs-built_in">Vec</span>::new();
<span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> mdecs=<span class="hljs-built_in">Vec</span>::new();
separatedecs(ds,&<span class="hljs-keyword">mut</span> vdecs,&<span class="hljs-keyword">mut</span> mdecs); <span class="hljs-comment">/*split var and method declarations*/</span>
ClassDec {superclass:sup,
classname:name,
vars:vdecs,
methods:mdecs}
} <==
Extension --> extends Type:sup { sup }
Extension --> { <span class="hljs-string">"Object"</span> }
VarDec --> Type:t ID:v ; { VarDec{dname:v,dtype:t,initval:Nothing,} }
VarDec --> Type:t ID:v = Exp:e ; {VarDec{dname:v,dtype:t,initval:e}}
MethodDec ==> public Type:ty ID:name ( FormalLst:args ) LBR Stats:mbody RBR {
MethodDec{ formals:args,
body: mbody,
classname:ty,
methodname:name, }
} <==
Decl --> { <span class="hljs-built_in">Vec</span>::new() }
Decl --> Decl:ds VarDec:v { ds.push(parser.lbx(<span class="hljs-number">1</span>,Vdec(v))); ds }
Decl --> Decl:ds MethodDec:m { ds.push(parser.lbx(<span class="hljs-number">1</span>,Mdec(m))); ds }
FormalLst --> { <span class="hljs-built_in">Vec</span>::new() }
# warning: list constructed backwards:
FormalLst ==> Type:ty ID:a FormalRst:frs {
frs.push(parser.lb(VarDec{dname:a,dtype:ty,initval:Nothing}));
frs
} <==
FormalRst --> { <span class="hljs-built_in">Vec</span>::new() }
FormalRst ==> , Type:ty ID:a FormalRst:frs {
frs.push(parser.lb(VarDec{dname:a,dtype:ty,initval:Nothing}));
frs
} <==
Type --> int [ ] { <span class="hljs-keyword">return</span> <span class="hljs-string">"int[]"</span>; }
Type --> boolean { <span class="hljs-keyword">return</span> <span class="hljs-string">"boolean"</span>; }
Type --> <span class="hljs-built_in">String</span> { <span class="hljs-keyword">return</span> <span class="hljs-string">"String"</span>; }
Type --> int { <span class="hljs-keyword">return</span> <span class="hljs-string">"int"</span>; }
Type --> void { <span class="hljs-keyword">return</span> <span class="hljs-string">"void"</span>; }
Type --> ID:c { c }
Stats --> { <span class="hljs-built_in">Vec</span>::new() }
Stats --> Stats:sv Stat:[s] { sv.push(s); sv }
Stat --> LBR Stats:sv RBR { Blockst(sv) }
Stat --> <span class="hljs-keyword">if</span> ( Exp:[c] ) Stat:[a] <span class="hljs-keyword">else</span> Stat:[b] { Ifstat(c, a, b) }
Stat --> <span class="hljs-keyword">if</span> ( Exp:[c] ) Stat:[a] { Ifstat(c,a,parser.lb(Nopst)) }
Stat --> <span class="hljs-keyword">while</span> ( Exp:[c] ) Stat:[s] { Whilest(c,s) }
Stat --> ID:v = Exp:[e] ; { Assignst(v,e) }
Stat --> Exp:[v] [ Exp:[i] ] = Exp:[e] ; { ArAssignst(v,i,e) }
Stat --> Exp:[obj] DOT ID:m ( ExpLst:args ) ; {Callstat(obj,m,args)}
Stat --> <span class="hljs-keyword">return</span> Exp:[e] ; { Returnst(e) }
Stat --> VarDec:v {Vardecst(v.dname,v.dtype,parser.lb(v.initval))}
Exp --> Exp:[a] * Exp:[b] { Binop(<span class="hljs-string">"*"</span>,a,b) }
Exp --> Exp:[a] + Exp:[b] { Binop(<span class="hljs-string">"+"</span>,a,b) }
Exp --> Exp:[a] / Exp:[b] { Binop(<span class="hljs-string">"/"</span>,a,b) }
Exp --> Exp:[a] - Exp:[b] { Binop(<span class="hljs-string">"-"</span>,a,b) }
Exp --> Exp:[a] && Exp:[b] { Binop(<span class="hljs-string">"&&"</span>,a,b) }
Exp --> Exp:[a] OROR Exp:[b] { Binop(<span class="hljs-string">"OROR"</span>,a,b) }
Exp --> ! Exp:[a] { Notexp(a) }
Exp --> Exp:[a] < Exp:[b] { Binop(<span class="hljs-string">"<"</span>,a,b) }
Exp --> Exp:[a] MOD Exp:[b] { Binop(<span class="hljs-string">"%"</span>,a,b) }
Exp --> Exp:[a] == Exp:[b] { Binop(<span class="hljs-string">"=="</span>,a,b) }
Exp --> Exp:[a] [ Exp:[i] ] { Binop(<span class="hljs-string">"[]"</span>,a,i) }
Exp --> Exp:[obj] DOT ID:field { Field(field,obj) }
Exp --> Exp:[obj] DOT ID:f ( ExpLst:args ) { Callexp(obj,f,args) }
Exp --> INTEGER:i { Int(i) }
Exp --> STRING:s { Strlit(s) }
Exp --> BOOL:b { Bool(b) }
Exp --> ID:x { Var(x) }
Exp --> this { Thisptr }
Exp --> new int [ Exp:[s] ] { Newarray(s) }
Exp --> new Type:x ( ) { Newobj(x) }
Exp --> ( Exp:e ) { e }
# warning: backwards list:
ExpLst --> { <span class="hljs-built_in">Vec</span>::new() }
ExpLst --> Exp:[e] ExpRst:er { er.push(e); er }
ExpRst --> { <span class="hljs-built_in">Vec</span>::new() }
ExpRst --> , Exp:[e] ExpRst:er { er.push(e); er }
# Lexical scanner setup using StrTokenizer
lexname DOT .
lexname MOD %
lexname LBR {
lexname RBR }
lexname OROR ||
lexvalue BOOL Alphanum(<span class="hljs-string">"true"</span>) <span class="hljs-literal">true</span>
lexvalue BOOL Alphanum(<span class="hljs-string">"false"</span>) <span class="hljs-literal">false</span>
lexvalue ID Alphanum(x) x
lexvalue INTEGER Num(n) (n <span class="hljs-keyword">as</span> <span class="hljs-built_in">i32</span>)
lexvalue STRING Strlit(s) s
EOF
</code></pre>
<p>Please note that the function
<a href="https://docs.rs/rustlr/latest/rustlr/zc_parser/struct.ZCParser.html#method.lb">ZCParser::lb</a>
had to be called to create certain <a href="https://docs.rs/rustlr/latest/rustlr/generic_absyn/struct.LBox.html">LBox</a> structures. Each item on
the stack contains the staring line/column position of that construct.
The parser itself also maintains it's own current line/column
position, which are used to form the LBox when <code>parser.lb</code> is called.
The <a href="https://docs.rs/rustlr/latest/rustlr/zc_parser/struct.ZCParser.html#method.lbx">ZCParser::lbx</a> function cannot be called when the right-hand
side of a production rule is empty.</p>
<p>Invoking the parser also requires a different procedure (find in main).
One can still call the .parse function on the generated parser but it
would return a value of the internal enum type.
The generated parser now contains two additional functions: <strong><code>parse_with</code></strong>
and <strong><code>parse_train_with</code></strong>. These functions include code to
extract the final semantic value from an enum variant. The return type of
these functions is in both cases <strong><code>Result<absyntype,absyntype></code></strong>: that is, a parse tree
is always returned, either as Ok(tree) or as Err(tree) if a parse error
has occurred.</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>()
{
<span class="hljs-keyword">let</span> args:<span class="hljs-built_in">Vec</span><<span class="hljs-built_in">String</span>> = std::env::args().collect();
<span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> srcfile = <span class="hljs-string">""</span>;
<span class="hljs-keyword">if</span> args.len()><span class="hljs-number">1</span> {srcfile = &args[<span class="hljs-number">1</span>];}
<span class="hljs-keyword">let</span> source = LexSource::new(srcfile).unwrap();
<span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> scanner3 = mjenumlexer::from_source(&source);
<span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> parser3 = make_parser();
<span class="hljs-keyword">let</span> result3 = parse_with(&<span class="hljs-keyword">mut</span> parser3, &<span class="hljs-keyword">mut</span> scanner3);
<span class="hljs-keyword">let</span> absyntree3 = result3.unwrap_or_else(|x|{<span class="hljs-built_in">println!</span>(<span class="hljs-string">"Parsing Errors Encountered"</span>); x});
<span class="hljs-built_in">println!</span>(<span class="hljs-string">"abstract syntax tree after parse: {:?}\n"</span>,absyntree3);
}<span class="hljs-comment">//main</span>
</code></pre>
<p>One could still call
<a href="https://docs.rs/rustlr/latest/rustlr/zc_parser/struct.ZCParser.html#method.parse">ZCParser::parse</a> and
<a href="https://docs.rs/rustlr/latest/rustlr/zc_parser/struct.ZCParser.html#method.parse_train">ZCParser::parse_train</a> directly.
However, these function now return the abstract syntax enclosed within the
generated enum. Each generated parser therefore contains its own
<strong><code>parse_with</code></strong> and <strong><code>parse_train_with</code></strong> functions.</p>
<h3 id="alternatives-to-consider">Alternatives to Consider</h3>
<p>Using different types by generating an internal enum comes at the cost
of tightly coupling the built-in lexer <a href="https://docs.rs/rustlr/latest/rustlr/lexer_interface/struct.StrTokenizer.html">StrTokenizer</a> to the parser, because code
must be generated to translate the tokens produced by the lexer into
the enum. There is an alternative way to have semantic actions produce
values of different types: specifying <strong><code>LBox<dyn Any></code></strong> as the absyntype of
grammar will invoke a different parser generation routine that automatically
upcasts/downcasts each semantic value into this generic type. This approach
allows the parser generation routines to stay generic, and does not
require a custom treatment of lexical tokens. However, this object-oriented
approach also comes with its own costs: it's slower, does not accommodate
non-static references (they don't implement Any), and compromises static
type safety. There is an <strong><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/lbany.html">original "Chapter 3"</a></strong> that explains how to use this approach,
A version of the "minijava" grammar that uses this approach
is found <strong><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/lbamj.grammar">here</a></strong>.</p>
<p>One can always create an enum manually and still use a single absyntype
declaration for the entire grammar. Combined with pattern matching, this
approach is another viable alternative even with larger grammars. This
version of the "minijava" grammar can be found <strong><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/mj.grammar">here</a></strong> along with its alternative
<a href="https://cs.hofstra.edu/~cscccl/rustlr_project/minijava/src/absyntax.rs">abstract syntax structures</a>. The main difference between these structures and
the one shown here is the <code>Construct</code> enum that ties all the different types
together.</p>
<p>In addition to the absyntype, there also the 'externtype' that's carried
by each parser. Thus one can use at least two types when creating
abstract syntax. For example, the main absyntype can be called 'Expression'
while the externtype can be a 'Vec<expression>'. An example of this
approach is found <strong><a href="https://cs.hofstra.edu/~cscccl/rustlr_project/lambdascript/untyped.grammar">here</a></strong>, which is the grammar for <a href="https://crates.io/crates/lambdascript">lambdascript</a>, an interpreter for the pure untyped lambda calculus.</expression></p>
<hr>
</div></body></html>