mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 21:31:46 +00:00
113 lines
4.1 KiB
TypeScript
113 lines
4.1 KiB
TypeScript
import { OutOfRange, unreachable } from '../helpers.mts';
|
|
import type { ParseNode } from '../parser/ParseNode.mts';
|
|
import { UTF16SurrogatePairToCodePoint } from './all.mts';
|
|
import { Unicode, type CodePoint } from '#self';
|
|
|
|
export type CharacterValueAcceptNode =
|
|
| ParseNode.RegExp.CharacterEscape
|
|
| ParseNode.RegExp.RegExpUnicodeEscapeSequence
|
|
| ParseNode.RegExp.ClassAtom
|
|
| ParseNode.RegExp.ClassEscape
|
|
| ParseNode.RegExp.ClassSetCharacter;
|
|
|
|
/** https://tc39.es/ecma262/#sec-patterns-static-semantics-character-value */
|
|
export function CharacterValue(node: CharacterValueAcceptNode): CodePoint {
|
|
switch (node.type) {
|
|
case 'CharacterEscape':
|
|
switch (node.production) {
|
|
case 'ControlEscape':
|
|
switch (node.ControlEscape) {
|
|
case 't':
|
|
return 0x0009 as CodePoint;
|
|
case 'n':
|
|
return 0x000A as CodePoint;
|
|
case 'v':
|
|
return 0x000B as CodePoint;
|
|
case 'f':
|
|
return 0x000C as CodePoint;
|
|
case 'r':
|
|
return 0x000D as CodePoint;
|
|
default:
|
|
unreachable(node.ControlEscape);
|
|
}
|
|
case 'AsciiLetter': {
|
|
// 1. Let ch be the code point matched by ControlLetter.
|
|
const ch = node.AsciiLetter;
|
|
// 2. Let i be ch's code point value.
|
|
const i = ch.codePointAt(0)!;
|
|
// 3. Return the remainder of dividing i by 32.
|
|
return i % 32 as CodePoint;
|
|
}
|
|
case 'HexEscapeSequence':
|
|
// 1. Return the numeric value of the code unit that is the SV of HexEscapeSequence.
|
|
return Number.parseInt(`${node.HexEscapeSequence.HexDigit_a}${node.HexEscapeSequence.HexDigit_b}`, 16) as CodePoint;
|
|
case 'RegExpUnicodeEscapeSequence':
|
|
return CharacterValue(node.RegExpUnicodeEscapeSequence);
|
|
case '0':
|
|
// 1. Return the code point value of U+0000 (NULL).
|
|
return 0x0000 as CodePoint;
|
|
case 'IdentityEscape': {
|
|
// 1. Let ch be the code point matched by IdentityEscape.
|
|
const ch = node.IdentityEscape.codePointAt(0)!;
|
|
// 2. Return the code point value of ch.
|
|
return ch as CodePoint;
|
|
}
|
|
default:
|
|
unreachable(node);
|
|
}
|
|
case 'RegExpUnicodeEscapeSequence':
|
|
switch (true) {
|
|
case 'Hex4Digits' in node:
|
|
return node.Hex4Digits as CodePoint;
|
|
case 'CodePoint' in node:
|
|
return node.CodePoint as CodePoint;
|
|
case 'HexTrailSurrogate' in node:
|
|
return UTF16SurrogatePairToCodePoint(node.HexLeadSurrogate!, node.HexTrailSurrogate!);
|
|
case 'HexLeadSurrogate' in node:
|
|
return node.HexLeadSurrogate as CodePoint;
|
|
default:
|
|
throw new OutOfRange('CharacterValue', node);
|
|
}
|
|
case 'ClassAtom':
|
|
switch (node.production) {
|
|
case '-':
|
|
// 1. Return the code point value of U+002D (HYPHEN-MINUS).
|
|
return 0x002D as CodePoint;
|
|
case 'SourceCharacter': {
|
|
// 1. Let ch be the code point matched by SourceCharacter.
|
|
const ch = node.SourceCharacter.codePointAt(0)!;
|
|
// 2. Return ch.
|
|
return ch as CodePoint;
|
|
}
|
|
case 'ClassEscape':
|
|
return CharacterValue(node.ClassEscape);
|
|
default:
|
|
unreachable(node);
|
|
}
|
|
case 'ClassEscape':
|
|
switch (node.production) {
|
|
case 'b':
|
|
// 1. Return the code point value of U+0008 (BACKSPACE).
|
|
return 0x0008 as CodePoint;
|
|
case '-':
|
|
// 1. Return the code point value of U+002D (HYPHEN-MINUS).
|
|
return 0x002D as CodePoint;
|
|
case 'CharacterEscape':
|
|
return CharacterValue(node.CharacterEscape);
|
|
case 'CharacterClassEscape':
|
|
throw new OutOfRange('CharacterValue', node);
|
|
default:
|
|
unreachable(node);
|
|
}
|
|
case 'ClassSetCharacter': {
|
|
if (node.production === 'CharacterEscape') {
|
|
return CharacterValue(node.CharacterEscape);
|
|
} else {
|
|
return Unicode.toCodePoint(node.UnicodeCharacter);
|
|
}
|
|
}
|
|
default:
|
|
unreachable(node);
|
|
}
|
|
}
|