From de3e998808dc64c4dd21c8850109fdceac7fb60f Mon Sep 17 00:00:00 2001 From: mStar aka a person <12024604-mstarongitlab@users.noreply.gitlab.com> Date: Thu, 25 Jan 2024 11:50:00 +0100 Subject: [PATCH] Add base types Implement JsNumber --- .gitignore | 1 + Cargo.lock | 53 +++++++++++++ Cargo.toml | 10 +++ TODO.md | 31 ++++++++ src/data_types/array.rs | 6 ++ src/data_types/big_int.rs | 6 ++ src/data_types/bool.rs | 12 +++ src/data_types/mod.rs | 27 +++++++ src/data_types/number.rs | 158 ++++++++++++++++++++++++++++++++++++++ src/data_types/object.rs | 6 ++ src/data_types/string.rs | 6 ++ src/data_types/symbol.rs | 4 + src/lib.rs | 2 + 13 files changed, 322 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 TODO.md create mode 100644 src/data_types/array.rs create mode 100644 src/data_types/big_int.rs create mode 100644 src/data_types/bool.rs create mode 100644 src/data_types/mod.rs create mode 100644 src/data_types/number.rs create mode 100644 src/data_types/object.rs create mode 100644 src/data_types/string.rs create mode 100644 src/data_types/symbol.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..55eda8d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,53 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "capibara-engine" +version = "0.1.0" +dependencies = [ + "num-bigint", + "widestring", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c05457d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "capibara-engine" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +num-bigint = "0.4.4" +widestring = "1.0.2" diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..cdad26c --- /dev/null +++ b/TODO.md @@ -0,0 +1,31 @@ +# Todos + +## Stage 1 + +- [ ] Js interpreter (for [EMCA Script 2023](https://tc39.es/ecma262/2023)) + - [ ] Js into token stream/tree + - [ ] Stack handling + - [ ] Token stream/tree interpretation + +## Stage 2 + +- [ ] Update interpreter to latest stable ECMA script version + +## Stage 3 + +- [ ] Deep type tracing + +## Stage 4 + +- [ ] Typscript support + +## Stage 5 + +- [ ] Precompile as much as possible + +## Stage 6 + +- [ ] Profit? + +## Comments +- Have to add wasm somewhere \ No newline at end of file diff --git a/src/data_types/array.rs b/src/data_types/array.rs new file mode 100644 index 0000000..c8eca42 --- /dev/null +++ b/src/data_types/array.rs @@ -0,0 +1,6 @@ +use super::VariableContent; + +#[derive(Debug)] +pub struct JsArray { + pub values: Vec +} \ No newline at end of file diff --git a/src/data_types/big_int.rs b/src/data_types/big_int.rs new file mode 100644 index 0000000..bfab22f --- /dev/null +++ b/src/data_types/big_int.rs @@ -0,0 +1,6 @@ +use num_bigint::BigInt; + +#[derive(Debug)] +pub struct JsBigInt { + pub value: BigInt +} \ No newline at end of file diff --git a/src/data_types/bool.rs b/src/data_types/bool.rs new file mode 100644 index 0000000..dd3f0f5 --- /dev/null +++ b/src/data_types/bool.rs @@ -0,0 +1,12 @@ +#[derive(Debug)] +pub struct JsBool { + pub value: bool +} + +pub const TRUE: JsBool = JsBool{ + value: true, +}; + +pub const FALSE: JsBool = JsBool{ + value: false, +}; \ No newline at end of file diff --git a/src/data_types/mod.rs b/src/data_types/mod.rs new file mode 100644 index 0000000..e326412 --- /dev/null +++ b/src/data_types/mod.rs @@ -0,0 +1,27 @@ +use self::{big_int::JsBigInt, bool::JsBool, number::JsNumber, object::JsObject, string::JsString, symbol::JsSymbol}; + +pub mod bool; +pub mod string; +pub mod symbol; +pub mod number; +pub mod big_int; +pub mod object; +pub mod array; + +#[derive(Debug, Default)] +pub enum VariableContent { + #[default] + Undefined, + Null, + Value(ValueType), +} + +#[derive(Debug)] +pub enum ValueType { + Bool(JsBool), + String(JsString), + Symbol(JsSymbol), + Number(JsNumber), + BigInt(JsBigInt), + Object(JsObject), +} \ No newline at end of file diff --git a/src/data_types/number.rs b/src/data_types/number.rs new file mode 100644 index 0000000..9620aae --- /dev/null +++ b/src/data_types/number.rs @@ -0,0 +1,158 @@ +use super::{bool::JsBool, string::JsString}; +use widestring::{utf16str, Utf16String}; + +#[derive(Debug, Clone, Copy)] +pub struct JsNumber { + pub value: f64 +} + +pub const NAN: JsNumber = JsNumber{ + value: f64::NAN, +}; + +// Implements https://tc39.es/ecma262/2023/#table-numeric-type-ops +impl JsNumber { + pub fn unary_minus(&self) -> JsNumber { + jsnum_math_op(&self, &self, |x, _| -x) + } + + pub fn bitwise_not(&self) -> JsNumber { + jsnum_math_op(&self, &self, |x, _| !i64::from(x.floor() as i64) as f64) + } + + pub fn exponentiate(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| x.powf(*y)) + } + + pub fn multiply(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| x * y) + } + + pub fn divide(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| x % y) + } + + pub fn add(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| x + y) + } + + pub fn pre_add(&mut self) -> JsNumber { + return if self.value.is_nan() { + return NAN.clone() + } else { + self.value += 1.0; + self.clone() + } + } + + pub fn post_add(&mut self) -> JsNumber { + return if self.value.is_nan() { + return NAN.clone() + } else { + let old = self.clone(); + self.value += 1.0; + old + } + } + + pub fn subtract(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| x - y) + } + + pub fn pre_subtract(&mut self) -> JsNumber { + return if self.value.is_nan() { + return NAN.clone() + } else { + self.value -= 1.0; + self.clone() + } + } + + pub fn post_subtract(&mut self) -> JsNumber { + return if self.value.is_nan() { + return NAN.clone() + } else { + let old = self.clone(); + self.value -= 1.0; + old + } + } + + pub fn left_shift(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| ((x.floor() as i64) << (y.floor() as i64)) as f64) + } + + pub fn right_shift_signed(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| ((x.floor() as i64) >> (y.floor() as i64)) as f64) + } + + pub fn right_shift_unsigned(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| (((x.floor() as i64) as u64) >> (y.floor() as i64)) as f64) + } + + pub fn less_than(&self, x: &JsNumber) -> JsBool { + jsnum_comp_op(&self, &x, |x, y| x < y) + } + + pub fn equal(&self, x: &JsNumber) -> JsBool { + jsnum_comp_op(&self, &x, |x, y| x == y) + } + + pub fn same_value(&self, x: &JsNumber) -> JsBool { + JsBool { value: std::ptr::eq(self, x) } + } + + pub fn bitwise_and(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| ((x.floor() as i64) & (y.floor() as i64)) as f64) + } + + pub fn bitwise_xor(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| ((x.floor() as i64) ^ (y.floor() as i64)) as f64) + } + + pub fn bitwise_or(&self, x: &JsNumber) -> JsNumber { + jsnum_math_op(&self, &x, |x, y| ((x.floor() as i64) | (y.floor() as i64)) as f64) + } + + pub fn to_string(&self) -> JsString { + if self.value.is_infinite() { + JsString{ + value: utf16str!("Infinity").to_owned() + } + } else if self.value.is_nan() { + JsString{ + value: utf16str!("NaN").to_owned() + } + } else { + JsString{ + value: Utf16String::from_str(&self.value.to_string()) + } + } + } +} + +fn jsnum_math_op(x: &JsNumber, y: &JsNumber, f: F) -> JsNumber where + F: Fn(&f64, &f64) -> f64 +{ + if x.value.is_nan() || y.value.is_nan() { + NAN.clone() + } else { + let value = f(&x.value, &y.value); + JsNumber{ + value + } + } +} + +fn jsnum_comp_op(x: &JsNumber, y: &JsNumber, f: F) -> JsBool where + F: Fn(&f64, &f64) -> bool +{ + if x.value.is_nan() || y.value.is_nan() { + super::bool::FALSE + } else { + let value = f(&x.value, &y.value); + JsBool{ + value + } + } +} \ No newline at end of file diff --git a/src/data_types/object.rs b/src/data_types/object.rs new file mode 100644 index 0000000..ec409e9 --- /dev/null +++ b/src/data_types/object.rs @@ -0,0 +1,6 @@ +use std::collections::HashMap; + +#[derive(Debug)] +pub struct JsObject { + pub value: HashMap +} \ No newline at end of file diff --git a/src/data_types/string.rs b/src/data_types/string.rs new file mode 100644 index 0000000..082529d --- /dev/null +++ b/src/data_types/string.rs @@ -0,0 +1,6 @@ +use widestring::Utf16String; + +#[derive(Debug)] +pub struct JsString { + pub value: Utf16String, +} \ No newline at end of file diff --git a/src/data_types/symbol.rs b/src/data_types/symbol.rs new file mode 100644 index 0000000..c86d43c --- /dev/null +++ b/src/data_types/symbol.rs @@ -0,0 +1,4 @@ +#[derive(Debug)] +pub struct JsSymbol { + pub value: f64, // TODO: Understand what symbol is and turn this into a representation for those +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..442f3c0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +mod data_types; +