diff --git a/index.html b/index.html index cb5d3b0..2206451 100644 --- a/index.html +++ b/index.html @@ -1,2896 +1,218 @@ - - - - - - - Error Stacks - - - - - - - - - -
-

Stage 1 Draft / October 21, 2017

-

Error Stacks

- - -

1System

- - -

1.1System.getStack ( error )

-

When the getStack method is called with argument error, the following steps are taken:

- -
    -
  1. If error does not have an [[ErrorData]] internal slot, throw a - TypeError exception.
  2. -
  3. Return ?  - GetStack(error). -
  4. -
-
-
- - -

1.2System.getStackString ( error )

-

When the getStackString method is called with argument error, the following steps are taken:

- -
    -
  1. If error does not have an [[ErrorData]] internal slot, throw a - TypeError exception.
  2. -
  3. Return ?  - GetStackString(error). -
  4. -
-
-
+ + + + +Error Stacks

Stage 1 Draft / February 17, 2021

Error Stacks

+ + +

1 System

+ + +

1.1 System.getStack ( error )

+

When the getStack method is called with argument error, the following steps are taken:

+
  1. Perform ? RequireInternalSlot(error, [[ErrorData]]).
  2. Let string be ? GetStackString(error).
  3. Let frames be ! GetStackFramesArray(error).
  4. Let obj be ! ObjectCreate(%ObjectPrototype%).
  5. Perform ! CreateDataPropertyOrThrow(obj, "frames", frames).
  6. Perform ! CreateDataPropertyOrThrow(obj, "string", string).
  7. Return obj.
+ + +

1.1.1 GetStackFramesArray ( error )

+

The abstract operation GetStackFramesArray takes argument error. It performs the following steps when called:

+
  1. Assert: error is an Object that has an [[ErrorData]] internal slot.
  2. Let frames be a new empty List.
  3. For each Stack Frame Record frame of error.[[ErrorData]], append ! FromStackFrame(frame) to frames.
  4. Return ! CreateArrayFromList(frames).
+
- -

2GetStack ( error )

-

When the abstract operation GetStack is called with argument error, the following steps are performed:

- -
    -
  1. Assert: error has an [[ErrorData]] internal slot.
  2. -
  3. Let frames be !  - GetStackFrames(error).
  4. -
  5. Let string be ?  - GetStackString(error).
  6. -
  7. Let obj be !  - ObjectCreate( - %ObjectPrototype%).
  8. -
  9. Perform !  - CreateDataProperty(obj, - "frames", frames).
  10. -
  11. Assert: The above - CreateDataProperty operation returns - true.
  12. -
  13. Perform !  - CreateDataProperty(obj, - "string", string).
  14. -
  15. Assert: The above - CreateDataProperty operation returns - true.
  16. -
  17. Let status be !  - SetIntegrityLevel(obj, - "frozen").
  18. -
  19. Assert: status is - true.
  20. -
  21. Return obj. -
  22. -
-
-
+ +

1.2 System.getStackString ( error )

+

When the getStackString method is called with argument error, the following steps are taken:

+
  1. Perform ? RequireInternalSlot(error, [[ErrorData]]).
  2. Return ? GetStackString(error).
-

3GetStackString ( error )

-

When the abstract operation GetStackString is called with argument error, the following steps are performed:

- -
    -
  1. Assert: error has an [[ErrorData]] internal slot.
  2. -
  3. Let errorString be ?  - ToString(error).
  4. -
  5. Let frames be !  - GetStackFrames(error).
  6. -
  7. Let frameString be a String consisting solely of the code unit 0x0020 (SPACE).
  8. -
  9. For each Stack Frame frame in frames, -
      -
    1. If frameString does not consist solely of the code unit 0x0020 (SPACE), -
        -
      1. Let frameString be the concatenation of frameString, the code unit 0x000A (LINE FEED), and the code unit 0x0020 (SPACE).
      2. -
      -
    2. -
    3. Let frameString be the concatenation of frameString and !  - GetFrameString(frame).
    4. -
    -
  10. -
  11. Let stackString be the concatenation of errorString, the code unit 0x000A (LINE FEED), and frameString.
  12. -
  13. Return stackString. -
  14. -
-
+

1.2.1 GetStackString ( error )

+

The abstract operation GetStackString takes argument error. It performs the following steps when called:

+
  1. Assert: error is an Object that has an [[ErrorData]] internal slot.
  2. Let stackString be ? ToString(error).
  3. For each Stack Frame Record frame of error.[[ErrorData]], do
    1. Let frameString be ! GetStackFrameString(frame).
    2. Set stackString to the string-concatenation of stackString, the code unit 0x000A (LINE FEED), the code unit 0x0020 (SPACE), and frameString.
  4. Return stackString.
- - -

4GetFrameString ( frame )

-

When the abstract operation GetFrameString is called with argument frame, the following steps are performed:

- -
    -
  1. Assert: !  - IsStackFrame(frame) is - true.
  2. -
  3. Let source be frame.[[Source]].
  4. -
  5. If - Type(source) is not String, -
      -
    1. Assert: !  - IsStackFrame(source) is - true.
    2. -
    3. Let source be the concatenation of - "eval" and !  - GetFrameString(source).
    4. -
    -
  6. -
  7. Assert: !  - Type(source) is String.
  8. -
  9. Let spanString be !  - GetStackFrameSpanString(source.[[Span]]).
  10. -
  11. return a String formed by concatenating the code unit 0x0020 (SPACE), - "at", the code unit 0x0020 (SPACE), frame.[[Name]], the code unit 0x0020 (SPACE), - "(", source, spanString, and - ")". -
  12. -
-
+
+
+ + +

2 Error Objects

+ + +

2.1 Properties of Error Instances

+

Error instances are ordinary objects that inherit properties from the Error prototype object and have an [[ErrorData]] internal slot whose value is undefined. The only specified uses of [[ErrorData]] is to identify Error, AggregateError, and NativeError instances as Error objects within Object.prototype.toString(the intrinsic, %Error.prototype%). Error instances are initially created with the internal slots described in Table 1.

+ +
Table 1: Internal Slots of Error Instances
+ + + + + + + + + + + +
Internal SlotDescription
[[ErrorData]]A List of Stack Frame records.
+
+
+
+ + +

2.2 Stack Frame Records

+

A Stack Frame Record is a Record value used to store stack information of Error objects.

+

Stack Frame Records have the fields listend in Table 2

+
Table 2: Stack Frame Record Fields
+ + + + + + + + + + + + + + + + + + + +
Field NameValue
[[Name]]String
[[Source]]String | Stack Frame Record
[[Span]]Stack Frame Span Record | empty
+
+ + +

2.2.1 FromStackFrame ( frame )

+

The abstract operation FromStackFrame takes argument frame (a Stack Frame Record). It performs the following steps when called:

+
  1. Let obj be ! ObjectCreate(%ObjectPrototype%).
  2. Perform ! CreateDataPropertyOrThrow(obj, "name", frame.[[Name]]).
  3. If frame.[[Source]] is a Stack Frame Record, then
    1. Let sourceFrameObj be ! FromStackFrame(frame.[[Source]]).
    2. Perform ! CreateDataPropertyOrThrow(obj, "source", sourceFrameObj).
  4. Else,
    1. Assert: Type(frame.[[Source]]) is String.
    2. Perform ! CreateDataPropertyOrThrow(obj, "source", frame.[[Source]]).
  5. If frame.[[Span]] is not empty, then
    1. Let spanObj be ! FromStackFrameSpan(frame.[[Span]]).
    2. Perform ! CreateDataPropertyOrThrow(obj, "span", spanObj).
  6. Return obj.
- -

5GetStackFrameSpanString( span )

-

When the abstract operation GetStackFrameSpanString is called with argument span, the following steps are performed:

- -
    -
  1. Assert: !  - IsStackFrameSpan(span) is - true.
  2. -
  3. Let spanString be !  - GetStackFramePositionString(span.[[StartPosition]]).
  4. -
  5. If span has an [[EndPosition]] internal slot, -
      -
    1. Let spanString be the concatenation of spanString, - "::", and !  - GetStackFramePositionString(span.[[EndPosition]]).
    2. -
    -
  6. -
  7. Return spanString. -
  8. -
-
+ +

2.2.2 GetStackFrameString ( frame )

+

The abstract operation GetStackFrameString takes argument frame (a Stack Frame Record). It performs the following steps when called:

+
  1. If frame.[[Source]] is a Stack Frame Record, then
    1. Let sourceFrameString be ! GetStackFrameString(frame.[[Source]]).
    2. Let sourceString be the string-concatenation of "eval" and sourceFrameString.
  2. Else,
    1. Assert: Type(frame.[[Source]]) is String.
    2. Let sourceString be frame.[[Source]].
  3. Let spanString be the empty string.
  4. If source.[[Span]] is not empty, set spanString to ! GetStackFrameSpanString(source.[[Span]]).
  5. Let frameString be the string-concatenation of the code unit 0x0020 (SPACE), "at", and the code unit 0x0020 (SPACE).
  6. If frame.[[Name]] is not the empty string, set frameString to the string-concatenation of frameString, frame.[[Name]], and the code unit 0x0020 (SPACE).
  7. Return the string-concatenation of frameString, "(", sourceString, spanString, and ")".
- -

6GetStackFramePositionString( position )

-

When the abstract operation GetStackFramePositionString is called with argument position, the following steps are performed:

- -
    -
  1. Assert: !  - IsStackFramePosition(position) is - true.
  2. -
  3. Let positionString be !  - ToString(position.[[Line]]).
  4. -
  5. If position has a [[Column]] internal slot, -
      -
    1. Let positionString be the concatenation of positionString, - ":", and !  - ToString(position.[[Column]]).
    2. -
    -
  6. -
  7. Return positionString. -
  8. -
-
-
- - -

7GetStackFrames( error )

-

When the abstract operation GetStackFrames is called with argument error, the following steps are performed:

- -
    -
  1. Assert: error has an [[ErrorData]] internal slot.
  2. -
  3. Let frames be a new empty - List.
  4. -
  5. Repeat, for each Stack Frame frame in error.[[ErrorData]], -
      -
    1. Append !  - FromStackFrame(frame) to frames.
    2. -
    -
  6. -
  7. Let array be !  - CreateArrayFromList(frames).
  8. -
  9. Let status be !  - SetIntegrityLevel(array, - "frozen").
  10. -
  11. Assert: status is - true.
  12. -
  13. Return array. -
  14. -
-
-
- - -

8The Stack Frame Specification Type

- - -

8.1IsStackFrame ( frame )

-

When the abstract operation IsStackFrame is called with Stack Frame frame, the following steps are performed:

- -
    -
  1. If !  - Type(frame) is not Object, return - false.
  2. -
  3. If frame does not have a [[Name]] internal slot, return - false.
  4. -
  5. If frame does not have a [[Source]] internal slot, return - false.
  6. -
  7. If frame does not have a [[Span]] internal slot, return - false.
  8. -
  9. If !  - Type(frame.[[Name]]) is not String, return - false.
  10. -
  11. If !  - Type(frame.[[Source]]) is not String, and !  - IsStackFrame(frame.[[Source]]) is not - true, return - false.
  12. -
  13. If !  - IsStackFrameSpan(frame.[[Span]]) is not - true, return - false.
  14. -
  15. Return - true. -
  16. -
-
-
- - -

8.2IsStackFrameSpan ( span )

-

When the abstract operation IsStackFrameSpan is called with argument span, the following steps are performed:

- -
    -
  1. If !  - Type(span) is not Object, return - false.
  2. -
  3. If span does not have a [[StartPosition]] internal slot, return - false.
  4. -
  5. If !  - IsStackFramePosition(span.[[StartPosition]]) is not - true, return - false.
  6. -
  7. If span has an [[EndPosition]] internal slot, -
      -
    1. If !  - IsStackFramePosition(span.[[EndPosition]]) is not - true, return - false.
    2. -
    -
  8. -
  9. Return - true. -
  10. -
-
-
+ +

2.2.3 Stack Frame Span Records

+

A Stack Frame Span Record is a Record value used to store location information of a Stack Frame Record.

+

Stack Frame Span Records have the fields listed in Table 3

+
Table 3: Stack Frame Span Record Fields
+ + + + + + + + + + + + + + + +
Field NameValue
[[StartPosition]]Stack Frame Position Record
[[EndPosition]]Stack Frame Position Record | empty
+
- -

8.3IsStackFramePosition ( position )

-

When the abstract operation IsStackFramePosition is called with argument position, the following steps are performed:

- -
    -
  1. If !  - Type(position) is not Object, return - false.
  2. -
  3. If position does not have a [[Line]] internal slot, return - false.
  4. -
  5. If position.[[Line]] is not a positive integer ≤ 253-1, return - false.
  6. -
  7. If position has a [[Column]] internal slot, -
      -
    1. If position.[[Column]] is not - +0 or a positive integer ≤ 253-1, return - false.
    2. -
    -
  8. -
  9. Return - true. -
  10. -
-
+ +

2.2.3.1 FromStackFrameSpan ( span )

+

The abstract operation FromStackFrameSpan takes argument span (a Stack Frame Span Record). It performs the following steps when called:

+
  1. Let list be a new empty List.
  2. Append ! FromStackFramePosition(span.[[StartPosition]]) to list.
  3. If span.[[EndPosition]] is not empty, append ! FromStackFramePosition(span.[[EndPosition]]) to list.
  4. Return ! CreateArrayFromList(list).
- -

8.4FromStackFrame ( frame )

-

When the abstract operation FromStackFrame is called with Stack Frame frame, the following steps are taken:

- -
    -
  1. Assert: !  - IsStackFrame(frame) is - true.
  2. -
  3. Let obj be !  - ObjectCreate( - %ObjectPrototype%).
  4. -
  5. Assert: obj is an extensible ordinary object with no own properties.
  6. -
  7. Perform !  - CreateDataProperty(obj, - "name", frame.[[Name]]).
  8. -
  9. Let source be frame.[[Source]].
  10. -
  11. If !  - Type(source) is String, -
      -
    1. Perform !  - CreateDataProperty(obj, - "source", source).
    2. -
    -
  12. -
  13. Else, -
      -
    1. Assert: !  - IsStackFrame(source) is - true.
    2. -
    3. Perform !  - CreateDataProperty(obj, - "source", !  - FromStackFrame(source)).
    4. -
    -
  14. -
  15. Perform !  - CreateDataProperty(obj, - "span", !  - FromStackFrameSpan(frame.[[Span]])).
  16. -
  17. Assert: All of the above - CreateDataProperty operations return - true.
  18. -
  19. Let status be !  - SetIntegrityLevel(obj, - "frozen").
  20. -
  21. Assert: status is - true.
  22. -
  23. Return obj. -
  24. -
-
+ +

2.2.3.2 GetStackFrameSpanString( span )

+

The abstract operation GetStackFrameSpanString takes argument span (a Stack Frame Span Record). It performs the following steps when called:

+
  1. Let startPositionString be ! GetStackFramePositionString(span.[[StartPosition]]).
  2. If span.[[EndPosition]] is not empty, then
    1. Let endPositionString be ! GetStackFramePositionString(span.[[EndPosition]]).
    2. Return the string-concatenation of startPositionString, "::", and endPositionString.
  3. Return startPositionString.
- -

8.5FromStackFrameSpan ( span )

-

When the abstract operation FromStackFrameSpan is called with argument span, the following steps are taken:

- -
    -
  1. Assert: !  - IsStackFrameSpan(span) is - true.
  2. -
  3. Let list be a new empty - List.
  4. -
  5. Append !  - FromStackFramePosition(span.[[StartPosition]]) to list.
  6. -
  7. If span has an [[EndPosition]] internal slot, append !  - FromStackFramePosition(span.[[EndPosition]]) to list.
  8. -
  9. Let array be !  - CreateArrayFromList(list).
  10. -
  11. Let status be !  - SetIntegrityLevel(array, - "frozen").
  12. -
  13. Assert: status is - true.
  14. -
  15. Return array. -
  16. -
-
-
- - -

8.6FromStackFramePosition ( position )

-

When the abstract operation FromStackFramePosition is called with argument position, the following steps are taken:

- -
    -
  1. Assert: !  - IsStackFramePosition(position) is - true.
  2. -
  3. Let list be a new empty - List.
  4. -
  5. Append position.[[Line]] to list.
  6. -
  7. If position has a [[Column]] internal slot, append position.[[Column]] to list.
  8. -
  9. Let array be !  - CreateArrayFromList(list).
  10. -
  11. Let status be !  - SetIntegrityLevel(array, - "frozen").
  12. -
  13. Assert: status is - true.
  14. -
  15. Return array. -
  16. -
-
+ +

2.2.3.3 Stack Frame Position Records

+

A Stack Frame Position Record is a Record value used to store position information of a Stack Frame Span Record.

+

Stack Frame Position Records have the fields listed in Table 4

+
Table 4: Stack Frame Position Record Fields
+ + + + + + + + + + + + + + + +
Field NameValue
[[Line]]A positive integer
[[Column]]A non-negative integer | empty
+
+ + +

2.2.3.3.1 FromStackFramePosition ( position )

+

The abstract operation FromStackFramePosition takes argument position (a Stack Frame Position Record). It performs the following steps when called:

+
  1. Let list be a new empty List.
  2. Append position.[[Line]] to list.
  3. If position.[[Column]] is not empty, append position.[[Column]] to list.
  4. Return ! CreateArrayFromList(list).
+
+ + +

2.2.3.3.2 GetStackFramePositionString( position )

+

The abstract operation GetStackFramePositionString takes argument position (a Stack Frame Position Record). It performs the following steps when called:

+
  1. Let lineString be ! ToString(𝔽(position.[[Line]])).
  2. If position.[[Column]] is not empty, then
    1. Let columnString be ! ToString(𝔽(position.[[Column]])).
    2. Return the string-concatenation of positionString, ":", and columnString.
  3. Return lineString.
+
+
+
- -

APlaceholder to ensure correct annex lettering

-
- - -

BAdditional Built-in Properties

-

When the ECMAScript host is a web browser the following additional properties of the standard built-in objects are defined.

+ +

A Placeholder to ensure correct annex lettering

+
- -

B.1Additional Properties of the Error.prototype Object

+ +

B Additional Built-in Properties

+

When the ECMAScript host is a web browser the following additional properties of the standard built-in objects are defined.

- -

B.1.1get Error.prototype.stack ( )

-

- Error.prototype.stack is an accessor property whose get accessor function performs the following steps:

- -
    -
  1. Let E be the - this value.
  2. -
  3. If !  - Type(E) is not Object, throw a - TypeError exception.
  4. -
  5. If E does not have an [[ErrorData]] internal slot, return - undefined.
  6. -
  7. Return ?  - GetStackString(error). -
  8. -
-
-

The value of the - "name" property of this function is - "get stack".

-
+ +

B.1 Additional Properties of the Error.prototype Object

- -

B.1.2set Error.prototype.stack ( value )

-

Its set accessor function performs the following steps:

- -
    -
  1. Let E be the - this value.
  2. -
  3. If !  - Type(E) is not Object, throw a - TypeError exception.
  4. -
  5. Let numberOfArgs be the number of arguments passed to this function call.
  6. -
  7. If numberOfArgs is - 0, throw a - TypeError exception.
  8. -
  9. Return ?  - CreateDataPropertyOrThrow(E, - "stack", value); -
  10. -
-
-

The value of the - "name" property of this function is - "set stack".

-
-
+ +

B.1.1 get Error.prototype.stack ( )

+

Error.prototype.stack is an accessor property whose get accessor function performs the following steps:

+
  1. Let E be the this value.
  2. If ! Type(E) is not Object, throw a TypeError exception.
  3. If E does not have an [[ErrorData]] internal slot, return undefined.
  4. Return ? GetStackString(error).
+

The value of the "name" property of this function is "get stack".

- -

CCopyright & Software License

-

Copyright Notice

-

© 2017 Jordan Harband, Mark Miller

+ +

B.1.2 set Error.prototype.stack ( value )

+

Its set accessor function performs the following steps:

+
  1. Let E be the this value.
  2. If ! Type(E) is not Object, throw a TypeError exception.
  3. Let numberOfArgs be the number of arguments passed to this function call.
  4. If numberOfArgs is 0, throw a TypeError exception.
  5. Return ? CreateDataPropertyOrThrow(E, "stack", value);
+

The value of the "name" property of this function is "set stack".

+
+
+
+

C Copyright & Software License

+ +

Copyright Notice

+

© 2021 Jordan Harband, Mark Miller

-

Software License

-

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

+

Software License

+

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

-

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

+

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

-
    -
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. -
  3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  4. -
  5. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.
  6. -
+
    +
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. +
  3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  4. +
  5. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.
  6. +
-

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-
-
- \ No newline at end of file + +
\ No newline at end of file diff --git a/package.json b/package.json index 449ea14..e53d497 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "description": "ECMAScript spec proposal for Error Stacks", "scripts": { - "build": "ecmarkup spec.emu --js=spec.js --css=spec.css | js-beautify -f - --type=html -t > index.html", + "build": "ecmarkup spec.emu index.html --js-out=spec.js --css-out=spec.css", "prepublish": "not-in-publish && npm run build || (echo >&2 'no publishing' && exit 255)" }, "repository": { @@ -32,7 +32,6 @@ "in-publish": "^2.0.0" }, "devDependencies": { - "ecmarkup": "^3.12.0", - "js-beautify": "^1.7.4" + "ecmarkup": "^6.1.0" } } diff --git a/spec.css b/spec.css index f313f8a..36ffb82 100644 --- a/spec.css +++ b/spec.css @@ -21,8 +21,8 @@ body.oldtoc { } a { - text-decoration: none; - color: #206ca7; + text-decoration: none; + color: #206ca7; } a:visited { @@ -30,15 +30,14 @@ a:visited { } a:hover { - text-decoration: underline; - color: #239dee; + text-decoration: underline; + color: #239dee; } - code { - font-weight: bold; - font-family: Consolas, Monaco, monospace; - white-space: pre; + font-weight: bold; + font-family: Consolas, Monaco, monospace; + white-space: pre; } pre code { @@ -52,13 +51,13 @@ pre code.hljs { } ol.toc { - list-style: none; - padding-left: 0; + list-style: none; + padding-left: 0; } ol.toc ol.toc { - padding-left: 2ex; - list-style: none; + padding-left: 2ex; + list-style: none; } var { @@ -78,16 +77,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 { @@ -105,29 +131,30 @@ emu-eqn div:first-child { } emu-note { - margin: 1em 0; - color: #666; - border-left: 5px solid #ccc; - display: flex; - flex-direction: row; + margin: 1em 0; + color: #666; + border-left: 5px solid #ccc; + display: flex; + flex-direction: row; } emu-note > span.note { - flex-basis: 100px; - min-width: 100px; - flex-grow: 0; - flex-shrink: 1; - text-transform: uppercase; - padding-left: 5px; + flex-basis: 100px; + min-width: 100px; + flex-grow: 0; + flex-shrink: 1; + text-transform: uppercase; + padding-left: 5px; } -emu-note[type=editor] { +emu-note[type='editor'] { border-left-color: #faa; } emu-note > div.note-contents { flex-grow: 1; flex-shrink: 1; + overflow: auto; } emu-note > div.note-contents > p:first-of-type { @@ -138,6 +165,10 @@ emu-note > div.note-contents > p:last-of-type { margin-bottom: 0; } +emu-table td code { + white-space: normal; +} + emu-figure { display: block; } @@ -161,98 +192,120 @@ emu-table figure { } emu-production { - display: block; - margin-top: 1em; - margin-bottom: 1em; - margin-left: 5ex; + display: block; } -emu-grammar.inline, emu-production.inline, -emu-grammar.inline emu-production emu-rhs, emu-production.inline emu-rhs, -emu-grammar[collapsed] emu-production emu-rhs, emu-production[collapsed] emu-rhs { - display: inline; - padding-left: 1ex; - margin-left: 0; +emu-grammar[type='example'] emu-production, +emu-grammar[type='definition'] emu-production { + margin-top: 1em; + margin-bottom: 1em; + margin-left: 5ex; } -emu-grammar[collapsed] emu-production, emu-production[collapsed] { - margin: 0; +emu-grammar.inline, +emu-production.inline, +emu-grammar.inline emu-production emu-rhs, +emu-production.inline emu-rhs, +emu-grammar[collapsed] emu-production emu-rhs { + display: inline; + padding-left: 1ex; + margin-left: 0; +} + +emu-production[collapsed] emu-rhs { + display: inline; + padding-left: 0.5ex; + margin-left: 0; +} + +emu-grammar[collapsed] emu-production, +emu-production[collapsed] { + margin: 0; } emu-constraints { - font-size: .75em; - margin-right: 1ex; + font-size: 0.75em; + margin-right: 0.5ex; } emu-gann { - margin-right: 1ex; + margin-right: 0.5ex; } emu-gann emu-t:last-child, +emu-gann emu-gprose:last-child, emu-gann emu-nt:last-child { - margin-right: 0; + margin-right: 0; } emu-geq { - margin-left: 1ex; - font-weight: bold; + margin-left: 0.5ex; + font-weight: bold; } emu-oneof { - font-weight: bold; - margin-left: 1ex; + font-weight: bold; + margin-left: 0.5ex; } emu-nt { - display: inline-block; - font-style: italic; - white-space: nowrap; - text-indent: 0; + display: inline-block; + font-style: italic; + white-space: nowrap; + text-indent: 0; } -emu-nt a, emu-nt a:visited { +emu-nt a, +emu-nt a:visited { color: #333; } emu-rhs emu-nt { - margin-right: 1ex; + margin-right: 0.5ex; } emu-t { - display: inline-block; - font-family: monospace; - font-weight: bold; - white-space: nowrap; - text-indent: 0; + display: inline-block; + font-family: monospace; + font-weight: bold; + white-space: nowrap; + text-indent: 0; } emu-production emu-t { - margin-right: 1ex; + margin-right: 0.5ex; } emu-rhs { - display: block; - padding-left: 75px; - text-indent: -25px; + display: block; + padding-left: 75px; + text-indent: -25px; } -emu-mods { - font-size: .85em; - vertical-align: sub; - font-style: normal; - font-weight: normal; +emu-production:not([collapsed]) emu-rhs { + border: 0.2ex dashed transparent; } -emu-production[collapsed] emu-mods { - display: none; +emu-production:not([collapsed]) emu-rhs:hover { + border-color: #888; + background-color: #f0f0f0; } -emu-params, emu-opt { +emu-mods { + font-size: 0.85em; + vertical-align: sub; + font-style: normal; + font-weight: normal; +} + +emu-params, +emu-opt { margin-right: 1ex; font-family: monospace; } -emu-params, emu-constraints { +emu-params, +emu-constraints { color: #2aa198; } @@ -261,8 +314,12 @@ emu-opt { } emu-gprose { - font-size: 0.9em; - font-family: Helvetica, Arial, sans-serif; + font-size: 0.9em; + font-family: Helvetica, Arial, sans-serif; +} + +emu-production emu-gprose { + margin-right: 1ex; } h1.shortname { @@ -286,154 +343,267 @@ h1.first { margin-top: 0; } -h1, h2, h3, h4, h5, h6 { - position: relative; +h1, +h2, +h3, +h4, +h5, +h6 { + position: relative; } h1 .secnum { text-decoration: none; - margin-right: 10px; + margin-right: 5px; } h1 span.title { order: 2; } +h1 { + font-size: 2.67em; + margin-bottom: 0; + line-height: 1em; +} +h2 { + font-size: 2em; +} +h3 { + font-size: 1.56em; +} +h4 { + font-size: 1.25em; +} +h5 { + font-size: 1.11em; +} +h6 { + font-size: 1em; +} -h1 { font-size: 2.67em; margin-top: 2em; margin-bottom: 0; line-height: 1em;} -h2 { font-size: 2em; } -h3 { font-size: 1.56em; } -h4 { font-size: 1.25em; } -h5 { font-size: 1.11em; } -h6 { font-size: 1em; } +emu-intro h1, +emu-clause h1, +emu-annex h1 { + font-size: 2em; +} +emu-intro h2, +emu-clause h2, +emu-annex h2 { + font-size: 1.56em; +} +emu-intro h3, +emu-clause h3, +emu-annex h3 { + font-size: 1.25em; +} +emu-intro h4, +emu-clause h4, +emu-annex h4 { + font-size: 1.11em; +} +emu-intro h5, +emu-clause h5, +emu-annex h5 { + font-size: 1em; +} +emu-intro h6, +emu-clause h6, +emu-annex h6 { + font-size: 0.9em; +} +emu-intro emu-intro h1, +emu-clause emu-clause h1, +emu-annex emu-annex h1 { + font-size: 1.56em; +} +emu-intro emu-intro h2, +emu-clause emu-clause h2, +emu-annex emu-annex h2 { + font-size: 1.25em; +} +emu-intro emu-intro h3, +emu-clause emu-clause h3, +emu-annex emu-annex h3 { + font-size: 1.11em; +} +emu-intro emu-intro h4, +emu-clause emu-clause h4, +emu-annex emu-annex h4 { + font-size: 1em; +} +emu-intro emu-intro h5, +emu-clause emu-clause h5, +emu-annex emu-annex h5 { + font-size: 0.9em; +} +emu-intro emu-intro emu-intro h1, +emu-clause emu-clause emu-clause h1, +emu-annex emu-annex emu-annex h1 { + font-size: 1.25em; +} +emu-intro emu-intro emu-intro h2, +emu-clause emu-clause emu-clause h2, +emu-annex emu-annex emu-annex h2 { + font-size: 1.11em; +} +emu-intro emu-intro emu-intro h3, +emu-clause emu-clause emu-clause h3, +emu-annex emu-annex emu-annex h3 { + font-size: 1em; +} +emu-intro emu-intro emu-intro h4, +emu-clause emu-clause emu-clause h4, +emu-annex emu-annex emu-annex h4 { + font-size: 0.9em; +} +emu-intro emu-intro emu-intro emu-intro h1, +emu-clause emu-clause emu-clause emu-clause h1, +emu-annex emu-annex emu-annex emu-annex h1 { + font-size: 1.11em; +} +emu-intro emu-intro emu-intro emu-intro h2, +emu-clause emu-clause emu-clause emu-clause h2, +emu-annex emu-annex emu-annex emu-annex h2 { + font-size: 1em; +} +emu-intro emu-intro emu-intro emu-intro h3, +emu-clause emu-clause emu-clause emu-clause h3, +emu-annex emu-annex emu-annex emu-annex h3 { + font-size: 0.9em; +} +emu-intro emu-intro emu-intro emu-intro emu-intro h1, +emu-clause emu-clause emu-clause emu-clause emu-clause h1, +emu-annex emu-annex emu-annex emu-annex emu-annex h1 { + font-size: 1em; +} +emu-intro emu-intro emu-intro emu-intro emu-intro h2, +emu-clause emu-clause emu-clause emu-clause emu-clause h2, +emu-annex emu-annex emu-annex emu-annex emu-annex h2 { + font-size: 0.9em; +} +emu-intro emu-intro emu-intro emu-intro emu-intro emu-intro h1, +emu-clause emu-clause emu-clause emu-clause emu-clause emu-clause h1, +emu-annex emu-annex emu-annex emu-annex emu-annex emu-annex h1 { + font-size: 0.9em; +} -h1:hover span.utils { +emu-clause, +emu-intro, +emu-annex { display: block; } -span.utils { - font-size: 18px; - line-height: 18px; - display: none; - position: absolute; - top: 100%; - left: 0; - right: 0; - font-weight: normal; +/* these values are twice the font-size for the

titles for clauses */ +emu-intro, +emu-clause, +emu-annex { + margin-top: 4em; } - -span.utils:before { - content: "⤷"; - display: inline-block; - padding: 0 5px; +emu-intro emu-intro, +emu-clause emu-clause, +emu-annex emu-annex { + margin-top: 3.12em; } - -span.utils > * { - display: inline-block; - margin-right: 20px; +emu-intro emu-intro emu-intro, +emu-clause emu-clause emu-clause, +emu-annex emu-annex emu-annex { + margin-top: 2.5em; } - -h1 span.utils span.anchor a, -h2 span.utils span.anchor a, -h3 span.utils span.anchor a, -h4 span.utils span.anchor a, -h5 span.utils span.anchor a, -h6 span.utils span.anchor a { - text-decoration: none; - font-variant: small-caps; +emu-intro emu-intro emu-intro emu-intro, +emu-clause emu-clause emu-clause emu-clause, +emu-annex emu-annex emu-annex emu-annex { + margin-top: 2.22em; } - -h1 span.utils span.anchor a:hover, -h2 span.utils span.anchor a:hover, -h3 span.utils span.anchor a:hover, -h4 span.utils span.anchor a:hover, -h5 span.utils span.anchor a:hover, -h6 span.utils span.anchor a:hover { - color: #333; +emu-intro emu-intro emu-intro emu-intro emu-intro, +emu-clause emu-clause emu-clause emu-clause emu-clause, +emu-annex emu-annex emu-annex emu-annex emu-annex { + margin-top: 2em; } - -emu-intro h1, emu-clause h1, emu-annex h1 { font-size: 2em; } -emu-intro h2, emu-clause h2, emu-annex h2 { font-size: 1.56em; } -emu-intro h3, emu-clause h3, emu-annex h3 { font-size: 1.25em; } -emu-intro h4, emu-clause h4, emu-annex h4 { font-size: 1.11em; } -emu-intro h5, emu-clause h5, emu-annex h5 { font-size: 1em; } -emu-intro h6, emu-clause h6, emu-annex h6 { font-size: 0.9em; } -emu-intro emu-intro h1, emu-clause emu-clause h1, emu-annex emu-annex h1 { font-size: 1.56em; } -emu-intro emu-intro h2, emu-clause emu-clause h2, emu-annex emu-annex h2 { font-size: 1.25em; } -emu-intro emu-intro h3, emu-clause emu-clause h3, emu-annex emu-annex h3 { font-size: 1.11em; } -emu-intro emu-intro h4, emu-clause emu-clause h4, emu-annex emu-annex h4 { font-size: 1em; } -emu-intro emu-intro h5, emu-clause emu-clause h5, emu-annex emu-annex h5 { font-size: 0.9em; } -emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex h1 { font-size: 1.25em; } -emu-intro emu-intro emu-intro h2, emu-clause emu-clause emu-clause h2, emu-annex emu-annex emu-annex h2 { font-size: 1.11em; } -emu-intro emu-intro emu-intro h3, emu-clause emu-clause emu-clause h3, emu-annex emu-annex emu-annex h3 { font-size: 1em; } -emu-intro emu-intro emu-intro h4, emu-clause emu-clause emu-clause h4, emu-annex emu-annex emu-annex h4 { font-size: 0.9em; } -emu-intro emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex emu-annex h1 { font-size: 1.11em; } -emu-intro emu-intro emu-intro emu-intro h2, emu-clause emu-clause emu-clause emu-clause h2, emu-annex emu-annex emu-annex emu-annex h2 { font-size: 1em; } -emu-intro emu-intro emu-intro emu-intro h3, emu-clause emu-clause emu-clause emu-clause h3, emu-annex emu-annex emu-annex emu-annex h3 { font-size: 0.9em; } -emu-intro emu-intro emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex emu-annex emu-annex h1 { font-size: 1em; } -emu-intro emu-intro emu-intro emu-intro emu-intro h2, emu-clause emu-clause emu-clause emu-clause emu-clause h2, emu-annex emu-annex emu-annex emu-annex emu-annex h2 { font-size: 0.9em; } -emu-intro emu-intro emu-intro emu-intro emu-intro emu-intro h1, emu-clause emu-clause emu-clause emu-clause emu-clause emu-clause h1, emu-annex emu-annex emu-annex emu-annex emu-annex emu-annex h1 { font-size: 0.9em } - -emu-clause, emu-intro, emu-annex { - display: block; +emu-intro emu-intro emu-intro emu-intro emu-intro emu-intro, +emu-clause emu-clause emu-clause emu-clause emu-clause emu-clause, +emu-annex emu-annex emu-annex emu-annex emu-annex emu-annex { + margin-top: 1.8em; } /* Figures and tables */ -figure { display: block; margin: 1em 0 3em 0; } -figure object { display: block; margin: 0 auto; } -figure table.real-table { margin: 0 auto; } +figure { + display: block; + margin: 1em 0 3em 0; +} +figure object { + display: block; + margin: 0 auto; +} +figure table.real-table { + margin: 0 auto; +} figure figcaption { - display: block; - color: #555555; - font-weight: bold; - text-align: center; + display: block; + color: #555555; + font-weight: bold; + text-align: center; } emu-table table { margin: 0 auto; } -emu-table table, table.real-table { - border-collapse: collapse; +emu-table table, +table.real-table { + border-collapse: collapse; } -emu-table td, emu-table th, table.real-table td, table.real-table th { - border: 1px solid black; - padding: 0.4em; - vertical-align: baseline; +emu-table td, +emu-table th, +table.real-table td, +table.real-table th { + border: 1px solid black; + padding: 0.4em; + vertical-align: baseline; } -emu-table th, emu-table thead td, table.real-table th { - background-color: #eeeeee; +emu-table th, +emu-table thead td, +table.real-table th { + background-color: #eeeeee; } /* Note: the left content edges of table.lightweight-table >tbody >tr >td and div.display line up. */ table.lightweight-table { - border-collapse: collapse; - margin: 0 0 0 1.5em; + border-collapse: collapse; + margin: 0 0 0 1.5em; } -table.lightweight-table td, table.lightweight-table th { - border: none; - padding: 0 0.5em; - vertical-align: baseline; +table.lightweight-table td, +table.lightweight-table th { + border: none; + padding: 0 0.5em; + vertical-align: baseline; } /* diff styles */ ins { - background-color: #e0f8e0; - text-decoration: none; - border-bottom: 1px solid #396; + background-color: #e0f8e0; + text-decoration: none; + border-bottom: 1px solid #396; } del { - background-color: #fee; + background-color: #fee; } -ins.block, del.block, -emu-production > ins, emu-production > del, -emu-grammar > ins, emu-grammar > del { +ins.block, +del.block, +emu-production > ins, +emu-production > del, +emu-grammar > ins, +emu-grammar > del { display: block; } +emu-rhs > ins, +emu-rhs > del { + display: inline; +} tr.ins > td > ins { border-bottom: none; @@ -468,7 +638,7 @@ tr.del > td { -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; - user-select: none;; + user-select: none; cursor: pointer; } @@ -476,7 +646,8 @@ tr.del > td { #menu { display: flex; flex-direction: column; - width: 33%; height: 100vh; + width: 33%; + height: 100vh; max-width: 500px; box-sizing: border-box; background-color: #ddd; @@ -484,7 +655,8 @@ tr.del > td { transition: opacity 0.1s linear; padding: 0 5px; position: fixed; - left: 0; top: 0; + left: 0; + top: 0; border-right: 2px solid #bbb; z-index: 2; @@ -545,7 +717,8 @@ tr.del > td { padding: 0; } -#menu-toc > ol , #menu-toc > ol ol { +#menu-toc > ol, +#menu-toc > ol ol { list-style-type: none; margin: 0; padding: 0; @@ -575,7 +748,7 @@ tr.del > td { -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; - user-select: none;; + user-select: none; cursor: pointer; } @@ -606,7 +779,7 @@ tr.del > td { */ } -#menu-toc li.revealed-leaf> a { +#menu-toc li.revealed-leaf > a { color: #206ca7; /* background-color: #222; @@ -642,6 +815,34 @@ tr.del > td { font-size: 0.8em; } +.menu-pane-header emu-opt, +.menu-pane-header emu-t, +.menu-pane-header emu-nt { + margin-right: 0px; + display: inline; + color: inherit; +} + +.menu-pane-header emu-rhs { + display: inline; + padding-left: 0px; + text-indent: 0px; +} + +.menu-pane-header emu-geq { + margin-left: 0px; +} + +a.menu-pane-header-production { + color: inherit; +} + +.menu-pane-header-production { + text-transform: none; + letter-spacing: 1.5px; + padding-left: 0.5em; +} + #menu-toc { display: flex; flex-direction: column; @@ -660,10 +861,10 @@ tr.del > td { flex-grow: 0; flex-shrink: 0; width: 100%; - + display: flex; flex-direction: column; - + max-height: 300px; } @@ -688,43 +889,42 @@ tr.del > td { } li.menu-search-result-clause:before { - content: 'clause'; - width: 40px; - display: inline-block; - text-align: right; - padding-right: 1ex; - color: #666; - font-size: 75%; + content: 'clause'; + width: 40px; + display: inline-block; + text-align: right; + padding-right: 1ex; + color: #666; + font-size: 75%; } li.menu-search-result-op:before { - content: 'op'; - width: 40px; - display: inline-block; - text-align: right; - padding-right: 1ex; - color: #666; - font-size: 75%; + content: 'op'; + width: 40px; + display: inline-block; + text-align: right; + padding-right: 1ex; + color: #666; + font-size: 75%; } li.menu-search-result-prod:before { - content: 'prod'; - width: 40px; - display: inline-block; - text-align: right; - padding-right: 1ex; - color: #666; - font-size: 75% + content: 'prod'; + width: 40px; + display: inline-block; + text-align: right; + padding-right: 1ex; + color: #666; + font-size: 75%; } - li.menu-search-result-term:before { - content: 'term'; - width: 40px; - display: inline-block; - text-align: right; - padding-right: 1ex; - color: #666; - font-size: 75% + content: 'term'; + width: 40px; + display: inline-block; + text-align: right; + padding-right: 1ex; + color: #666; + font-size: 75%; } #menu-search-results ul { @@ -737,7 +937,6 @@ li.menu-search-result-term:before { text-overflow: ellipsis; } - #menu-trace-list { counter-reset: item; margin: 0 0 0 20px; @@ -749,19 +948,19 @@ li.menu-search-result-term:before { } #menu-trace-list li .secnum:after { - content: " "; + content: ' '; } #menu-trace-list li:before { - content: counter(item) " "; - background-color: #222; - counter-increment: item; - color: #999; - width: 20px; - height: 20px; - line-height: 20px; - display: inline-block; - text-align: center; - margin: 2px 4px 2px 0; + content: counter(item) ' '; + background-color: #222; + counter-increment: item; + color: #999; + width: 20px; + height: 20px; + line-height: 20px; + display: inline-block; + text-align: center; + margin: 2px 4px 2px 0; } @media (max-width: 1000px) { @@ -803,26 +1002,31 @@ li.menu-search-result-term:before { } h1 .secnum:empty { - margin: 0; padding: 0; + margin: 0; + padding: 0; } } - /* Toolbox */ -.toolbox { - position: absolute; - background: #ddd; - border: 1px solid #aaa; +.toolbox-container { + position: absolute; display: none; - color: #eee; - padding: 5px; - border-radius: 3px; + padding-bottom: 7px; } -.toolbox.active { +.toolbox-container.active { display: inline-block; } +.toolbox { + position: relative; + background: #ddd; + border: 1px solid #aaa; + color: #eee; + padding: 5px; + border-radius: 3px; +} + .toolbox a { text-decoration: none; padding: 0 5px; @@ -832,28 +1036,29 @@ li.menu-search-result-term:before { text-decoration: underline; } -.toolbox:after, .toolbox:before { - top: 100%; - left: 15px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; +.toolbox:after, +.toolbox:before { + top: 100%; + left: 15px; + border: solid transparent; + content: ' '; + height: 0; + width: 0; + position: absolute; + pointer-events: none; } .toolbox:after { - border-color: rgba(0, 0, 0, 0); - border-top-color: #ddd; - border-width: 10px; - margin-left: -10px; + border-color: rgba(0, 0, 0, 0); + border-top-color: #ddd; + border-width: 10px; + margin-left: -10px; } .toolbox:before { - border-color: rgba(204, 204, 204, 0); - border-top-color: #aaa; - border-width: 12px; - margin-left: -12px; + border-color: rgba(204, 204, 204, 0); + border-top-color: #aaa; + border-width: 12px; + margin-left: -12px; } #references-pane-container { @@ -898,3 +1103,25 @@ li.menu-search-result-term:before { text-align: right; padding-right: 5px; } + +@media print { + #menu-toggle { + display: none; + } +} + +[normative-optional] { + border-left: 5px solid #ff6600; + padding: 0.5em; + display: block; + background: #ffeedd; +} + +.normative-optional-tag { + text-transform: uppercase; + color: #884400; +} + +.normative-optional-tag a { + color: #884400; +} diff --git a/spec.emu b/spec.emu index ee20a19..4f08a3d 100644 --- a/spec.emu +++ b/spec.emu @@ -10,210 +10,237 @@ contributors: Jordan Harband, Mark Miller -

System

+

System

- +

System.getStack ( _error_ )

When the `getStack` method is called with argument _error_, the following steps are taken:

- 1. If _error_ does not have an [[ErrorData]] internal slot, throw a *TypeError* exception. - 1. Return ? GetStack(_error_). + 1. Perform ? RequireInternalSlot(_error_, [[ErrorData]]). + 1. Let _string_ be ? GetStackString(_error_). + 1. Let _frames_ be ! GetStackFramesArray(_error_). + 1. Let _obj_ be ! ObjectCreate(%ObjectPrototype%). + 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"frames"*, _frames_). + 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"string"*, _string_). + 1. Return _obj_. + + +

GetStackFramesArray ( _error_ )

+

The abstract operation GetStackFramesArray takes argument _error_. It performs the following steps when called:

+ + 1. Assert: _error_ is an Object that has an [[ErrorData]] internal slot. + 1. Let _frames_ be a new empty List. + 1. For each Stack Frame Record _frame_ of _error_.[[ErrorData]], append ! FromStackFrame(_frame_) to _frames_. + 1. Return ! CreateArrayFromList(_frames_). + +

System.getStackString ( _error_ )

When the `getStackString` method is called with argument _error_, the following steps are taken:

- 1. If _error_ does not have an [[ErrorData]] internal slot, throw a *TypeError* exception. + 1. Perform ? RequireInternalSlot(_error_, [[ErrorData]]). 1. Return ? GetStackString(_error_). -
-
- -

GetStack ( _error_ )

-

When the abstract operation _GetStack_ is called with argument _error_, the following steps are performed:

- - 1. Assert: _error_ has an [[ErrorData]] internal slot. - 1. Let _frames_ be ! GetStackFrames(_error_). - 1. Let _string_ be ? GetStackString(_error_). - 1. Let _obj_ be ! ObjectCreate(%ObjectPrototype%). - 1. Perform ! CreateDataProperty(_obj_, *"frames"*, _frames_). - 1. Assert: The above CreateDataProperty operation returns *true*. - 1. Perform ! CreateDataProperty(_obj_, *"string"*, _string_). - 1. Assert: The above CreateDataProperty operation returns *true*. - 1. Let _status_ be ! SetIntegrityLevel(_obj_, *"frozen"*). - 1. Assert: _status_ is *true*. - 1. Return _obj_. - -
- - -

GetStackString ( _error_ )

-

When the abstract operation _GetStackString_ is called with argument _error_, the following steps are performed:

- - 1. Assert: _error_ has an [[ErrorData]] internal slot. - 1. Let _errorString_ be ? ToString(_error_). - 1. Let _frames_ be ! GetStackFrames(_error_). - 1. Let _frameString_ be a String consisting solely of the code unit 0x0020 (SPACE). - 1. For each Stack Frame _frame_ in _frames_, - 1. If _frameString_ does not consist solely of the code unit 0x0020 (SPACE), - 1. Let _frameString_ be the concatenation of _frameString_, the code unit 0x000A (LINE FEED), and the code unit 0x0020 (SPACE). - 1. Let _frameString_ be the concatenation of _frameString_ and ! GetFrameString(_frame_). - 1. Let _stackString_ be the concatenation of _errorString_, the code unit 0x000A (LINE FEED), and _frameString_. - 1. Return _stackString_. - + +

GetStackString ( _error_ )

+

The abstract operation GetStackString takes argument _error_. It performs the following steps when called:

+ + 1. Assert: _error_ is an Object that has an [[ErrorData]] internal slot. + 1. Let _stackString_ be ? ToString(_error_). + 1. For each Stack Frame Record _frame_ of _error_.[[ErrorData]], do + 1. Let _frameString_ be ! GetStackFrameString(_frame_). + 1. Set _stackString_ to the string-concatenation of _stackString_, the code unit 0x000A (LINE FEED), the code unit 0x0020 (SPACE), and _frameString_. + 1. Return _stackString_. + +
+
- -

GetFrameString ( _frame_ )

-

When the abstract operation _GetFrameString_ is called with argument _frame_, the following steps are performed:

- - 1. Assert: ! IsStackFrame(_frame_) is *true*. - 1. Let _source_ be _frame_.[[Source]]. - 1. If Type(_source_) is not String, - 1. Assert: ! IsStackFrame(_source_) is *true*. - 1. Let _source_ be the concatenation of *"eval*" and ! GetFrameString(_source_). - 1. Assert: ! Type(_source_) is String. - 1. Let _spanString_ be ! GetStackFrameSpanString(_source_.[[Span]]). - 1. return a String formed by concatenating the code unit 0x0020 (SPACE), *"at"*, the code unit 0x0020 (SPACE), _frame_.[[Name]], the code unit 0x0020 (SPACE), *"("*, _source_, _spanString_, and *")"*. - -
+ +

Error Objects

- -

GetStackFrameSpanString( _span_ )

-

When the abstract operation _GetStackFrameSpanString_ is called with argument _span_, the following steps are performed:

- - 1. Assert: ! IsStackFrameSpan(_span_) is *true*. - 1. Let _spanString_ be ! GetStackFramePositionString(_span_.[[StartPosition]]). - 1. If _span_ has an [[EndPosition]] internal slot, - 1. Let _spanString_ be the concatenation of _spanString_, *"::"*, and ! GetStackFramePositionString(_span_.[[EndPosition]]). - 1. Return _spanString_. - -
+ +

Properties of Error Instances

+

Error instances are ordinary objects that inherit properties from the Error prototype object and have an [[ErrorData]] internal slot whose value is *undefined*. The only specified uses of [[ErrorData]] is to identify Error, AggregateError, and _NativeError_ instances as Error objects within `Object.prototype.toString`(the intrinsic, %Error.prototype%). Error instances are initially created with the internal slots described in .

+ + + + + + + + + + + + + +
Internal SlotDescription
[[ErrorData]]A List of Stack Frame records.
+
+
+
- -

GetStackFramePositionString( _position_ )

-

When the abstract operation _GetStackFramePositionString_ is called with argument _position_, the following steps are performed:

- - 1. Assert: ! IsStackFramePosition(_position_) is *true*. - 1. Let _positionString_ be ! ToString(_position_.[[Line]]). - 1. If _position_ has a [[Column]] internal slot, - 1. Let _positionString_ be the concatenation of _positionString_, *":"*, and ! ToString(_position_.[[Column]]). - 1. Return _positionString_. - -
+ +

Stack Frame Records

+

A Stack Frame Record is a Record value used to store stack information of Error objects.

+

Stack Frame Records have the fields listend in

+ + + + + + + + + + + + + + + + + + + + +
Field NameValue
[[Name]]String
[[Source]]String | Stack Frame Record
[[Span]]Stack Frame Span Record | ~empty~
+
- -

GetStackFrames( _error_ )

-

When the abstract operation _GetStackFrames_ is called with argument _error_, the following steps are performed:

- - 1. Assert: _error_ has an [[ErrorData]] internal slot. - 1. Let _frames_ be a new empty List. - 1. Repeat, for each Stack Frame _frame_ in _error_.[[ErrorData]], - 1. Append ! FromStackFrame(_frame_) to _frames_. - 1. Let _array_ be ! CreateArrayFromList(_frames_). - 1. Let _status_ be ! SetIntegrityLevel(_array_, *"frozen"*). - 1. Assert: _status_ is *true*. - 1. Return _array_. - -
+ +

FromStackFrame ( _frame_ )

+

The abstract operation FromStackFrame takes argument _frame_ (a Stack Frame Record). It performs the following steps when called:

+ + 1. Let _obj_ be ! ObjectCreate(%ObjectPrototype%). + 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"name"*, _frame_.[[Name]]). + 1. If _frame_.[[Source]] is a Stack Frame Record, then + 1. Let _sourceFrameObj_ be ! FromStackFrame(_frame_.[[Source]]). + 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"source"*, _sourceFrameObj_). + 1. Else, + 1. Assert: Type(_frame_.[[Source]]) is String. + 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"source"*, _frame_.[[Source]]). + 1. If _frame_.[[Span]] is not ~empty~, then + 1. Let _spanObj_ be ! FromStackFrameSpan(_frame_.[[Span]]). + 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"span"*, _spanObj_). + 1. Return _obj_. + +
- -

The Stack Frame Specification Type

+ +

GetStackFrameString ( _frame_ )

+

The abstract operation GetStackFrameString takes argument _frame_ (a Stack Frame Record). It performs the following steps when called:

+ + 1. If _frame_.[[Source]] is a Stack Frame Record, then + 1. Let _sourceFrameString_ be ! GetStackFrameString(_frame_.[[Source]]). + 1. Let _sourceString_ be the string-concatenation of *"eval*" and _sourceFrameString_. + 1. Else, + 1. Assert: Type(_frame_.[[Source]]) is String. + 1. Let _sourceString_ be _frame_.[[Source]]. + 1. Let _spanString_ be the empty string. + 1. If _source_.[[Span]] is not ~empty~, set _spanString_ to ! GetStackFrameSpanString(_source_.[[Span]]). + 1. Let _frameString_ be the string-concatenation of the code unit 0x0020 (SPACE), *"at"*, and the code unit 0x0020 (SPACE). + 1. If _frame_.[[Name]] is not the empty string, set _frameString_ to the string-concatenation of _frameString_, frame.[[Name]], and the code unit 0x0020 (SPACE). + 1. Return the string-concatenation of _frameString_, *"("*, _sourceString_, _spanString_, and *")"*. + +
- -

IsStackFrame ( _frame_ )

-

When the abstract operation IsStackFrame is called with Stack Frame _frame_, the following steps are performed:

- - 1. If ! Type(_frame_) is not Object, return *false*. - 1. If _frame_ does not have a [[Name]] internal slot, return *false*. - 1. If _frame_ does not have a [[Source]] internal slot, return *false*. - 1. If _frame_ does not have a [[Span]] internal slot, return *false*. - 1. If ! Type(_frame_.[[Name]]) is not String, return *false*. - 1. If ! Type(_frame_.[[Source]]) is not String, and ! IsStackFrame(_frame_.[[Source]]) is not *true*, return *false*. - 1. If ! IsStackFrameSpan(_frame_.[[Span]]) is not *true*, return *false*. - 1. Return *true*. - -
+ +

Stack Frame Span Records

+

A Stack Frame Span Record is a Record value used to store location information of a Stack Frame Record.

+

Stack Frame Span Records have the fields listed in

+ + + + + + + + + + + + + + + + +
Field NameValue
[[StartPosition]]Stack Frame Position Record
[[EndPosition]]Stack Frame Position Record | ~empty~
+
- -

IsStackFrameSpan ( _span_ )

-

When the abstract operation IsStackFrameSpan is called with argument _span_, the following steps are performed:

- - 1. If ! Type(_span_) is not Object, return *false*. - 1. If _span_ does not have a [[StartPosition]] internal slot, return *false*. - 1. If ! IsStackFramePosition(_span_.[[StartPosition]]) is not *true*, return *false*. - 1. If _span_ has an [[EndPosition]] internal slot, - 1. If ! IsStackFramePosition(_span_.[[EndPosition]]) is not *true*, return *false*. - 1. Return *true*. - -
+ +

FromStackFrameSpan ( _span_ )

+

The abstract operation FromStackFrameSpan takes argument _span_ (a Stack Frame Span Record). It performs the following steps when called:

+ + 1. Let _list_ be a new empty List. + 1. Append ! FromStackFramePosition(_span_.[[StartPosition]]) to _list_. + 1. If _span_.[[EndPosition]] is not empty, append ! FromStackFramePosition(_span_.[[EndPosition]]) to _list_. + 1. Return ! CreateArrayFromList(_list_). + +
- -

IsStackFramePosition ( _position_ )

-

When the abstract operation IsStackFramePosition is called with argument _position_, the following steps are performed:

- - 1. If ! Type(_position_) is not Object, return *false*. - 1. If _position_ does not have a [[Line]] internal slot, return *false*. - 1. If _position_.[[Line]] is not a positive integer ≤ 253-1, return *false*. - 1. If _position_ has a [[Column]] internal slot, - 1. If _position_.[[Column]] is not *+0* or a positive integer ≤ 253-1, return *false*. - 1. Return *true*. - -
+ +

GetStackFrameSpanString( _span_ )

+

The abstract operation GetStackFrameSpanString takes argument _span_ (a Stack Frame Span Record). It performs the following steps when called:

+ + 1. Let _startPositionString_ be ! GetStackFramePositionString(_span_.[[StartPosition]]). + 1. If _span_.[[EndPosition]] is not ~empty~, then + 1. Let _endPositionString_ be ! GetStackFramePositionString(_span_.[[EndPosition]]). + 1. Return the string-concatenation of _startPositionString_, *"::"*, and _endPositionString_. + 1. Return _startPositionString_. + +
- -

FromStackFrame ( _frame_ )

-

When the abstract operation FromStackFrame is called with Stack Frame _frame_, the following steps are taken:

- - 1. Assert: ! IsStackFrame(_frame_) is *true*. - 1. Let _obj_ be ! ObjectCreate(%ObjectPrototype%). - 1. Assert: _obj_ is an extensible ordinary object with no own properties. - 1. Perform ! CreateDataProperty(_obj_, *"name"*, _frame_.[[Name]]). - 1. Let _source_ be _frame_.[[Source]]. - 1. If ! Type(_source_) is String, - 1. Perform ! CreateDataProperty(_obj_, *"source"*, _source_). - 1. Else, - 1. Assert: ! IsStackFrame(_source_) is *true*. - 1. Perform ! CreateDataProperty(_obj_, *"source*", ! FromStackFrame(_source_)). - 1. Perform ! CreateDataProperty(_obj_, *"span"*, ! FromStackFrameSpan(_frame_.[[Span]])). - 1. Assert: All of the above CreateDataProperty operations return *true*. - 1. Let _status_ be ! SetIntegrityLevel(_obj_, *"frozen"*). - 1. Assert: _status_ is *true*. - 1. Return _obj_. - -
+ +

Stack Frame Position Records

+

A Stack Frame Position Record is a Record value used to store position information of a Stack Frame Span Record.

+

Stack Frame Position Records have the fields listed in

+ + + + + + + + + + + + + + + + +
Field NameValue
[[Line]]A positive integer
[[Column]]A non-negative integer | ~empty~
+
- -

FromStackFrameSpan ( _span_ )

-

When the abstract operation FromStackFrameSpan is called with argument _span_, the following steps are taken:

- - 1. Assert: ! IsStackFrameSpan(_span_) is *true*. - 1. Let _list_ be a new empty List. - 1. Append ! FromStackFramePosition(_span_.[[StartPosition]]) to _list_. - 1. If _span_ has an [[EndPosition]] internal slot, append ! FromStackFramePosition(_span_.[[EndPosition]]) to _list_. - 1. Let _array_ be ! CreateArrayFromList(_list_). - 1. Let _status_ be ! SetIntegrityLevel(_array_, *"frozen"*). - 1. Assert: _status_ is *true*. - 1. Return _array_. - -
+ +

FromStackFramePosition ( _position_ )

+

The abstract operation FromStackFramePosition takes argument _position_ (a Stack Frame Position Record). It performs the following steps when called:

+ + 1. Let _list_ be a new empty List. + 1. Append _position_.[[Line]] to _list_. + 1. If _position_.[[Column]] is not ~empty~, append _position_.[[Column]] to _list_. + 1. Return ! CreateArrayFromList(_list_). + +
- -

FromStackFramePosition ( _position_ )

-

When the abstract operation FromStackFramePosition is called with argument _position_, the following steps are taken:

- - 1. Assert: ! IsStackFramePosition(_position_) is *true*. - 1. Let _list_ be a new empty List. - 1. Append _position_.[[Line]] to _list_. - 1. If _position_ has a [[Column]] internal slot, append _position_.[[Column]] to _list_. - 1. Let _array_ be ! CreateArrayFromList(_list_). - 1. Let _status_ be ! SetIntegrityLevel(_array_, *"frozen"*). - 1. Assert: _status_ is *true*. - 1. Return _array_. - + +

GetStackFramePositionString( _position_ )

+

The abstract operation GetStackFramePositionString takes argument _position_ (a Stack Frame Position Record). It performs the following steps when called:

+ + 1. Let _lineString_ be ! ToString(𝔽(_position_.[[Line]])). + 1. If _position_.[[Column]] is not empty, then + 1. Let _columnString_ be ! ToString(𝔽(_position_.[[Column]])). + 1. Return the string-concatenation of _positionString_, *":"*, and _columnString_. + 1. Return _lineString_. + +
+
+
diff --git a/spec.js b/spec.js index 1a02d93..ddf0a33 100644 --- a/spec.js +++ b/spec.js @@ -1,17 +1,122 @@ -"use strict"; +'use strict'; + +var sdoBox = { + init: function () { + this.$alternativeId = null; + this.$outer = document.createElement('div'); + this.$outer.classList.add('toolbox-container'); + this.$container = document.createElement('div'); + this.$container.classList.add('toolbox'); + this.$displayLink = document.createElement('a'); + this.$displayLink.setAttribute('href', '#'); + this.$displayLink.textContent = 'Syntax-Directed Operations'; + this.$displayLink.addEventListener( + 'click', + function (e) { + e.preventDefault(); + e.stopPropagation(); + referencePane.showSDOs(sdoMap[this.$alternativeId] || {}, this.$alternativeId); + }.bind(this) + ); + this.$container.appendChild(this.$displayLink); + this.$outer.appendChild(this.$container); + document.body.appendChild(this.$outer); + }, + + activate: function (el) { + clearTimeout(this.deactiveTimeout); + Toolbox.deactivate(); + this.$alternativeId = el.id; + var numSdos = Object.keys(sdoMap[this.$alternativeId] || {}).length; + this.$displayLink.textContent = 'Syntax-Directed Operations (' + numSdos + ')'; + this.$outer.classList.add('active'); + var top = el.offsetTop - this.$outer.offsetHeight; + var left = el.offsetLeft + 50 - 10; // 50px = padding-left(=75px) + text-indent(=-25px) + this.$outer.setAttribute('style', 'left: ' + left + 'px; top: ' + top + 'px'); + if (top < document.body.scrollTop) { + this.$container.scrollIntoView(); + } + }, + + deactivate: function () { + clearTimeout(this.deactiveTimeout); + this.$outer.classList.remove('active'); + }, +}; + +document.addEventListener('DOMContentLoaded', function () { + sdoBox.init(); + + var insideTooltip = false; + sdoBox.$outer.addEventListener('pointerenter', function () { + insideTooltip = true; + }); + sdoBox.$outer.addEventListener('pointerleave', function () { + insideTooltip = false; + sdoBox.deactivate(); + }); + + sdoBox.deactiveTimeout = null; + [].forEach.call(document.querySelectorAll('emu-grammar[type=definition] emu-rhs'), function ( + node + ) { + node.addEventListener('pointerenter', function () { + sdoBox.activate(this); + }); + + node.addEventListener('pointerleave', function (e) { + sdoBox.deactiveTimeout = setTimeout(function () { + if (!insideTooltip) { + sdoBox.deactivate(); + } + }, 500); + }); + }); + + document.addEventListener( + 'keydown', + debounce(function (e) { + if (e.code === 'Escape') { + sdoBox.deactivate(); + } + }) + ); +}); + +var sdoMap = {}; +document.addEventListener('DOMContentLoaded', function () { + var sdoMapContainer = document.getElementById('sdo-map'); + if (sdoMapContainer == null) { + console.error('could not find SDO map container'); + } else { + sdoMap = JSON.parse(sdoMapContainer.textContent); + } +}); +'use strict'; function Search(menu) { this.menu = menu; this.$search = document.getElementById('menu-search'); this.$searchBox = document.getElementById('menu-search-box'); this.$searchResults = document.getElementById('menu-search-results'); - + this.loadBiblio(); - + document.addEventListener('keydown', this.documentKeydown.bind(this)); - - this.$searchBox.addEventListener('keydown', debounce(this.searchBoxKeydown.bind(this), { stopPropagation: true })); - this.$searchBox.addEventListener('keyup', debounce(this.searchBoxKeyup.bind(this), { stopPropagation: true })); + + this.$searchBox.addEventListener( + 'keydown', + debounce(this.searchBoxKeydown.bind(this), { stopPropagation: true }) + ); + this.$searchBox.addEventListener( + 'keyup', + debounce(this.searchBoxKeyup.bind(this), { stopPropagation: true }) + ); + + // Perform an initial search if the box is not empty. + if (this.$searchBox.value) { + this.search(this.$searchBox.value); + } } Search.prototype.loadBiblio = function () { @@ -20,13 +125,15 @@ Search.prototype.loadBiblio = function () { this.biblio = []; } else { this.biblio = JSON.parse($biblio.textContent); - this.biblio.clauses = this.biblio.filter(function (e) { return e.type === 'clause' }); + this.biblio.clauses = this.biblio.filter(function (e) { + return e.type === 'clause'; + }); this.biblio.byId = this.biblio.reduce(function (map, entry) { map[entry.id] = entry; return map; }, {}); } -} +}; Search.prototype.documentKeydown = function (e) { if (e.keyCode === 191) { @@ -34,7 +141,7 @@ Search.prototype.documentKeydown = function (e) { e.stopPropagation(); this.triggerSearch(); } -} +}; Search.prototype.searchBoxKeydown = function (e) { e.stopPropagation(); @@ -45,16 +152,15 @@ Search.prototype.searchBoxKeydown = function (e) { e.preventDefault(); this.selectResult(); } -} +}; Search.prototype.searchBoxKeyup = function (e) { if (e.keyCode === 13 || e.keyCode === 9) { return; } - - this.search(e.target.value); -} + this.search(e.target.value); +}; Search.prototype.triggerSearch = function (e) { if (this.menu.isVisible()) { @@ -66,7 +172,7 @@ Search.prototype.triggerSearch = function (e) { this.$searchBox.focus(); this.$searchBox.select(); -} +}; // bit 12 - Set if the result starts with searchString // bits 8-11: 8 - number of chunks multiplied by 2 if cases match, otherwise 1. // bits 1-7: 127 - length of the entry @@ -74,25 +180,23 @@ Search.prototype.triggerSearch = function (e) { // prefer shorter matches. function relevance(result, searchString) { var relevance = 0; - + relevance = Math.max(0, 8 - result.match.chunks) << 7; - + if (result.match.caseMatch) { relevance *= 2; } - + if (result.match.prefix) { - relevance += 2048 + relevance += 2048; } - + relevance += Math.max(0, 255 - result.entry.key.length); - + return relevance; } Search.prototype.search = function (searchString) { - var s = Date.now(); - if (searchString === '') { this.displayResults([]); this.hideSearch(); @@ -100,53 +204,60 @@ Search.prototype.search = function (searchString) { } else { this.showSearch(); } - + if (searchString.length === 1) { this.displayResults([]); return; } - + var results; if (/^[\d\.]*$/.test(searchString)) { - results = this.biblio.clauses.filter(function (clause) { - return clause.number.substring(0, searchString.length) === searchString; - }).map(function (clause) { - return { entry: clause }; - }); + results = this.biblio.clauses + .filter(function (clause) { + return clause.number.substring(0, searchString.length) === searchString; + }) + .map(function (clause) { + return { entry: clause }; + }); } else { results = []; - + for (var i = 0; i < this.biblio.length; i++) { var entry = this.biblio[i]; - + if (!entry.key) { + // biblio entries without a key aren't searchable + continue; + } + var match = fuzzysearch(searchString, entry.key); if (match) { results.push({ entry: entry, match: match }); } } - + results.forEach(function (result) { result.relevance = relevance(result, searchString); }); - - results = results.sort(function (a, b) { return b.relevance - a.relevance }); + results = results.sort(function (a, b) { + return b.relevance - a.relevance; + }); } if (results.length > 50) { results = results.slice(0, 50); } - + this.displayResults(results); -} +}; Search.prototype.hideSearch = function () { this.$search.classList.remove('active'); -} +}; Search.prototype.showSearch = function () { this.$search.classList.add('active'); -} +}; Search.prototype.selectResult = function () { var $first = this.$searchResults.querySelector('li:first-child a'); @@ -154,7 +265,7 @@ Search.prototype.selectResult = function () { if ($first) { document.location = $first.getAttribute('href'); } - + this.$searchBox.value = ''; this.$searchBox.blur(); this.displayResults([]); @@ -163,12 +274,12 @@ Search.prototype.selectResult = function () { if (this._closeAfterSearch) { this.menu.hide(); } -} +}; Search.prototype.displayResults = function (results) { if (results.length > 0) { this.$searchResults.classList.remove('no-results'); - + var html = '
    '; results.forEach(function (result) { @@ -185,7 +296,7 @@ Search.prototype.displayResults = function (results) { } else if (entry.type === 'production') { text = entry.key; cssClass = 'prod'; - id = entry.id; + id = entry.id; } else if (entry.type === 'op') { text = entry.key; cssClass = 'op'; @@ -197,19 +308,25 @@ Search.prototype.displayResults = function (results) { } if (text) { - html += '' + html += + ''; } }); - html += '
' + html += ''; this.$searchResults.innerHTML = html; } else { this.$searchResults.innerHTML = ''; this.$searchResults.classList.add('no-results'); } -} - +}; function Menu() { this.$toggle = document.getElementById('menu-toggle'); @@ -220,8 +337,8 @@ function Menu() { this.$toc = document.querySelector('#menu-toc > ol'); this.$specContainer = document.getElementById('spec-container'); this.search = new Search(this); - - this._pinnedIds = {}; + + this._pinnedIds = {}; this.loadPinEntries(); // toggle menu @@ -234,20 +351,26 @@ function Menu() { var tocItems = this.$menu.querySelectorAll('#menu-toc li'); for (var i = 0; i < tocItems.length; i++) { var $item = tocItems[i]; - $item.addEventListener('click', function($item, event) { - $item.classList.toggle('active'); - event.stopPropagation(); - }.bind(null, $item)); + $item.addEventListener( + 'click', + function ($item, event) { + $item.classList.toggle('active'); + event.stopPropagation(); + }.bind(null, $item) + ); } // close toc on toc item selection var tocLinks = this.$menu.querySelectorAll('#menu-toc li > a'); for (var i = 0; i < tocLinks.length; i++) { var $link = tocLinks[i]; - $link.addEventListener('click', function(event) { - this.toggle(); - event.stopPropagation(); - }.bind(this)); + $link.addEventListener( + 'click', + function (event) { + this.toggle(); + event.stopPropagation(); + }.bind(this) + ); } // update active clause on scroll @@ -261,13 +384,12 @@ function Menu() { if (offTop) { e.preventDefault(); } - var offBottom = e.deltaY > 0 - && target.offsetHeight + target.scrollTop >= target.scrollHeight; + var offBottom = e.deltaY > 0 && target.offsetHeight + target.scrollTop >= target.scrollHeight; if (offBottom) { - e.preventDefault(); - } - }) + e.preventDefault(); + } + }); } Menu.prototype.documentKeydown = function (e) { @@ -277,16 +399,16 @@ Menu.prototype.documentKeydown = function (e) { } else if (e.keyCode > 48 && e.keyCode < 58) { this.selectPin(e.keyCode - 49); } -} +}; Menu.prototype.updateActiveClause = function () { - this.setActiveClause(findActiveClause(this.$specContainer)) -} + this.setActiveClause(findActiveClause(this.$specContainer)); +}; Menu.prototype.setActiveClause = function (clause) { this.$activeClause = clause; this.revealInToc(this.$activeClause); -} +}; Menu.prototype.revealInToc = function (path) { var current = this.$toc.querySelectorAll('li.revealed'); @@ -294,21 +416,22 @@ Menu.prototype.revealInToc = function (path) { current[i].classList.remove('revealed'); current[i].classList.remove('revealed-leaf'); } - + var current = this.$toc; var index = 0; while (index < path.length) { var children = current.children; for (var i = 0; i < children.length; i++) { - if ('#' + path[index].id === children[i].children[1].getAttribute('href') ) { + if ('#' + path[index].id === children[i].children[1].getAttribute('href')) { children[i].classList.add('revealed'); if (index === path.length - 1) { children[i].classList.add('revealed-leaf'); var rect = children[i].getBoundingClientRect(); - this.$toc.getBoundingClientRect().top + // this.$toc.getBoundingClientRect().top; var tocRect = this.$toc.getBoundingClientRect(); if (rect.top + 10 > tocRect.bottom) { - this.$toc.scrollTop = this.$toc.scrollTop + (rect.top - tocRect.bottom) + (rect.bottom - rect.top); + this.$toc.scrollTop = + this.$toc.scrollTop + (rect.top - tocRect.bottom) + (rect.bottom - rect.top); } else if (rect.top < tocRect.top) { this.$toc.scrollTop = this.$toc.scrollTop - (tocRect.top - rect.top); } @@ -316,29 +439,26 @@ Menu.prototype.revealInToc = function (path) { current = children[i].querySelector('ol'); index++; break; - } + } } - } -} +}; function findActiveClause(root, path) { var clauses = new ClauseWalker(root); var $clause; - var found = false; var path = path || []; - - while ($clause = clauses.nextNode()) { + + while (($clause = clauses.nextNode())) { var rect = $clause.getBoundingClientRect(); - var $header = $clause.children[0]; - var marginTop = parseInt(getComputedStyle($header)["margin-top"]); - - if ((rect.top - marginTop) <= 0 && rect.bottom > 0) { - found = true; + var $header = $clause.querySelector('h1'); + var marginTop = parseInt(getComputedStyle($header)['margin-top']); + + if (rect.top - marginTop <= 0 && rect.bottom > 0) { return findActiveClause($clause, path.concat($clause)) || path; } } - + return path; } @@ -354,42 +474,46 @@ function ClauseWalker(root) { } else { previous = node; } - if (node.nodeName === 'EMU-CLAUSE' || node.nodeName === 'EMU-INTRO' || node.nodeName === 'EMU-ANNEX') { + if ( + node.nodeName === 'EMU-CLAUSE' || + node.nodeName === 'EMU-INTRO' || + node.nodeName === 'EMU-ANNEX' + ) { return NodeFilter.FILTER_ACCEPT; } else { return NodeFilter.FILTER_SKIP; } - } + }, }, false - ); - + ); + return treeWalker; } Menu.prototype.toggle = function () { this.$menu.classList.toggle('active'); -} +}; Menu.prototype.show = function () { this.$menu.classList.add('active'); -} +}; Menu.prototype.hide = function () { this.$menu.classList.remove('active'); -} +}; -Menu.prototype.isVisible = function() { +Menu.prototype.isVisible = function () { return this.$menu.classList.contains('active'); -} +}; Menu.prototype.showPins = function () { this.$pins.classList.add('active'); -} +}; Menu.prototype.hidePins = function () { this.$pins.classList.remove('active'); -} +}; Menu.prototype.addPinEntry = function (id) { var entry = this.search.biblio.byId[id]; @@ -407,7 +531,8 @@ Menu.prototype.addPinEntry = function (id) { } else { prefix = ''; } - this.$pinList.innerHTML += '
  • ' + prefix + entry.titleHTML + '
  • '; + this.$pinList.innerHTML += + '
  • ' + prefix + entry.titleHTML + '
  • '; } else { this.$pinList.innerHTML += '
  • ' + entry.key + '
  • '; } @@ -417,7 +542,7 @@ Menu.prototype.addPinEntry = function (id) { } this._pinnedIds[id] = true; this.persistPinEntries(); -} +}; Menu.prototype.removePinEntry = function (id) { var item = this.$pinList.querySelector('a[href="#' + id + '"]').parentNode; @@ -428,7 +553,7 @@ Menu.prototype.removePinEntry = function (id) { } this.persistPinEntries(); -} +}; Menu.prototype.persistPinEntries = function () { try { @@ -438,7 +563,7 @@ Menu.prototype.persistPinEntries = function () { } localStorage.pinEntries = JSON.stringify(Object.keys(this._pinnedIds)); -} +}; Menu.prototype.loadPinEntries = function () { try { @@ -446,14 +571,14 @@ Menu.prototype.loadPinEntries = function () { } catch (e) { return; } - + var pinsString = window.localStorage.pinEntries; if (!pinsString) return; var pins = JSON.parse(pinsString); - for(var i = 0; i < pins.length; i++) { + for (var i = 0; i < pins.length; i++) { this.addPinEntry(pins[i]); } -} +}; Menu.prototype.togglePinEntry = function (id) { if (!id) { @@ -465,19 +590,30 @@ Menu.prototype.togglePinEntry = function (id) { } else { this.addPinEntry(id); } -} +}; Menu.prototype.selectPin = function (num) { document.location = this.$pinList.children[num].children[0].href; -} +}; var menu; function init() { menu = new Menu(); var $container = document.getElementById('spec-container'); - $container.addEventListener('mouseover', debounce(function (e) { - Toolbox.activateIfMouseOver(e); - })); + $container.addEventListener( + 'mouseover', + debounce(function (e) { + Toolbox.activateIfMouseOver(e); + }) + ); + document.addEventListener( + 'keydown', + debounce(function (e) { + if (e.code === 'Escape' && Toolbox.active) { + Toolbox.deactivate(); + } + }) + ); } document.addEventListener('DOMContentLoaded', init); @@ -485,7 +621,7 @@ document.addEventListener('DOMContentLoaded', init); function debounce(fn, opts) { opts = opts || {}; var timeout; - return function(e) { + return function (e) { if (opts.stopPropagation) { e.stopPropagation(); } @@ -493,15 +629,18 @@ function debounce(fn, opts) { if (timeout) { clearTimeout(timeout); } - timeout = setTimeout(function() { - timeout = null; - fn.apply(this, args); - }.bind(this), 150); - } + timeout = setTimeout( + function () { + timeout = null; + fn.apply(this, args); + }.bind(this), + 150 + ); + }; } var CLAUSE_NODES = ['EMU-CLAUSE', 'EMU-INTRO', 'EMU-ANNEX']; -function findLocalReferences ($elem) { +function findLocalReferences($elem) { var name = $elem.innerHTML; var references = []; @@ -510,7 +649,7 @@ function findLocalReferences ($elem) { parentClause = parentClause.parentNode; } - if(!parentClause) return; + if (!parentClause) return; var vars = parentClause.querySelectorAll('var'); @@ -538,7 +677,7 @@ function toggleFindLocalReferences($elem) { } } -function installFindLocalReferences () { +function installFindLocalReferences() { document.addEventListener('click', function (e) { if (e.target.nodeName === 'VAR') { toggleFindLocalReferences(e.target); @@ -548,9 +687,6 @@ function installFindLocalReferences () { document.addEventListener('DOMContentLoaded', installFindLocalReferences); - - - // The following license applies to the fuzzysearch function // The MIT License (MIT) // Copyright © 2015 Nicolas Bevacqua @@ -571,17 +707,16 @@ document.addEventListener('DOMContentLoaded', installFindLocalReferences); // 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. -function fuzzysearch (searchString, haystack, caseInsensitive) { +function fuzzysearch(searchString, haystack, caseInsensitive) { var tlen = haystack.length; var qlen = searchString.length; var chunks = 1; var finding = false; - var prefix = true; - + if (qlen > tlen) { return false; } - + if (qlen === tlen) { if (searchString === haystack) { return { caseMatch: true, chunks: 1, prefix: true }; @@ -591,7 +726,7 @@ function fuzzysearch (searchString, haystack, caseInsensitive) { return false; } } - + outer: for (var i = 0, j = 0; i < qlen; i++) { var nch = searchString[i]; while (j < tlen) { @@ -605,57 +740,69 @@ function fuzzysearch (searchString, haystack, caseInsensitive) { finding = false; } } - - if (caseInsensitive) { return false } - + + if (caseInsensitive) { + return false; + } + return fuzzysearch(searchString.toLowerCase(), haystack.toLowerCase(), true); } - + return { caseMatch: !caseInsensitive, chunks: chunks, prefix: j <= qlen }; } var Toolbox = { init: function () { + this.$outer = document.createElement('div'); + this.$outer.classList.add('toolbox-container'); this.$container = document.createElement('div'); this.$container.classList.add('toolbox'); + this.$outer.appendChild(this.$container); this.$permalink = document.createElement('a'); this.$permalink.textContent = 'Permalink'; this.$pinLink = document.createElement('a'); this.$pinLink.textContent = 'Pin'; this.$pinLink.setAttribute('href', '#'); - this.$pinLink.addEventListener('click', function (e) { - e.preventDefault(); - e.stopPropagation(); - menu.togglePinEntry(this.entry.id); - }.bind(this)); + this.$pinLink.addEventListener( + 'click', + function (e) { + e.preventDefault(); + e.stopPropagation(); + menu.togglePinEntry(this.entry.id); + }.bind(this) + ); this.$refsLink = document.createElement('a'); this.$refsLink.setAttribute('href', '#'); - this.$refsLink.addEventListener('click', function (e) { - e.preventDefault(); - e.stopPropagation(); - referencePane.showReferencesFor(this.entry); - }.bind(this)); + this.$refsLink.addEventListener( + 'click', + function (e) { + e.preventDefault(); + e.stopPropagation(); + referencePane.showReferencesFor(this.entry); + }.bind(this) + ); this.$container.appendChild(this.$permalink); this.$container.appendChild(this.$pinLink); this.$container.appendChild(this.$refsLink); - document.body.appendChild(this.$container); + document.body.appendChild(this.$outer); }, activate: function (el, entry, target) { if (el === this._activeEl) return; + sdoBox.deactivate(); this.active = true; this.entry = entry; - this.$container.classList.add('active'); - this.top = el.offsetTop - this.$container.offsetHeight - 10; - this.left = el.offsetLeft; - this.$container.setAttribute('style', 'left: ' + this.left + 'px; top: ' + this.top + 'px'); + this.$outer.classList.add('active'); + this.top = el.offsetTop - this.$outer.offsetHeight; + this.left = el.offsetLeft - 10; + this.$outer.setAttribute('style', 'left: ' + this.left + 'px; top: ' + this.top + 'px'); this.updatePermalink(); this.updateReferences(); this._activeEl = el; if (this.top < document.body.scrollTop && el === target) { // don't scroll unless it's a small thing (< 200px) - this.$container.scrollIntoView(); + this.$outer.scrollIntoView(); } }, @@ -672,7 +819,10 @@ var Toolbox = { if (ref && (!this.active || e.pageY > this._activeEl.offsetTop)) { var entry = menu.search.biblio.byId[ref.id]; this.activate(ref.element, entry, e.target); - } else if (this.active && ((e.pageY < this.top) || e.pageY > (this._activeEl.offsetTop + this._activeEl.offsetHeight))) { + } else if ( + this.active && + (e.pageY < this.top || e.pageY > this._activeEl.offsetTop + this._activeEl.offsetHeight) + ) { this.deactivate(); } }, @@ -680,16 +830,38 @@ var Toolbox = { findReferenceUnder: function (el) { while (el) { var parent = el.parentNode; - if (el.nodeName === 'H1' && parent.nodeName.match(/EMU-CLAUSE|EMU-ANNEX|EMU-INTRO/) && parent.id) { + if (el.nodeName === 'EMU-RHS' || el.nodeName === 'EMU-PRODUCTION') { + return null; + } + if ( + el.nodeName === 'H1' && + parent.nodeName.match(/EMU-CLAUSE|EMU-ANNEX|EMU-INTRO/) && + parent.id + ) { return { element: el, id: parent.id }; - } else if (el.nodeName.match(/EMU-(?!CLAUSE|XREF|ANNEX|INTRO)|DFN/) && - el.id && el.id[0] !== '_') { - if (el.nodeName === 'EMU-FIGURE' || el.nodeName === 'EMU-TABLE' || el.nodeName === 'EMU-EXAMPLE') { + } else if (el.nodeName === 'EMU-NT') { + if ( + parent.nodeName === 'EMU-PRODUCTION' && + parent.id && + parent.id[0] !== '_' && + parent.firstElementChild === el + ) { + // return the LHS non-terminal element + return { element: el, id: parent.id }; + } + return null; + } else if ( + el.nodeName.match(/EMU-(?!CLAUSE|XREF|ANNEX|INTRO)|DFN/) && + el.id && + el.id[0] !== '_' + ) { + if ( + el.nodeName === 'EMU-FIGURE' || + el.nodeName === 'EMU-TABLE' || + el.nodeName === 'EMU-EXAMPLE' + ) { // return the figcaption element return { element: el.children[0].children[0], id: el.id }; - } else if (el.nodeName === 'EMU-PRODUCTION') { - // return the LHS non-terminal element - return { element: el.children[0], id: el.id }; } else { return { element: el, id: el.id }; } @@ -699,15 +871,14 @@ var Toolbox = { }, deactivate: function () { - this.$container.classList.remove('active'); + this.$outer.classList.remove('active'); this._activeEl = null; - this.activeElBounds = null; this.active = false; - } -} + }, +}; var referencePane = { - init: function() { + init: function () { this.$container = document.createElement('div'); this.$container.setAttribute('id', 'references-pane-container'); @@ -722,14 +893,18 @@ var referencePane = { this.$header = document.createElement('div'); this.$header.classList.add('menu-pane-header'); - this.$header.textContent = 'References to '; + this.$headerText = document.createElement('span'); + this.$header.appendChild(this.$headerText); this.$headerRefId = document.createElement('a'); this.$header.appendChild(this.$headerRefId); this.$closeButton = document.createElement('span'); this.$closeButton.setAttribute('id', 'references-pane-close'); - this.$closeButton.addEventListener('click', function (e) { - this.deactivate(); - }.bind(this)); + this.$closeButton.addEventListener( + 'click', + function (e) { + this.deactivate(); + }.bind(this) + ); this.$header.appendChild(this.$closeButton); this.$pane.appendChild(this.$header); @@ -755,44 +930,101 @@ var referencePane = { this.$container.classList.remove('active'); }, - showReferencesFor(entry) { + showReferencesFor: function (entry) { this.activate(); + this.$headerText.textContent = 'References to '; var newBody = document.createElement('tbody'); var previousId; var previousCell; var dupCount = 0; this.$headerRefId.textContent = '#' + entry.id; this.$headerRefId.setAttribute('href', '#' + entry.id); - entry.referencingIds.map(function (id) { - var target = document.getElementById(id); - var cid = findParentClauseId(target); - var clause = menu.search.biblio.byId[cid]; - var dupCount = 0; - return { id: id, clause: clause } - }).sort(function (a, b) { - return sortByClauseNumber(a.clause, b.clause); - }).forEach(function (record, i) { - if (previousId === record.clause.id) { - previousCell.innerHTML += ' (' + (dupCount + 2) + ')'; - dupCount++; - } else { - var row = newBody.insertRow(); - var cell = row.insertCell(); - cell.innerHTML = record.clause.number; - cell = row.insertCell(); - cell.innerHTML = '' + record.clause.titleHTML + ''; - previousCell = cell; - previousId = record.clause.id; - dupCount = 0; + this.$headerRefId.style.display = 'inline'; + entry.referencingIds + .map(function (id) { + var target = document.getElementById(id); + var cid = findParentClauseId(target); + var clause = menu.search.biblio.byId[cid]; + return { id: id, clause: clause }; + }) + .sort(function (a, b) { + return sortByClauseNumber(a.clause, b.clause); + }) + .forEach(function (record, i) { + if (previousId === record.clause.id) { + previousCell.innerHTML += ' (' + (dupCount + 2) + ')'; + dupCount++; + } else { + var row = newBody.insertRow(); + var cell = row.insertCell(); + cell.innerHTML = record.clause.number; + cell = row.insertCell(); + cell.innerHTML = '' + record.clause.titleHTML + ''; + previousCell = cell; + previousId = record.clause.id; + dupCount = 0; + } + }, this); + this.$table.removeChild(this.$tableBody); + this.$tableBody = newBody; + this.$table.appendChild(this.$tableBody); + }, + + showSDOs: function (sdos, alternativeId) { + this.activate(); + var rhs = document.getElementById(alternativeId); + var parentName = rhs.parentNode.getAttribute('name'); + var colons = rhs.parentNode.querySelector('emu-geq'); + rhs = rhs.cloneNode(true); + rhs.querySelectorAll('emu-params,emu-constraints').forEach(function (e) { + e.remove(); + }); + rhs.querySelectorAll('[id]').forEach(function (e) { + e.removeAttribute('id'); + }); + rhs.querySelectorAll('a').forEach(function (e) { + e.parentNode.replaceChild(document.createTextNode(e.textContent), e); + }); + var text = parentName + ' : ' + rhs.textContent.replace(/\s+/g, ' '); + + this.$headerText.innerHTML = + 'Syntax-Directed Operations for
    ' + + parentName + + ' ' + + colons.outerHTML + + ' '; + this.$headerText.querySelector('a').append(rhs); + this.$headerRefId.style.display = 'none'; + var newBody = document.createElement('tbody'); + Object.keys(sdos).forEach(function (sdoName) { + var pair = sdos[sdoName]; + var clause = pair.clause; + var ids = pair.ids; + var first = ids[0]; + var row = newBody.insertRow(); + var cell = row.insertCell(); + cell.innerHTML = clause; + cell = row.insertCell(); + var html = '' + sdoName + ''; + for (var i = 1; i < ids.length; ++i) { + html += ' (' + (i + 1) + ')'; } - }, this); + cell.innerHTML = html; + }); this.$table.removeChild(this.$tableBody); this.$tableBody = newBody; this.$table.appendChild(this.$tableBody); - } -} + }, +}; function findParentClauseId(node) { - while (node && node.nodeName !== 'EMU-CLAUSE' && node.nodeName !== 'EMU-INTRO' && node.nodeName !== 'EMU-ANNEX') { + while ( + node && + node.nodeName !== 'EMU-CLAUSE' && + node.nodeName !== 'EMU-INTRO' && + node.nodeName !== 'EMU-ANNEX' + ) { node = node.parentNode; } if (!node) return null; @@ -807,7 +1039,7 @@ function sortByClauseNumber(c1, c2) { if (i >= c2c.length) { return 1; } - + var c1 = c1c[i]; var c2 = c2c[i]; var c1cn = Number(c1); @@ -823,7 +1055,7 @@ function sortByClauseNumber(c1, c2) { return -1; } else if (Number.isNaN(c1cn) && !Number.isNaN(c2cn)) { return 1; - } else if(c1cn > c2cn) { + } else if (c1cn > c2cn) { return 1; } else if (c1cn < c2cn) { return -1; @@ -839,9 +1071,9 @@ function sortByClauseNumber(c1, c2) { document.addEventListener('DOMContentLoaded', function () { Toolbox.init(); referencePane.init(); -}) +}); var CLAUSE_NODES = ['EMU-CLAUSE', 'EMU-INTRO', 'EMU-ANNEX']; -function findLocalReferences ($elem) { +function findLocalReferences($elem) { var name = $elem.innerHTML; var references = []; @@ -850,7 +1082,7 @@ function findLocalReferences ($elem) { parentClause = parentClause.parentNode; } - if(!parentClause) return; + if (!parentClause) return; var vars = parentClause.querySelectorAll('var'); @@ -878,7 +1110,7 @@ function toggleFindLocalReferences($elem) { } } -function installFindLocalReferences () { +function installFindLocalReferences() { document.addEventListener('click', function (e) { if (e.target.nodeName === 'VAR') { toggleFindLocalReferences(e.target); @@ -887,3 +1119,36 @@ function installFindLocalReferences () { } document.addEventListener('DOMContentLoaded', installFindLocalReferences); +var decimalBullet = Array.apply(null, Array(100)).map(function (a, i) { + return '' + (i + 1); +}); +var alphaBullet = Array.apply(null, Array(26)).map(function (a, i) { + return String.fromCharCode('a'.charCodeAt(0) + i); +}); + +// prettier-ignore +var romanBullet = ['i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii', 'viii', 'ix', 'x', 'xi', 'xii', 'xiii', 'xiv', 'xv', 'xvi', 'xvii', 'xviii', 'xix', 'xx', 'xxi', 'xxii', 'xxiii', 'xxiv', 'xxv']; +// prettier-ignore +var bullets = [decimalBullet, alphaBullet, romanBullet, decimalBullet, alphaBullet, romanBullet]; + +function addStepNumberText(ol, parentIndex) { + for (var i = 0; i < ol.children.length; ++i) { + var child = ol.children[i]; + var index = parentIndex.concat([i]); + var applicable = bullets[Math.min(index.length - 1, 5)]; + var span = document.createElement('span'); + span.textContent = (applicable[i] || '?') + '. '; + span.style.fontSize = '0'; + span.setAttribute('aria-hidden', 'true'); + child.prepend(span); + var sublist = child.querySelector('ol'); + if (sublist != null) { + addStepNumberText(sublist, index); + } + } +} +document.addEventListener('DOMContentLoaded', function () { + document.querySelectorAll('emu-alg > ol').forEach(function (ol) { + addStepNumberText(ol, []); + }); +});