Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for replacement algorithms and for xrefs to steps #217

Merged
merged 3 commits into from
Jun 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions css/elements.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,43 @@ emu-const {
emu-val {
font-weight: bold;
}
emu-alg ol, emu-alg ol ol ol ol {
list-style-type: decimal;
}

emu-alg ol ol, emu-alg ol ol ol ol ol {
list-style-type: lower-alpha;
}

emu-alg ol ol ol, ol ol ol ol ol ol {
list-style-type: lower-roman;
/* depth 1 */
emu-alg ol,
/* depth 4 */
emu-alg ol ol ol ol,
emu-alg ol.nested-thrice,
emu-alg ol.nested-twice ol,
emu-alg ol.nested-once ol ol {
list-style-type: decimal;
}

/* depth 2 */
emu-alg ol ol,
emu-alg ol.nested-once,
/* depth 5 */
emu-alg ol ol ol ol ol,
emu-alg ol.nested-four-times,
emu-alg ol.nested-thrice ol,
emu-alg ol.nested-twice ol ol,
emu-alg ol.nested-once ol ol ol {
list-style-type: lower-alpha;
}

/* depth 3 */
emu-alg ol ol ol,
emu-alg ol.nested-twice,
emu-alg ol.nested-once ol,
/* depth 6 */
emu-alg ol ol ol ol ol ol,
emu-alg ol.nested-lots,
emu-alg ol.nested-four-times ol,
emu-alg ol.nested-thrice ol ol,
emu-alg ol.nested-twice ol ol ol,
emu-alg ol.nested-once ol ol ol ol,
/* depth 7+ */
emu-alg ol.nested-lots ol {
list-style-type: lower-roman;
}

emu-eqn {
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ecmarkup",
"version": "3.24.0",
"version": "3.25.0",
"description": "Custom element definitions and core utilities for markup that specifies ECMAScript and related technologies.",
"main": "lib/ecmarkup.js",
"typings": "lib/ecmarkup.d.ts",
Expand Down Expand Up @@ -44,7 +44,7 @@
"dependencies": {
"bluebird": "^3.7.2",
"chalk": "^1.1.3",
"ecmarkdown": "^5.0.2",
"ecmarkdown": "^5.1.0",
"eslint": "^6.8.0",
"grammarkdown": "^2.2.0",
"highlight.js": "^9.17.1",
Expand Down
48 changes: 41 additions & 7 deletions spec/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/solarized_light.min.css">
<title>Ecmarkup</title>
<pre class=metadata>
repository: https://github.com/bterlson/ecmarkup
repository: https://github.com/tc39/ecmarkup
assets: none
copyright: false
</pre>
<emu-biblio href="./biblio.json"></emu-biblio>
<emu-intro id="intro">
<h1>Ecmarkup</h1>
<p><a href="https://github.com/bterlson/ecmarkup">Ecmarkup</a> is a number of custom elements and a toolchain suitable for specifying semantics for ECMAScript and other programming languages.</p>
<p><a href="https://github.com/tc39/ecmarkup">Ecmarkup</a> is a number of custom elements and a toolchain suitable for specifying semantics for ECMAScript and other programming languages.</p>
<p>Ecmarkup offers the following conveniences (among many others):</p>
<ul>
<li><a href="https://github.com/domenic/ecmarkdown">Ecmarkdown</a> syntax for paragraphs and algorithms</li>
<li><a href="https://github.com/tc39/ecmarkdown">Ecmarkdown</a> syntax for paragraphs and algorithms</li>
<li><a href="https://github.com/rbuckton/grammarkdown">Grammarkdown</a> for specifying grammar</li>
<li>Terse markup for the authoring conventions used in ECMAScript specifications including clauses, notes, examples, figures, tables, and more.</li>
<li>Easy cross-references by element ID to clauses, abstract operations, examples, figures, tables, and etc. in the current document, ES6, and other specs.</li>
Expand All @@ -24,7 +24,7 @@ <h1>Ecmarkup</h1>
<li>Auto-links abstract operations and terms based on name with support for external bibliographies for cross-referencing between specs</li>
<li>Source code syntax highlighting inside pre code blocks</li>
</ul>
<p>This document is itself written using Ecmarkup. Its source can be viewed <a href="https://github.com/bterlson/ecmarkup/blob/master/spec/index.html">on github</a>.</p>
<p>This document is itself written using Ecmarkup. Its source can be viewed <a href="https://github.com/tc39/ecmarkup/blob/master/spec/index.html">on github</a>.</p>
</emu-intro>

<emu-clause id="getting-started">
Expand Down Expand Up @@ -93,7 +93,7 @@ <h1>Editorial Conventions</h1>
</table>
</emu-table>

<p>There are also a number of elements and corresponding Ecmarkdown syntax to give inline styles to various parts of your document in accordance with ECMAScript conventions. More detail on Ecmarkdown syntax can be found <a href="https://github.com/domenic/ecmarkdown">on its readme</a>.</p>
<p>There are also a number of elements and corresponding Ecmarkdown syntax to give inline styles to various parts of your document in accordance with ECMAScript conventions. More detail on Ecmarkdown syntax can be found <a href="https://github.com/tc39/ecmarkdown">on its readme</a>.</p>
<emu-table id="emd-overview">
<emu-caption>Inline styles/conventions</emu-caption>
<table>
Expand Down Expand Up @@ -198,6 +198,36 @@ <h3>Result</h3>
1. let _recurse_ be the result of calling EmuAlgExample(`true`)
2. Return the result of evaluating this |NonTerminalProduction|
</emu-alg>

<h2>Replacement algorithms</h2>
<p>Algorithms may be specified to replace a labeled step, in which case the algorithm will adopt the numbering of that step. For example:</p>

<h3>Element</h3>
<pre><code class="language-html">
&lt;emu-alg>
1. Step.
1. Step 2.
1. [label="replace-me"] Replaced.
1. Substep.
&lt;/emu-alg>
&lt;p>The following is an alernative definition of step &lt;emu-xref href="#step-replace-me">&lt;/emu-xref>.&lt;/p>
&lt;emu-alg replaces-step="replace-me">
1. Replacement.
1. Substep.
&lt;/emu-alg>
</code></pre>
<h3>Result</h3>
<emu-alg>
1. Step.
1. Step 2.
1. [label="replace-me"] Replaced.
1. Substep.
</emu-alg>
<p>The following is an alernative definition of step <emu-xref href="#step-replace-me"></emu-xref>.</p>
<emu-alg replaces-step="replace-me">
1. Replacement.
1. Substep.
</emu-alg>
</emu-clause>

<emu-clause id="emu-eqn">
Expand All @@ -223,8 +253,8 @@ <h2>Example</h2>

<emu-clause id="emu-xref">
<h1>emu-xref</h1>
<p>Cross-reference another clause, production, note, example, or abstract operation. If the text content of this element is empty, a suitable default is used. The `title` attribute controls this default - when present, clauses are referred to using their title rather than number. This also applies to examples which are indexed first by their containing clause and then their example number.</p>
<p>Cross-references to an id check for clauses, productions, and examples in this order. For each type, the local document is consulted before looking for external sources including the default ES6 biblio.</p>
<p>Cross-reference another clause, production, note, example, abstract operation, or labeled step. If the text content of this element is empty, a suitable default is used. The `title` attribute controls this default - when present, clauses are referred to using their title rather than number. This also applies to examples which are indexed first by their containing clause and then their example number.</p>
<p>Cross-references to an id check for clauses, productions, examples, and steps in this order. For each type, the local document is consulted before looking for external sources including the default ES6 biblio.</p>

<h2>Attributes</h2>
<p><b>href:</b> Optional: URL of the target clause, production, or example to cross-reference.</p>
Expand All @@ -239,13 +269,17 @@ <h2>Example</h2>
&lt;p>See &lt;emu-xref href="#emu-note" title>&lt;/emu-xref> for information on the emu-note element.&lt;/p>
&lt;p>The &lt;emu-xref href="#emu-biblio">biblio element&lt;/emu-xref> supports xref to external specs.&lt;/p>
&lt;p>&lt;emu-xref aoid="Get">&lt;/emu-xref> is an abstract operation from ES6&lt;/p>
&lt;p>&lt;emu-alg>1. [label="example-step-label"] Example labeled step.&lt;/emu-alg>&lt;/p>
&lt;p>You can reference step &lt;emu-xref href="#step-example-step-label">&lt;/emu-xref> like this&lt;/p>
</code></pre>

<b>Result</b>
<p>The clause element is specified in <emu-xref href="#emu-clause"></emu-xref>.</p>
<p>See <emu-xref href="#emu-note" title></emu-xref> for information on the emu-note element.</p>
<p>The <emu-xref href="#emu-biblio">biblio element</emu-xref> will eventually support xref to external specs.</p>
<p><emu-xref aoid="Get"></emu-xref> is an abstract operation from ES6</p>
<p><emu-alg>1. [label="example-step-label"] Example labeled step.</emu-alg></p>
<p>You can reference step <emu-xref href="#step-example-step-label"></emu-xref> like this</p>
</emu-clause>

<emu-clause id="emu-not-ref" namespace="emu-not-ref">
Expand Down
59 changes: 50 additions & 9 deletions src/Algorithm.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Context } from './Context';
import type { StepBiblioEntry } from './Biblio';

import { logWarning } from './utils';
import Builder from './Builder';
import * as emd from 'ecmarkdown';

Expand All @@ -9,22 +11,61 @@ export default class Algorithm extends Builder {
context.inAlg = true;
const { node } = context;

if ('ecmarkdownOut' in node) {
// i.e., we already parsed this during the lint phase
// @ts-ignore
node.innerHTML = node.ecmarkdownOut.replace(/((?:\s+|>)[!?])\s+(\w+\s*\()/g, '$1&nbsp;$2');
return;
}
// prettier-ignore
const rawHtml =
'ecmarkdownOut' in node
? (node as any).ecmarkdownOut
: emd.algorithm(node.innerHTML);

// replace spaces after !/? with &nbsp; to prevent bad line breaking
const html = emd
.algorithm(node.innerHTML)
.replace(/((?:\s+|>)[!?])\s+(\w+\s*\()/g, '$1&nbsp;$2');
const html = rawHtml.replace(/((?:\s+|>)[!?])\s+(\w+\s*\()/g, '$1&nbsp;$2');
node.innerHTML = html;

let labeledStepEntries: StepBiblioEntry[] = [];
let replaces = node.getAttribute('replaces-step');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this attribute from the output?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ecmarkup doesn't really clean up after itself, as a rule - all the emu-whatever tags are in the output, etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine. We should reconsider that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #218 to track.

if (replaces) {
replaces = 'step-' + replaces;
context.spec.replacementAlgorithms.push({
element: node,
target: replaces,
});
context.spec.replacementAlgorithmToContainedLabeledStepEntries.set(node, labeledStepEntries);
}

let labeledSteps = Array.from(node.querySelectorAll('li[id]'));
if (replaces && labeledSteps.length > 0 && node.firstElementChild!.children.length > 1) {
logWarning(
'You should not label a step in a replacement algorithm which has multiple top-level steps because the resulting step number could be ambiguous.'
);
}

for (const step of labeledSteps) {
let entry: StepBiblioEntry = {
type: 'step',
id: step.id,
stepNumbers: getStepNumbers(step as Element),
referencingIds: [],
};
context.spec.biblio.add(entry);
if (replaces) {
// The biblio entries for labeled steps in replacement algorithms will be modified in-place by a subsequent pass
labeledStepEntries.push(entry);
context.spec.labeledStepsToBeRectified.add(step.id);
}
}
}

static exit(context: Context) {
context.inAlg = false;
}
static elements = ['EMU-ALG'];
}

function getStepNumbers(item: Element) {
let counts = [];
while (item.parentElement?.tagName === 'OL') {
counts.unshift(1 + Array.from(item.parentElement.children).indexOf(item));
item = item.parentElement.parentElement!;
}
return counts;
}
14 changes: 13 additions & 1 deletion src/Biblio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ export default class Biblio {
entry.namespace = ns;
env!.push(entry);
if (entry.id) {
if ({}.hasOwnProperty.call(this, entry.id)) {
throw new Error('Duplicate biblio entry ' + JSON.stringify(entry.id) + '.');
}
this._byId[entry.id] = entry;
}
}
Expand Down Expand Up @@ -263,12 +266,19 @@ export interface FigureBiblioEntry extends BiblioEntryBase {
caption?: string;
}

export interface StepBiblioEntry extends BiblioEntryBase {
type: 'step';
id: string;
stepNumbers: number[];
}

export type BiblioEntry =
| AlgorithmBiblioEntry
| ProductionBiblioEntry
| ClauseBiblioEntry
| TermBiblioEntry
| FigureBiblioEntry;
| FigureBiblioEntry
| StepBiblioEntry;

function dumpEnv(env: EnvRec) {
console.log('## ' + env._namespace);
Expand Down Expand Up @@ -308,6 +318,8 @@ function getKey(item: BiblioEntry) {
case 'example':
case 'note':
return item.caption;
case 'step':
return item.id;
default:
throw new Error("Can't get key for " + (<BiblioEntry>item).type);
}
Expand Down
Loading