Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #331 "We only get Const::Num, never Const::Int" #338

Merged
merged 1 commit into from
Apr 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Razican marked this conversation as resolved.
Show resolved Hide resolved
}

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