Skip to content

Commit

Permalink
Fix #331 "We only get Const::Num, never Const::Int" (#338)
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Apr 28, 2020
1 parent e0e17a8 commit 84b4da5
Show file tree
Hide file tree
Showing 17 changed files with 403 additions and 246 deletions.
4 changes: 2 additions & 2 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,11 +739,11 @@ pub fn find_index(this: &Value, args: &[Value], interpreter: &mut Interpreter) -
let result = interpreter.call(predicate_arg, &this_arg, arguments)?;

if result.is_true() {
return Ok(Gc::new(ValueData::Number(f64::from(i))));
return Ok(Gc::new(ValueData::Rational(f64::from(i))));
}
}

Ok(Gc::new(ValueData::Number(f64::from(-1))))
Ok(Gc::new(ValueData::Rational(f64::from(-1))))
}

/// `Array.prototype.fill( value[, start[, end]] )`
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/boolean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub fn to_boolean(value: &Value) -> Value {
match *value.deref().borrow() {
ValueData::Object(_) => to_value(true),
ValueData::String(ref s) if !s.is_empty() => to_value(true),
ValueData::Number(n) if n != 0.0 && !n.is_nan() => to_value(true),
ValueData::Rational(n) if n != 0.0 && !n.is_nan() => to_value(true),
ValueData::Integer(n) if n != 0 => to_value(true),
ValueData::Boolean(v) => to_value(v),
_ => to_value(false),
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/console/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn formatter_utf_8_checks() {
"Są takie chwile %dą %są tu%sów %привет%ź".to_string(),
)),
Gc::new(ValueData::Integer(123)),
Gc::new(ValueData::Number(1.23)),
Gc::new(ValueData::Rational(1.23)),
Gc::new(ValueData::String("ł".to_string())),
];
let res = formatter(&val);
Expand All @@ -60,7 +60,7 @@ fn formatter_trailing_format_leader_renders() {
fn formatter_float_format_works() {
let val = [
Gc::new(ValueData::String("%f".to_string())),
Gc::new(ValueData::Number(3.1415)),
Gc::new(ValueData::Rational(3.1415)),
];
let res = formatter(&val);
assert_eq!(res, "3.141500")
Expand Down
6 changes: 3 additions & 3 deletions boa/src/builtins/function/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ fn check_arguments_object() {
"#;

eprintln!("{}", forward(&mut engine, init));
let expected_return_val: f64 = 100.0;
let expected_return_val = 100;
let return_val = forward_val(&mut engine, "val").expect("value expected");
assert_eq!(return_val.is_double(), true);
assert_eq!(return_val.is_integer(), true);
assert_eq!(
from_value::<f64>(return_val).expect("Could not convert value to f64"),
from_value::<i32>(return_val).expect("Could not convert value to i32"),
expected_return_val
);
}
2 changes: 1 addition & 1 deletion boa/src/builtins/number/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn to_number(value: &Value) -> Value {
ValueData::Integer(i) => to_value(f64::from(i)),
ValueData::Object(ref o) => (o).deref().borrow().get_internal_slot("NumberData"),
ValueData::Null => to_value(0),
ValueData::Number(n) => to_value(n),
ValueData::Rational(n) => to_value(n),
ValueData::String(ref s) => match s.parse::<f64>() {
Ok(n) => to_value(n),
Err(_) => to_value(f64::NAN),
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ impl Object {
pub fn from(value: &Value) -> Result<Self, ()> {
match *value.deref().borrow() {
ValueData::Boolean(_) => Ok(Self::from_boolean(value)),
ValueData::Number(_) => Ok(Self::from_number(value)),
ValueData::Rational(_) => Ok(Self::from_number(value)),
ValueData::String(_) => Ok(Self::from_string(value)),
ValueData::Object(ref obj) => Ok(obj.borrow().clone()),
_ => Err(()),
Expand Down
54 changes: 34 additions & 20 deletions boa/src/builtins/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub enum ValueData {
/// `String` - A UTF-8 string, such as `"Hello, world"`
String(String),
/// `Number` - A 64-bit floating point number, such as `3.1415`
Number(f64),
Rational(f64),
/// `Number` - A 32-bit integer, such as `42`
Integer(i32),
/// `Object` - An object, such as `Math`, represented by a binary tree of string keys to Javascript values
Expand Down Expand Up @@ -150,7 +150,21 @@ impl ValueData {
/// Returns true if the value is a 64-bit floating-point number
pub fn is_double(&self) -> bool {
match *self {
Self::Number(_) => true,
Self::Rational(_) => true,
_ => false,
}
}

/// Returns true if the value is integer.
#[allow(clippy::float_cmp)]
pub fn is_integer(&self) -> bool {
// If it can fit in a i32 and the trucated version is
// equal to the original then it is an integer.
let is_racional_intiger = |n: f64| n == ((n as i32) as f64);

match *self {
Self::Integer(_) => true,
Self::Rational(n) if is_racional_intiger(n) => true,
_ => false,
}
}
Expand Down Expand Up @@ -183,7 +197,7 @@ impl ValueData {
match *self {
Self::Object(_) => true,
Self::String(ref s) if !s.is_empty() => true,
Self::Number(n) if n != 0.0 && !n.is_nan() => true,
Self::Rational(n) if n != 0.0 && !n.is_nan() => true,
Self::Integer(n) if n != 0 => true,
Self::Boolean(v) => v,
_ => false,
Expand All @@ -198,9 +212,9 @@ impl ValueData {
Ok(num) => num,
Err(_) => NAN,
},
Self::Number(num) => num,
Self::Rational(num) => num,
Self::Boolean(true) => 1.0,
Self::Boolean(false) | Self::Null => 0.0,
Self::Boolean(false) | ValueData::Null => 0.0,
Self::Integer(num) => f64::from(num),
}
}
Expand All @@ -218,7 +232,7 @@ impl ValueData {
Ok(num) => num,
Err(_) => 0,
},
Self::Number(num) => num as i32,
Self::Rational(num) => num as i32,
Self::Boolean(true) => 1,
Self::Integer(num) => num,
}
Expand Down Expand Up @@ -556,7 +570,7 @@ impl ValueData {
pub fn from_json(json: JSONValue) -> Self {
match json {
JSONValue::Number(v) => {
Self::Number(v.as_f64().expect("Could not convert value to f64"))
Self::Rational(v.as_f64().expect("Could not convert value to f64"))
}
JSONValue::String(v) => Self::String(v),
JSONValue::Bool(v) => Self::Boolean(v),
Expand Down Expand Up @@ -607,7 +621,7 @@ impl ValueData {
JSONValue::Object(new_obj)
}
Self::String(ref str) => JSONValue::String(str.clone()),
Self::Number(num) => JSONValue::Number(
Self::Rational(num) => JSONValue::Number(
JSONNumber::from_f64(num).expect("Could not convert to JSONNumber"),
),
Self::Integer(val) => JSONValue::Number(JSONNumber::from(val)),
Expand All @@ -619,7 +633,7 @@ impl ValueData {
/// https://tc39.es/ecma262/#sec-typeof-operator
pub fn get_type(&self) -> &'static str {
match *self {
Self::Number(_) | Self::Integer(_) => "number",
Self::Rational(_) | Self::Integer(_) => "number",
Self::String(_) => "string",
Self::Boolean(_) => "boolean",
Self::Symbol(_) => "symbol",
Expand All @@ -637,7 +651,7 @@ impl ValueData {
}

pub fn as_num_to_power(&self, other: Self) -> Self {
Self::Number(self.to_num().powf(other.to_num()))
Self::Rational(self.to_num().powf(other.to_num()))
}
}

Expand Down Expand Up @@ -847,7 +861,7 @@ impl Display for ValueData {
_ => write!(f, "Symbol()"),
},
Self::String(ref v) => write!(f, "{}", v),
Self::Number(v) => write!(
Self::Rational(v) => write!(
f,
"{}",
match v {
Expand Down Expand Up @@ -884,9 +898,9 @@ impl PartialEq for ValueData {
_ if self.is_null_or_undefined() && other.is_null_or_undefined() => true,
(Self::String(_), _) | (_, Self::String(_)) => self.to_string() == other.to_string(),
(Self::Boolean(a), Self::Boolean(b)) if a == b => true,
(Self::Number(a), Self::Number(b)) if a == b && !a.is_nan() && !b.is_nan() => true,
(Self::Number(a), _) if a == other.to_num() => true,
(_, Self::Number(a)) if a == self.to_num() => true,
(Self::Rational(a), Self::Rational(b)) if a == b && !a.is_nan() && !b.is_nan() => true,
(Self::Rational(a), _) if a == other.to_num() => true,
(_, Self::Rational(a)) if a == self.to_num() => true,
(Self::Integer(a), Self::Integer(b)) if a == b => true,
_ => false,
}
Expand All @@ -901,32 +915,32 @@ impl Add for ValueData {
Self::String(format!("{}{}", s.clone(), &o.to_string()))
}
(ref s, Self::String(ref o)) => Self::String(format!("{}{}", s.to_string(), o)),
(ref s, ref o) => Self::Number(s.to_num() + o.to_num()),
(ref s, ref o) => Self::Rational(s.to_num() + o.to_num()),
}
}
}
impl Sub for ValueData {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self::Number(self.to_num() - other.to_num())
Self::Rational(self.to_num() - other.to_num())
}
}
impl Mul for ValueData {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self::Number(self.to_num() * other.to_num())
Self::Rational(self.to_num() * other.to_num())
}
}
impl Div for ValueData {
type Output = Self;
fn div(self, other: Self) -> Self {
Self::Number(self.to_num() / other.to_num())
Self::Rational(self.to_num() / other.to_num())
}
}
impl Rem for ValueData {
type Output = Self;
fn rem(self, other: Self) -> Self {
Self::Number(self.to_num() % other.to_num())
Self::Rational(self.to_num() % other.to_num())
}
}
impl BitAnd for ValueData {
Expand Down Expand Up @@ -1027,7 +1041,7 @@ impl FromValue for char {

impl ToValue for f64 {
fn to_value(&self) -> Value {
Gc::new(ValueData::Number(*self))
Gc::new(ValueData::Rational(*self))
}
}
impl FromValue for f64 {
Expand Down
10 changes: 5 additions & 5 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ impl Executor for Interpreter {
ValueData::Symbol(_) => "symbol",
ValueData::Null | ValueData::Object(_) => "object",
ValueData::Boolean(_) => "boolean",
ValueData::Number(_) | ValueData::Integer(_) => "number",
ValueData::Rational(_) | ValueData::Integer(_) => "number",
ValueData::String(_) => "string",
ValueData::Function(_) => "function",
}))
Expand Down Expand Up @@ -728,7 +728,7 @@ impl Interpreter {
ValueData::Undefined => to_value("undefined"),
ValueData::Null => to_value("null"),
ValueData::Boolean(ref boolean) => to_value(boolean.to_string()),
ValueData::Number(ref num) => to_value(num.to_string()),
ValueData::Rational(ref num) => to_value(num.to_string()),
ValueData::Integer(ref num) => to_value(num.to_string()),
ValueData::String(ref string) => to_value(string.clone()),
ValueData::Object(_) => {
Expand Down Expand Up @@ -759,7 +759,7 @@ impl Interpreter {
bool_obj.set_internal_slot("BooleanData", value.clone());
Ok(bool_obj)
}
ValueData::Number(_) => {
ValueData::Rational(_) => {
let proto = self
.realm
.environment
Expand Down Expand Up @@ -788,7 +788,7 @@ impl Interpreter {
match *value.deref().borrow() {
ValueData::Null => String::from("null"),
ValueData::Boolean(ref boolean) => boolean.to_string(),
ValueData::Number(ref num) => num.to_string(),
ValueData::Rational(ref num) => num.to_string(),
ValueData::Integer(ref num) => num.to_string(),
ValueData::String(ref string) => string.clone(),
ValueData::Object(_) => {
Expand All @@ -809,7 +809,7 @@ impl Interpreter {
f64::from(0)
}
}
ValueData::Number(num) => num,
ValueData::Rational(num) => num,
ValueData::Integer(num) => f64::from(num),
ValueData::String(ref string) => string.parse::<f64>().unwrap(),
ValueData::Object(_) => {
Expand Down
36 changes: 32 additions & 4 deletions boa/src/syntax/ast/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ impl Debug for VecToken {
}
}

/// Represents the type differenct types of numeric literals.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum NumericLiteral {
/// A floating point number
Rational(f64),

/// An integer
Integer(i32),
// TODO: Add BigInt
}

impl From<f64> for NumericLiteral {
fn from(n: f64) -> Self {
Self::Rational(n)
}
}

impl From<i32> for NumericLiteral {
fn from(n: i32) -> Self {
Self::Integer(n)
}
}

/// Represents the type of Token and the data it has inside.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, PartialEq, Debug)]
Expand All @@ -78,7 +102,7 @@ pub enum TokenKind {
NullLiteral,

/// A numeric literal.
NumericLiteral(f64),
NumericLiteral(NumericLiteral),

/// A piece of punctuation
///
Expand Down Expand Up @@ -138,8 +162,11 @@ impl TokenKind {
}

/// Creates a `NumericLiteral` token kind.
pub fn numeric_literal(lit: f64) -> Self {
Self::NumericLiteral(lit)
pub fn numeric_literal<L>(lit: L) -> Self
where
L: Into<NumericLiteral>,
{
Self::NumericLiteral(lit.into())
}

/// Creates a `Punctuator` token type.
Expand Down Expand Up @@ -178,7 +205,8 @@ impl Display for TokenKind {
Self::Identifier(ref ident) => write!(f, "{}", ident),
Self::Keyword(ref word) => write!(f, "{}", word),
Self::NullLiteral => write!(f, "null"),
Self::NumericLiteral(ref num) => write!(f, "{}", num),
Self::NumericLiteral(NumericLiteral::Rational(num)) => write!(f, "{}", num),
Self::NumericLiteral(NumericLiteral::Integer(num)) => write!(f, "{}", num),
Self::Punctuator(ref punc) => write!(f, "{}", punc),
Self::StringLiteral(ref lit) => write!(f, "{}", lit),
Self::RegularExpressionLiteral(ref body, ref flags) => write!(f, "/{}/{}", body, flags),
Expand Down
Loading

0 comments on commit 84b4da5

Please sign in to comment.