mirror of https://github.com/boa-dev/boa.git
Browse Source
This Pull Request improves our test results display per edition and cleanups our edition detector logic. It changes the following: - Adds a new `edition` flag to limit the maximum edition that will be tested. - Adds a new `versioned` flag to display all tested editions in a table. - Adds utility methods to `SpecEdition` to detect the edition of a test and get all the available editions. - Cleanups logic. Output with this PR ~(We only collect ES5, ES6 and ES13 stats, so all other editions are a WIP)~: ![image](https://user-images.githubusercontent.com/38230983/227010384-883f0934-47be-4be7-84c2-a21feb9de8a9.png) ~Marking as a draft since I need to determine the version of the remaining features, but feel free to review everything else.~ Finished!pull/2724/head
José Julián Espina
2 years ago
7 changed files with 771 additions and 218 deletions
@ -0,0 +1,358 @@ |
|||||||
|
//! Edition detection utilities.
|
||||||
|
//!
|
||||||
|
//! This module contains the [`SpecEdition`] struct, which is used in the tester to
|
||||||
|
//! classify all tests per minimum required ECMAScript edition.
|
||||||
|
|
||||||
|
use std::fmt::Display; |
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize}; |
||||||
|
|
||||||
|
use crate::read::{MetaData, TestFlag}; |
||||||
|
|
||||||
|
// TODO: Open PR in https://github.com/tc39/test262 to add "exp-operator" and "Array.prototype.includes"
|
||||||
|
// features.
|
||||||
|
/// Minimum edition required by a specific feature in the `test262` repository.
|
||||||
|
static FEATURE_EDITION: phf::Map<&'static str, SpecEdition> = phf::phf_map! { |
||||||
|
// Proposed language features
|
||||||
|
|
||||||
|
// Hashbang Grammar
|
||||||
|
// https://github.com/tc39/proposal-hashbang
|
||||||
|
"hashbang" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Intl.Locale Info
|
||||||
|
// https://github.com/tc39/proposal-intl-locale-info
|
||||||
|
"Intl.Locale-info" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// FinalizationRegistry#cleanupSome
|
||||||
|
// https://github.com/tc39/proposal-cleanup-some
|
||||||
|
"FinalizationRegistry.prototype.cleanupSome" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Intl.NumberFormat V3
|
||||||
|
// https://github.com/tc39/proposal-intl-numberformat-v3
|
||||||
|
"Intl.NumberFormat-v3" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Legacy RegExp features
|
||||||
|
// https://github.com/tc39/proposal-regexp-legacy-features
|
||||||
|
"legacy-regexp" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Atomics.waitAsync
|
||||||
|
// https://github.com/tc39/proposal-atomics-wait-async
|
||||||
|
"Atomics.waitAsync" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Import Assertions
|
||||||
|
// https://github.com/tc39/proposal-import-assertions/
|
||||||
|
"import-assertions" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// JSON modules
|
||||||
|
// https://github.com/tc39/proposal-json-modules
|
||||||
|
"json-modules" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Resizable Arraybuffer
|
||||||
|
// https://github.com/tc39/proposal-resizablearraybuffer
|
||||||
|
"resizable-arraybuffer" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// ArrayBuffer transfer
|
||||||
|
// https://github.com/tc39/proposal-arraybuffer-transfer
|
||||||
|
"arraybuffer-transfer" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Temporal
|
||||||
|
// https://github.com/tc39/proposal-temporal
|
||||||
|
"Temporal" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// ShadowRealm, née Callable Boundary Realms
|
||||||
|
// https://github.com/tc39/proposal-realms
|
||||||
|
"ShadowRealm" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Array.prototype.findLast & Array.prototype.findLastIndex
|
||||||
|
// https://github.com/tc39/proposal-array-find-from-last
|
||||||
|
"array-find-from-last" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Array.prototype.group & Array.prototype.groupToMap
|
||||||
|
// https://github.com/tc39/proposal-array-grouping
|
||||||
|
"array-grouping" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Intl.DurationFormat
|
||||||
|
// https://github.com/tc39/proposal-intl-duration-format
|
||||||
|
"Intl.DurationFormat" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// RegExp set notation + properties of strings
|
||||||
|
// https://github.com/tc39/proposal-regexp-set-notation
|
||||||
|
"regexp-v-flag" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Decorators
|
||||||
|
// https://github.com/tc39/proposal-decorators
|
||||||
|
"decorators" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Duplicate named capturing groups
|
||||||
|
// https://github.com/tc39/proposal-duplicate-named-capturing-groups
|
||||||
|
"regexp-duplicate-named-groups" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Symbols as WeakMap keys
|
||||||
|
// https://github.com/tc39/proposal-symbols-as-weakmap-keys
|
||||||
|
"symbols-as-weakmap-keys" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Array.prototype.toReversed, Array.prototype.toSorted, Array.prototype.toSpliced,
|
||||||
|
// Array.prototype.with and the equivalent TypedArray methods.
|
||||||
|
// https://github.com/tc39/proposal-change-array-by-copy/
|
||||||
|
"change-array-by-copy" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// https://tc39.es/proposal-array-from-async/
|
||||||
|
"Array.fromAsync" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Well-formed Unicode strings
|
||||||
|
// https://github.com/tc39/proposal-is-usv-string
|
||||||
|
"String.prototype.isWellFormed" => SpecEdition::ESNext, |
||||||
|
"String.prototype.toWellFormed" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// https://github.com/tc39/proposal-intl-enumeration
|
||||||
|
"Intl-enumeration" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Part of the next ES14 edition
|
||||||
|
|
||||||
|
"Intl.DateTimeFormat-extend-timezonename" => SpecEdition::ESNext, |
||||||
|
"Intl.DisplayNames-v2" => SpecEdition::ESNext, |
||||||
|
"Intl.Segmenter" => SpecEdition::ESNext, |
||||||
|
|
||||||
|
// Standard language features
|
||||||
|
|
||||||
|
"AggregateError" => SpecEdition::ES12, |
||||||
|
"align-detached-buffer-semantics-with-web-reality" => SpecEdition::ES12, |
||||||
|
"arbitrary-module-namespace-names" => SpecEdition::ES13, |
||||||
|
"ArrayBuffer" => SpecEdition::ES6, |
||||||
|
"Array.prototype.at" => SpecEdition::ES13, |
||||||
|
"Array.prototype.flat" => SpecEdition::ES10, |
||||||
|
"Array.prototype.flatMap" => SpecEdition::ES10, |
||||||
|
"Array.prototype.values" => SpecEdition::ES6, |
||||||
|
"arrow-function" => SpecEdition::ES6, |
||||||
|
"async-iteration" => SpecEdition::ES9, |
||||||
|
"async-functions" => SpecEdition::ES8, |
||||||
|
"Atomics" => SpecEdition::ES8, |
||||||
|
"BigInt" => SpecEdition::ES11, |
||||||
|
"caller" => SpecEdition::ES5, |
||||||
|
"class" => SpecEdition::ES6, |
||||||
|
"class-fields-private" => SpecEdition::ES13, |
||||||
|
"class-fields-private-in" => SpecEdition::ES13, |
||||||
|
"class-fields-public" => SpecEdition::ES13, |
||||||
|
"class-methods-private" => SpecEdition::ES13, |
||||||
|
"class-static-block" => SpecEdition::ES13, |
||||||
|
"class-static-fields-private" => SpecEdition::ES13, |
||||||
|
"class-static-fields-public" => SpecEdition::ES13, |
||||||
|
"class-static-methods-private" => SpecEdition::ES13, |
||||||
|
"coalesce-expression" => SpecEdition::ES11, |
||||||
|
"computed-property-names" => SpecEdition::ES6, |
||||||
|
"const" => SpecEdition::ES6, |
||||||
|
"cross-realm" => SpecEdition::ES6, |
||||||
|
"DataView" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.getFloat32" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.getFloat64" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.getInt16" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.getInt32" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.getInt8" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.getUint16" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.getUint32" => SpecEdition::ES6, |
||||||
|
"DataView.prototype.setUint8" => SpecEdition::ES6, |
||||||
|
"default-parameters" => SpecEdition::ES6, |
||||||
|
"destructuring-assignment" => SpecEdition::ES6, |
||||||
|
"destructuring-binding" => SpecEdition::ES6, |
||||||
|
"dynamic-import" => SpecEdition::ES11, |
||||||
|
"error-cause" => SpecEdition::ES13, |
||||||
|
"export-star-as-namespace-from-module" => SpecEdition::ES11, |
||||||
|
"FinalizationRegistry" => SpecEdition::ES12, |
||||||
|
"for-in-order" => SpecEdition::ES11, |
||||||
|
"for-of" => SpecEdition::ES6, |
||||||
|
"Float32Array" => SpecEdition::ES6, |
||||||
|
"Float64Array" => SpecEdition::ES6, |
||||||
|
"generators" => SpecEdition::ES6, |
||||||
|
"globalThis" => SpecEdition::ES11, |
||||||
|
"import.meta" => SpecEdition::ES11, |
||||||
|
"Int8Array" => SpecEdition::ES6, |
||||||
|
"Int16Array" => SpecEdition::ES6, |
||||||
|
"Int32Array" => SpecEdition::ES6, |
||||||
|
"intl-normative-optional" => SpecEdition::ES8, |
||||||
|
"Intl.DateTimeFormat-datetimestyle" => SpecEdition::ES12, |
||||||
|
"Intl.DateTimeFormat-dayPeriod" => SpecEdition::ES8, |
||||||
|
"Intl.DateTimeFormat-formatRange" => SpecEdition::ES12, |
||||||
|
"Intl.DateTimeFormat-fractionalSecondDigits" => SpecEdition::ES12, |
||||||
|
"Intl.DisplayNames" => SpecEdition::ES12, |
||||||
|
"Intl.ListFormat" => SpecEdition::ES12, |
||||||
|
"Intl.Locale" => SpecEdition::ES12, |
||||||
|
"Intl.NumberFormat-unified" => SpecEdition::ES11, |
||||||
|
"Intl.RelativeTimeFormat" => SpecEdition::ES11, |
||||||
|
"json-superset" => SpecEdition::ES10, |
||||||
|
"let" => SpecEdition::ES6, |
||||||
|
"logical-assignment-operators" => SpecEdition::ES12, |
||||||
|
"Map" => SpecEdition::ES6, |
||||||
|
"new.target" => SpecEdition::ES6, |
||||||
|
"numeric-separator-literal" => SpecEdition::ES12, |
||||||
|
"object-rest" => SpecEdition::ES9, |
||||||
|
"object-spread" => SpecEdition::ES9, |
||||||
|
"Object.fromEntries" => SpecEdition::ES10, |
||||||
|
"Object.hasOwn" => SpecEdition::ES13, |
||||||
|
"Object.is" => SpecEdition::ES6, |
||||||
|
"optional-catch-binding" => SpecEdition::ES10, |
||||||
|
"optional-chaining" => SpecEdition::ES11, |
||||||
|
"Promise" => SpecEdition::ES6, |
||||||
|
"Promise.allSettled" => SpecEdition::ES11, |
||||||
|
"Promise.any" => SpecEdition::ES12, |
||||||
|
"Promise.prototype.finally" => SpecEdition::ES9, |
||||||
|
"Proxy" => SpecEdition::ES6, |
||||||
|
"proxy-missing-checks" => SpecEdition::ES6, |
||||||
|
"Reflect" => SpecEdition::ES6, |
||||||
|
"Reflect.construct" => SpecEdition::ES6, |
||||||
|
"Reflect.set" => SpecEdition::ES6, |
||||||
|
"Reflect.setPrototypeOf" => SpecEdition::ES6, |
||||||
|
"regexp-dotall" => SpecEdition::ES9, |
||||||
|
"regexp-lookbehind" => SpecEdition::ES9, |
||||||
|
"regexp-match-indices" => SpecEdition::ES13, |
||||||
|
"regexp-named-groups" => SpecEdition::ES9, |
||||||
|
"regexp-unicode-property-escapes" => SpecEdition::ES9, |
||||||
|
"rest-parameters" => SpecEdition::ES6, |
||||||
|
"Set" => SpecEdition::ES6, |
||||||
|
"SharedArrayBuffer" => SpecEdition::ES8, |
||||||
|
"string-trimming" => SpecEdition::ES10, |
||||||
|
"String.fromCodePoint" => SpecEdition::ES6, |
||||||
|
"String.prototype.at" => SpecEdition::ES13, |
||||||
|
"String.prototype.endsWith" => SpecEdition::ES6, |
||||||
|
"String.prototype.includes" => SpecEdition::ES6, |
||||||
|
"String.prototype.matchAll" => SpecEdition::ES11, |
||||||
|
"String.prototype.replaceAll" => SpecEdition::ES12, |
||||||
|
"String.prototype.trimEnd" => SpecEdition::ES10, |
||||||
|
"String.prototype.trimStart" => SpecEdition::ES10, |
||||||
|
"super" => SpecEdition::ES6, |
||||||
|
"Symbol" => SpecEdition::ES6, |
||||||
|
"Symbol.asyncIterator" => SpecEdition::ES9, |
||||||
|
"Symbol.hasInstance" => SpecEdition::ES6, |
||||||
|
"Symbol.isConcatSpreadable" => SpecEdition::ES6, |
||||||
|
"Symbol.iterator" => SpecEdition::ES6, |
||||||
|
"Symbol.match" => SpecEdition::ES6, |
||||||
|
"Symbol.matchAll" => SpecEdition::ES11, |
||||||
|
"Symbol.prototype.description" => SpecEdition::ES10, |
||||||
|
"Symbol.replace" => SpecEdition::ES6, |
||||||
|
"Symbol.search" => SpecEdition::ES6, |
||||||
|
"Symbol.species" => SpecEdition::ES6, |
||||||
|
"Symbol.split" => SpecEdition::ES6, |
||||||
|
"Symbol.toPrimitive" => SpecEdition::ES6, |
||||||
|
"Symbol.toStringTag" => SpecEdition::ES6, |
||||||
|
"Symbol.unscopables" => SpecEdition::ES6, |
||||||
|
"tail-call-optimization" => SpecEdition::ES6, |
||||||
|
"template" => SpecEdition::ES6, |
||||||
|
"top-level-await" => SpecEdition::ES13, |
||||||
|
"TypedArray" => SpecEdition::ES6, |
||||||
|
"TypedArray.prototype.at" => SpecEdition::ES13, |
||||||
|
"u180e" => SpecEdition::ES7, |
||||||
|
"Uint8Array" => SpecEdition::ES6, |
||||||
|
"Uint16Array" => SpecEdition::ES6, |
||||||
|
"Uint32Array" => SpecEdition::ES6, |
||||||
|
"Uint8ClampedArray" => SpecEdition::ES6, |
||||||
|
"WeakMap" => SpecEdition::ES6, |
||||||
|
"WeakRef" => SpecEdition::ES12, |
||||||
|
"WeakSet" => SpecEdition::ES6, |
||||||
|
"well-formed-json-stringify" => SpecEdition::ES10, |
||||||
|
"__proto__" => SpecEdition::ES6, |
||||||
|
"__getter__" => SpecEdition::ES8, |
||||||
|
"__setter__" => SpecEdition::ES8, |
||||||
|
|
||||||
|
// Test-Harness Features
|
||||||
|
|
||||||
|
"IsHTMLDDA" => SpecEdition::ES9, |
||||||
|
"host-gc-required" => SpecEdition::ES5, |
||||||
|
}; |
||||||
|
|
||||||
|
/// List of ECMAScript editions that can be tested in the `test262` repository.
|
||||||
|
#[derive(
|
||||||
|
Debug, |
||||||
|
Clone, |
||||||
|
Copy, |
||||||
|
PartialEq, |
||||||
|
Eq, |
||||||
|
PartialOrd, |
||||||
|
Ord, |
||||||
|
Default, |
||||||
|
Serialize, |
||||||
|
Deserialize, |
||||||
|
clap::ValueEnum, |
||||||
|
)] |
||||||
|
#[serde(untagged)] |
||||||
|
pub(crate) enum SpecEdition { |
||||||
|
/// [ECMAScript 5.1 Edition](https://262.ecma-international.org/5.1)
|
||||||
|
ES5 = 5, |
||||||
|
/// [ECMAScript 6th Edition](https://262.ecma-international.org/6.0)
|
||||||
|
ES6, |
||||||
|
/// [ECMAScript 7th Edition](https://262.ecma-international.org/7.0)
|
||||||
|
ES7, |
||||||
|
/// [ECMAScript 8th Edition](https://262.ecma-international.org/8.0)
|
||||||
|
ES8, |
||||||
|
/// [ECMAScript 9th Edition](https://262.ecma-international.org/9.0)
|
||||||
|
ES9, |
||||||
|
/// [ECMAScript 10th Edition](https://262.ecma-international.org/10.0)
|
||||||
|
ES10, |
||||||
|
/// [ECMAScript 11th Edition](https://262.ecma-international.org/11.0)
|
||||||
|
ES11, |
||||||
|
/// [ECMAScript 12th Edition](https://262.ecma-international.org/12.0)
|
||||||
|
ES12, |
||||||
|
/// [ECMAScript 13th Edition](https://262.ecma-international.org/13.0)
|
||||||
|
ES13, |
||||||
|
/// The edition being worked on right now.
|
||||||
|
///
|
||||||
|
/// A draft is currently available in <https://tc39.es/ecma262>.
|
||||||
|
#[default] |
||||||
|
ESNext, |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for SpecEdition { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
match *self { |
||||||
|
Self::ESNext => write!(f, "ECMAScript Next"), |
||||||
|
Self::ES5 => write!(f, "ECMAScript 5.1"), |
||||||
|
v => write!(f, "ECMAScript {}", v as u8), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl SpecEdition { |
||||||
|
/// Gets the minimum required ECMAScript edition of a test from its metadata.
|
||||||
|
///
|
||||||
|
/// If the function finds unknown features in `metadata`, returns an `Err(Vec<&str>)` containing
|
||||||
|
/// the list of unknown features.
|
||||||
|
pub(crate) fn from_test_metadata(metadata: &MetaData) -> Result<Self, Vec<&str>> { |
||||||
|
let mut min_edition = if metadata.flags.contains(&TestFlag::Async) { |
||||||
|
Self::ES8 |
||||||
|
} else if metadata.es6id.is_some() || metadata.flags.contains(&TestFlag::Module) { |
||||||
|
Self::ES6 |
||||||
|
} else { |
||||||
|
Self::ES5 |
||||||
|
}; |
||||||
|
|
||||||
|
let mut unknowns = Vec::new(); |
||||||
|
for feature in &*metadata.features { |
||||||
|
let Some(feature_edition) = FEATURE_EDITION.get(feature).copied() else { |
||||||
|
unknowns.push(&**feature); |
||||||
|
continue; |
||||||
|
}; |
||||||
|
min_edition = std::cmp::max(min_edition, feature_edition); |
||||||
|
} |
||||||
|
|
||||||
|
if unknowns.is_empty() { |
||||||
|
Ok(min_edition) |
||||||
|
} else { |
||||||
|
Err(unknowns) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets an iterator of all currently available editions.
|
||||||
|
pub(crate) fn all_editions() -> impl Iterator<Item = Self> { |
||||||
|
[ |
||||||
|
Self::ES5, |
||||||
|
Self::ES6, |
||||||
|
Self::ES7, |
||||||
|
Self::ES8, |
||||||
|
Self::ES9, |
||||||
|
Self::ES10, |
||||||
|
Self::ES11, |
||||||
|
Self::ES12, |
||||||
|
Self::ES13, |
||||||
|
Self::ESNext, |
||||||
|
] |
||||||
|
.into_iter() |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue