///|
const ASCII_PROPERTY_NAME : Regex = re"^[A-Za-z_$][A-Za-z0-9_$]*$"
///|
const PROPERTY_QUOTE_START : Regex = re"^['\"`]"
///|
/// Decode static ASCII identifier keys, including JS escapes. Other values
/// cannot collide with the ASCII property names generated by this pass.
fn quoted_property_name(source : String, start : Int, end : Int) -> String? {
let output = StringBuilder()
for remaining = source.view(start_offset=start + 1, end_offset=end - 1) {
let (digits, radix, rest) = lexmatch remaining with longest {
(re"^[A-Za-z0-9_$]+" as literal, after=rest) => {
output.write_view(literal)
continue rest
}
(re"^\\(?:\r\n|[\n\r\u2028\u2029])", after=rest) => continue rest
(re"^\\x" + (re"[0-9A-Fa-f]{2}" as digits), after=rest) =>
(digits, 16, rest)
(re"^\\u" + (re"[0-9A-Fa-f]{4}" as digits), after=rest) =>
(digits, 16, rest)
(re"^\\u[{]" + (re"[0-9A-Fa-f]+" as digits) + re"[}]", after=rest) =>
(digits, 16, rest)
(
re"^\\" +
((re"[0-3][0-7]{0,2}" | re"[4-7][0-7]?") as digits),
after=rest,
) => (digits, 8, rest)
// Incomplete numeric escapes and control escapes cannot name a property.
(re"^\\[bfnrtvux]", after=_) => return None
(re"^\\" + (re"[A-Za-z0-9_$]" as character), after=rest) => {
output.write_char(character)
continue rest
}
re"^$" => break
_ => return None
}
guard decode_escape_digits(digits, radix) is Some(code_point) else {
return None
}
guard code_point < 0x80 && code_point.to_char() is Some(character) else {
return None
}
output.write_char(character)
continue rest
}
let name = output.to_string()
guard name =~ ASCII_PROPERTY_NAME else { return None }
Some(name)
}
///|
fn Program::property_leaf(program : Program, id : Int) -> Int {
for current = id {
let node = program.nodes[current]
guard node.kind == Parenthesized else { break current }
continue node.a
}
}