Browse Source

added support for String.prototype.charAt()

pull/18/head
Jason Williams 5 years ago
parent
commit
64ab7b0133
  1. 1
      src/lib/js/object.rs
  2. 23
      src/lib/js/string.rs
  3. 12
      src/lib/syntax/lexer.rs
  4. 2
      tests/js/test.js

1
src/lib/js/object.rs

@ -6,6 +6,7 @@ use std::collections::HashMap;
/// Static `prototype`, usually set on constructors as a key to point to their respective prototype object.
/// As this string will be used a lot throughout the program, its best being a static global string which will be referenced
pub static PROTOTYPE: &'static str = "prototype";
/// Static `__proto__`, usually set on Object instances as a key to point to their respective prototype object.
/// As this string will be used a lot throughout the program, its best being a static global string which will be referenced
pub static INSTANCE_PROTOTYPE: &'static str = "__proto__";

23
src/lib/js/string.rs

@ -30,6 +30,28 @@ pub fn to_string(this: Value, _: Value, _: Vec<Value>) -> ResultValue {
Ok(to_value(format!("{}", primitive_val).to_string()))
}
// Get the character at the supplied index
// https://tc39.github.io/ecma262/#sec-string.prototype.charat
pub fn char_at(this: Value, _: Value, args: Vec<Value>) -> ResultValue {
// ^^ represents instance ^^ represents arguments (we only care about the first one in this case)
// First we get it the actual string a private field stored on the object only the engine has access to.
// Then we convert it into a Rust String by wrapping it in from_value
let primitive_val: String =
from_value(this.get_private_field(String::from("PrimitiveValue"))).unwrap();
let pos = from_value(args[0].clone()).unwrap();
// Calling .len() on a string would give the wrong result, as they are bytes not the number of unicode code points
// Note that this is an O(N) operation (because UTF-8 is complex) while getting the number of bytes is an O(1) operation.
let length = primitive_val.chars().count();
// We should return an empty string is pos is out of range
if pos > length || pos < 0 as usize {
return Ok(to_value::<String>(String::new()));
}
Ok(to_value::<char>(primitive_val.chars().nth(pos).unwrap()))
}
/// Create a new `String` object
pub fn _create(global: Value) -> Value {
let string = to_value(make_string as NativeFunctionData);
@ -43,6 +65,7 @@ pub fn _create(global: Value) -> Value {
set: Gc::new(ValueData::Undefined),
};
proto.set_prop_slice("length", prop);
proto.set_field_slice("charAt", to_value(char_at as NativeFunctionData));
proto.set_field_slice("toString", to_value(to_string as NativeFunctionData));
string.set_field_slice(PROTOTYPE, proto);
string

12
src/lib/syntax/lexer.rs

@ -284,6 +284,7 @@ impl<'a> Lexer<'a> {
}
u64::from_str_radix(&buf, 16).unwrap()
} else {
let mut gone_decimal = false;
loop {
let ch = self.preview_next()?;
match ch {
@ -292,13 +293,22 @@ impl<'a> Lexer<'a> {
self.next()?;
}
'8' | '9' | '.' => {
gone_decimal = true;
buf.push(ch);
self.next()?;
}
_ => break,
}
}
u64::from_str_radix(&buf, 8).unwrap()
if gone_decimal {
u64::from_str(&buf).unwrap()
} else {
if buf.is_empty() {
0
} else {
u64::from_str_radix(&buf, 8).unwrap()
}
}
};
self.push_token(TokenData::NumericLiteral(num as f64))
}

2
tests/js/test.js

@ -1,2 +1,2 @@
var a = new String("test");
a.toString();
a.charAt(9);

Loading…
Cancel
Save