Skip to content

Commit

Permalink
feat(ecmascript): String.fromCharCode (#416)
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac authored Sep 17, 2024
1 parent 451253e commit b9681f2
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::ecmascript::types::String;
use crate::ecmascript::types::Value;
use crate::ecmascript::types::BUILTIN_STRING_MEMORY;
use crate::heap::IntrinsicConstructorIndexes;
use crate::SmallString;

pub struct StringConstructor;

Expand All @@ -39,7 +40,7 @@ impl BuiltinIntrinsicConstructor for StringConstructor {
struct StringFromCharCode;
impl Builtin for StringFromCharCode {
const BEHAVIOUR: Behaviour = Behaviour::Regular(StringConstructor::from_char_code);
const LENGTH: u8 = 0;
const LENGTH: u8 = 1;
const NAME: String = BUILTIN_STRING_MEMORY.fromCharCode;
}
struct StringFromCodePoint;
Expand Down Expand Up @@ -112,20 +113,63 @@ impl StringConstructor {
Ok(s.into_value())
}

/// ### [22.1.2.1 String.fromCharCode ( ...`codeUnits` )](https://262.ecma-international.org/15.0/index.html#sec-string.fromcharcode)
///
/// This function may be called with any number of arguments which form
/// the rest parameter `codeUnits`.
fn from_char_code(
_agent: &mut Agent,
agent: &mut Agent,
_this_value: Value,
_arguments: ArgumentsList,
code_units: ArgumentsList,
) -> JsResult<Value> {
todo!();
// 1. Let result be the empty String.
// 2. For each element next of codeUnits, do
// a. Let nextCU be the code unit whose numeric value is ℝ(? ToUint16(next)).
// b. Set result to the string-concatenation of result and nextCU.
// 3. Return result.

if code_units.is_empty() {
return Ok(String::EMPTY_STRING.into_value());
}

// fast path: only a single valid code unit
if code_units.len() == 1 {
let cu = code_units.get(0).to_uint16(agent)?;
if let Some(cu) = char::from_u32(cu as u32) {
return Ok(SmallString::from(cu).into());
}
}

let mut buf = Vec::with_capacity(code_units.len());

for next in code_units.iter() {
let code_unit = next.to_uint16(agent)?;
buf.push(code_unit);
}
let result = std::string::String::from_utf16_lossy(&buf);

Ok(String::from_string(agent, result).into())
}

/// ### [22.1.2.2 String.fromCodePoint ( ...`codePoints` ) ](https://262.ecma-international.org/15.0/index.html#sec-string.fromcodepoint)
///
/// This function may be called with any number of arguments which form
/// the rest parameter `codePoints`.
fn from_code_point(
_agent: &mut Agent,
_this_value: Value,
_arguments: ArgumentsList,
) -> JsResult<Value> {
todo!();
// 1. Let result be the empty String.
// 2. For each element next of codePoints, do
// a. Let nextCP be ? ToNumber(next).
// b. If IsIntegralNumber(nextCP) is false, throw a RangeError exception.
// c. If ℝ(nextCP) < 0 or ℝ(nextCP) > 0x10FFFF, throw a RangeError exception.
// d. Set result to the string-concatenation of result and UTF16EncodeCodePoint(ℝ(nextCP)).
// 3. Assert: If codePoints is empty, then result is the empty String.
// 4. Return result.

todo!()
}

fn raw(_agent: &mut Agent, _this_value: Value, _arguments: ArgumentsList) -> JsResult<Value> {
Expand Down
10 changes: 9 additions & 1 deletion nova_vm/src/ecmascript/types/language/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::{
use crate::{
ecmascript::{
abstract_operations::type_conversion::{
to_big_int, to_int32, to_number, to_numeric, to_string, to_uint32,
to_big_int, to_int16, to_int32, to_number, to_numeric, to_string, to_uint16, to_uint32,
},
builtins::{
bound_function::BoundFunction,
Expand Down Expand Up @@ -443,6 +443,14 @@ impl Value {
to_uint32(agent, self)
}

pub fn to_int16(self, agent: &mut Agent) -> JsResult<i16> {
to_int16(agent, self)
}

pub fn to_uint16(self, agent: &mut Agent) -> JsResult<u16> {
to_uint16(agent, self)
}

pub fn to_string(self, agent: &mut Agent) -> JsResult<String> {
to_string(agent, self)
}
Expand Down
6 changes: 6 additions & 0 deletions small_string/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ impl TryFrom<&str> for SmallString {
}
}

impl From<char> for SmallString {
fn from(ch: char) -> Self {
Self::from_code_point(ch)
}
}

#[test]
fn valid_stack_strings() {
assert!(SmallString::try_from("").is_ok());
Expand Down
33 changes: 2 additions & 31 deletions tests/expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -6084,18 +6084,6 @@
"built-ins/SharedArrayBuffer/zero-length.js": "CRASH",
"built-ins/String/S15.5.5.1_A4_T1.js": "CRASH",
"built-ins/String/S9.8_A5_T1.js": "FAIL",
"built-ins/String/fromCharCode/S15.5.3.2_A1.js": "FAIL",
"built-ins/String/fromCharCode/S15.5.3.2_A2.js": "CRASH",
"built-ins/String/fromCharCode/S15.5.3.2_A3_T1.js": "CRASH",
"built-ins/String/fromCharCode/S15.5.3.2_A3_T2.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A1.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A2.1.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A2.2.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A3.1_T1.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A3.1_T2.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A3.1_T3.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A3.1_T4.js": "CRASH",
"built-ins/String/fromCharCode/S9.7_A3.2_T1.js": "CRASH",
"built-ins/String/fromCodePoint/argument-is-Symbol.js": "CRASH",
"built-ins/String/fromCodePoint/argument-is-not-integer.js": "CRASH",
"built-ins/String/fromCodePoint/argument-not-coercible.js": "CRASH",
Expand All @@ -6121,12 +6109,6 @@
"built-ins/String/prototype/includes/return-false-with-out-of-bounds-position.js": "FAIL",
"built-ins/String/prototype/includes/searchstring-is-regexp-throws.js": "FAIL",
"built-ins/String/prototype/includes/searchstring-not-found-with-position.js": "FAIL",
"built-ins/String/prototype/indexOf/S15.5.4.7_A5_T1.js": "CRASH",
"built-ins/String/prototype/indexOf/S15.5.4.7_A5_T2.js": "CRASH",
"built-ins/String/prototype/indexOf/S15.5.4.7_A5_T3.js": "CRASH",
"built-ins/String/prototype/indexOf/S15.5.4.7_A5_T4.js": "CRASH",
"built-ins/String/prototype/indexOf/S15.5.4.7_A5_T5.js": "CRASH",
"built-ins/String/prototype/indexOf/S15.5.4.7_A5_T6.js": "CRASH",
"built-ins/String/prototype/indexOf/searchstring-tostring-bigint.js": "FAIL",
"built-ins/String/prototype/isWellFormed/returns-boolean.js": "FAIL",
"built-ins/String/prototype/isWellFormed/to-string-primitive.js": "CRASH",
Expand Down Expand Up @@ -12843,8 +12825,8 @@
"language/block-scope/syntax/redeclaration/inner-block-var-redeclaration-attempt-after-function.js": "FAIL",
"language/block-scope/syntax/redeclaration/var-name-redeclaration-attempt-with-function.js": "FAIL",
"language/block-scope/syntax/redeclaration/var-redeclaration-attempt-after-function.js": "FAIL",
"language/comments/S7.4_A5.js": "CRASH",
"language/comments/S7.4_A6.js": "CRASH",
"language/comments/S7.4_A5.js": "TIMEOUT",
"language/comments/S7.4_A6.js": "TIMEOUT",
"language/comments/hashbang/eval-indirect.js": "FAIL",
"language/comments/hashbang/function-constructor.js": "CRASH",
"language/comments/hashbang/use-strict.js": "CRASH",
Expand Down Expand Up @@ -18931,17 +18913,6 @@
"language/literals/regexp/u-unicode-esc.js": "CRASH",
"language/literals/regexp/unicode-escape-nls-err.js": "FAIL",
"language/literals/regexp/y-assertion-start.js": "CRASH",
"language/literals/string/S7.8.4_A4.1_T1.js": "CRASH",
"language/literals/string/S7.8.4_A4.1_T2.js": "CRASH",
"language/literals/string/S7.8.4_A4.2_T1.js": "CRASH",
"language/literals/string/S7.8.4_A4.2_T3.js": "CRASH",
"language/literals/string/S7.8.4_A4.2_T5.js": "CRASH",
"language/literals/string/S7.8.4_A4.2_T7.js": "CRASH",
"language/literals/string/S7.8.4_A5.1_T1.js": "CRASH",
"language/literals/string/S7.8.4_A6.1_T1.js": "CRASH",
"language/literals/string/S7.8.4_A6.3_T1.js": "CRASH",
"language/literals/string/S7.8.4_A7.1_T1.js": "CRASH",
"language/literals/string/S7.8.4_A7.3_T1.js": "CRASH",
"language/literals/string/line-separator-eval.js": "FAIL",
"language/literals/string/mongolian-vowel-separator-eval.js": "FAIL",
"language/literals/string/paragraph-separator-eval.js": "FAIL",
Expand Down
6 changes: 3 additions & 3 deletions tests/metrics.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"results": {
"crash": 17208,
"fail": 7727,
"pass": 20082,
"crash": 17163,
"fail": 7741,
"pass": 20113,
"skip": 31,
"timeout": 3,
"unresolved": 0
Expand Down

0 comments on commit b9681f2

Please sign in to comment.