Skip to content

Commit

Permalink
Merge d23c657 into 91bece6
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Apr 24, 2020
2 parents 91bece6 + d23c657 commit 6f8c46c
Show file tree
Hide file tree
Showing 12 changed files with 454 additions and 252 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 @@ -630,11 +630,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 @@ -72,7 +72,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
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 @@ -27,7 +27,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 @@ -359,7 +359,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
52 changes: 33 additions & 19 deletions boa/src/builtins/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,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 @@ -140,7 +140,21 @@ impl ValueData {
/// Returns true if the value is a 64-bit floating-point number
pub fn is_double(&self) -> bool {
match *self {
ValueData::Number(_) => true,
ValueData::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 {
ValueData::Integer(_) => true,
ValueData::Rational(n) if is_racional_intiger(n) => true,
_ => false,
}
}
Expand Down Expand Up @@ -172,7 +186,7 @@ impl ValueData {
match *self {
ValueData::Object(_) => true,
ValueData::String(ref s) if !s.is_empty() => true,
ValueData::Number(n) if n != 0.0 && !n.is_nan() => true,
ValueData::Rational(n) if n != 0.0 && !n.is_nan() => true,
ValueData::Integer(n) if n != 0 => true,
ValueData::Boolean(v) => v,
_ => false,
Expand All @@ -190,7 +204,7 @@ impl ValueData {
Ok(num) => num,
Err(_) => NAN,
},
ValueData::Number(num) => num,
ValueData::Rational(num) => num,
ValueData::Boolean(true) => 1.0,
ValueData::Boolean(false) | ValueData::Null => 0.0,
ValueData::Integer(num) => f64::from(num),
Expand All @@ -210,7 +224,7 @@ impl ValueData {
Ok(num) => num,
Err(_) => 0,
},
ValueData::Number(num) => num as i32,
ValueData::Rational(num) => num as i32,
ValueData::Boolean(true) => 1,
ValueData::Integer(num) => num,
}
Expand Down Expand Up @@ -545,7 +559,7 @@ impl ValueData {
pub fn from_json(json: JSONValue) -> Self {
match json {
JSONValue::Number(v) => {
ValueData::Number(v.as_f64().expect("Could not convert value to f64"))
ValueData::Rational(v.as_f64().expect("Could not convert value to f64"))
}
JSONValue::String(v) => ValueData::String(v),
JSONValue::Bool(v) => ValueData::Boolean(v),
Expand Down Expand Up @@ -595,7 +609,7 @@ impl ValueData {
JSONValue::Object(new_obj)
}
ValueData::String(ref str) => JSONValue::String(str.clone()),
ValueData::Number(num) => JSONValue::Number(
ValueData::Rational(num) => JSONValue::Number(
JSONNumber::from_f64(num).expect("Could not convert to JSONNumber"),
),
ValueData::Integer(val) => JSONValue::Number(JSONNumber::from(val)),
Expand All @@ -606,7 +620,7 @@ impl ValueData {
/// https://tc39.es/ecma262/#sec-typeof-operator
pub fn get_type(&self) -> &'static str {
match *self {
ValueData::Number(_) | ValueData::Integer(_) => "number",
ValueData::Rational(_) | ValueData::Integer(_) => "number",
ValueData::String(_) => "string",
ValueData::Boolean(_) => "boolean",
ValueData::Symbol(_) => "symbol",
Expand All @@ -624,7 +638,7 @@ impl ValueData {
}

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

Expand Down Expand Up @@ -834,7 +848,7 @@ impl Display for ValueData {
_ => write!(f, "Symbol()"),
},
ValueData::String(ref v) => write!(f, "{}", v),
ValueData::Number(v) => write!(
ValueData::Rational(v) => write!(
f,
"{}",
match v {
Expand Down Expand Up @@ -873,13 +887,13 @@ impl PartialEq for ValueData {
self.to_string() == other.to_string()
}
(ValueData::Boolean(a), ValueData::Boolean(b)) if a == b => true,
(ValueData::Number(a), ValueData::Number(b))
(ValueData::Rational(a), ValueData::Rational(b))
if a == b && !a.is_nan() && !b.is_nan() =>
{
true
}
(ValueData::Number(a), _) if a == other.to_num() => true,
(_, ValueData::Number(a)) if a == self.to_num() => true,
(ValueData::Rational(a), _) if a == other.to_num() => true,
(_, ValueData::Rational(a)) if a == self.to_num() => true,
(ValueData::Integer(a), ValueData::Integer(b)) if a == b => true,
_ => false,
}
Expand All @@ -896,32 +910,32 @@ impl Add for ValueData {
(ref s, ValueData::String(ref o)) => {
ValueData::String(format!("{}{}", s.to_string(), o))
}
(ref s, ref o) => ValueData::Number(s.to_num() + o.to_num()),
(ref s, ref o) => ValueData::Rational(s.to_num() + o.to_num()),
}
}
}
impl Sub for ValueData {
type Output = Self;
fn sub(self, other: Self) -> Self {
ValueData::Number(self.to_num() - other.to_num())
ValueData::Rational(self.to_num() - other.to_num())
}
}
impl Mul for ValueData {
type Output = Self;
fn mul(self, other: Self) -> Self {
ValueData::Number(self.to_num() * other.to_num())
ValueData::Rational(self.to_num() * other.to_num())
}
}
impl Div for ValueData {
type Output = Self;
fn div(self, other: Self) -> Self {
ValueData::Number(self.to_num() / other.to_num())
ValueData::Rational(self.to_num() / other.to_num())
}
}
impl Rem for ValueData {
type Output = Self;
fn rem(self, other: Self) -> Self {
ValueData::Number(self.to_num() % other.to_num())
ValueData::Rational(self.to_num() % other.to_num())
}
}
impl BitAnd for ValueData {
Expand Down Expand Up @@ -1022,7 +1036,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 @@ -534,7 +534,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 @@ -726,7 +726,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 @@ -757,7 +757,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 @@ -786,7 +786,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 @@ -807,7 +807,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
64 changes: 58 additions & 6 deletions boa/src/syntax/ast/token.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
//! This module implements the Token structure used in the JavaScript programing language.
use crate::syntax::ast::{keyword::Keyword, pos::Position, punc::Punctuator};
use std::fmt::{Debug, Display, Formatter, Result};

#[cfg(feature = "serde-ast")]
use serde::{Deserialize, Serialize};

/// Represents a token.
/// This represents the smallest individual words, phrases, or characters that JavaScript can understand.
#[cfg_attr(feature = "serde-ast", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub struct Token {
/// The token Data
/// The token kind, which contains the actual data of the token.
pub kind: TokenKind,
/// Token position from original source code

/// The token position from origina source code.
pub pos: Position,
}

Expand All @@ -30,6 +33,7 @@ impl Display for Token {
}
}

/// A continuous sequence of tokens.
pub struct VecToken(Vec<Token>);

impl Debug for VecToken {
Expand All @@ -42,32 +46,79 @@ impl Debug for VecToken {
}
}

/// Represents the type differenct types of numeric literals.
#[cfg_attr(feature = "serde-ast", 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-ast", derive(Serialize, Deserialize))]
#[derive(Clone, PartialEq, Debug)]
pub enum TokenKind {
/// A boolean literal, which is either `true` or `false`
BooleanLiteral(bool),

/// The end of the file
EOF,

/// An identifier
Identifier(String),
/// A keyword

/// A keyword.
///
/// see: [`Keyword`](../keyword/enum.Keyword.html)
Keyword(Keyword),

/// A `null` literal
NullLiteral,

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

/// A piece of punctuation
///
/// see: [`Punctuator`](../punc/enum.Punctuator.html)
Punctuator(Punctuator),

/// A string literal
StringLiteral(String),

/// A regular expression, consisting of body and flags
RegularExpressionLiteral(String, String),

/// Indicates the end of a line \n
LineTerminator,
}

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

impl Display for TokenKind {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match *self {
Expand All @@ -76,7 +127,8 @@ impl Display for TokenKind {
TokenKind::Identifier(ref ident) => write!(f, "{}", ident),
TokenKind::Keyword(ref word) => write!(f, "{}", word),
TokenKind::NullLiteral => write!(f, "null"),
TokenKind::NumericLiteral(ref num) => write!(f, "{}", num),
TokenKind::NumericLiteral(NumericLiteral::Rational(num)) => write!(f, "{}", num),
TokenKind::NumericLiteral(NumericLiteral::Integer(num)) => write!(f, "{}", num),
TokenKind::Punctuator(ref punc) => write!(f, "{}", punc),
TokenKind::StringLiteral(ref lit) => write!(f, "{}", lit),
TokenKind::RegularExpressionLiteral(ref body, ref flags) => {
Expand Down
Loading

0 comments on commit 6f8c46c

Please sign in to comment.