Files
ask262/engine262/src/static-semantics/CharacterValue.mts
T

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);
}
}