Skip to content

Commit

Permalink
Add support for regex literals (boa-dev#94)
Browse files Browse the repository at this point in the history
* Implement regex literal lexing

* Add parser support for regex literals

* Implement very basic RegExp object

* Fix escaping a backslash

* Store rust structs as internal state in objects

* Remove unnecessary regexp constant

* Implement RegExp.test()

* Implement properties on RegExp

* Implement RegExp.exec()

* Implement RegExp.toString()

* Rename RegularExpression to RegularExpressionLiteral
  • Loading branch information
999eagle authored and jasonwilliams committed Sep 3, 2019
1 parent 6d81538 commit 5e7df4f
Show file tree
Hide file tree
Showing 12 changed files with 694 additions and 24 deletions.
37 changes: 37 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ gc_derive = "0.3.2"
serde_json = "1.0.40"
rand = "0.7.0"
chrono = "0.4.7"
regex = "^1.2"

# Optional Dependencies
wasm-bindgen = { version = "0.2.47", optional = true }
Expand All @@ -33,4 +34,4 @@ path = "src/lib/lib.rs"

[[bench]]
name = "string"
harness = false
harness = false
4 changes: 2 additions & 2 deletions src/lib/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
function::{Function, RegularFunction},
json, math, object,
object::{ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE},
string,
regexp, string,
value::{from_value, to_value, ResultValue, Value, ValueData},
},
syntax::ast::{
Expand Down Expand Up @@ -58,7 +58,6 @@ impl Executor for Interpreter {
// Do Const values need to be garbage collected? We no longer need them once we've generated Values
ExprDef::Const(Const::String(ref str)) => Ok(to_value(str.to_owned())),
ExprDef::Const(Const::Bool(val)) => Ok(to_value(val)),
ExprDef::Const(Const::RegExp(_, _, _)) => Ok(to_value(None::<()>)),
ExprDef::Block(ref es) => {
let mut obj = to_value(None::<()>);
for e in es.iter() {
Expand Down Expand Up @@ -390,6 +389,7 @@ impl InterpreterBuilder {
array::init(&global);
function::init(&global);
json::init(&global);
regexp::init(&global);
string::init(&global);

Self { global }
Expand Down
2 changes: 2 additions & 0 deletions src/lib/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub mod json;
pub mod math;
/// The global `Object` object
pub mod object;
/// The global 'RegExp' object
pub mod regexp;
/// The global `String` object
pub mod string;
/// Javascript values, utility methods and conversion between Javascript values and Rust values
Expand Down
14 changes: 12 additions & 2 deletions src/lib/js/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ use gc::Gc;
use gc_derive::{Finalize, Trace};
use std::{borrow::Borrow, collections::HashMap, ops::Deref};

/// Static `prototype`, usually set on constructors as a key to point to their respective prototype object.
pub use internal_state::{InternalState, InternalStateCell};

mod internal_state;

/// Static `prototype`, usually set on constructors as a key to point to their respective prototype object.
pub static PROTOTYPE: &str = "prototype";

/// Static `__proto__`, usually set on Object instances as a key to point to their respective prototype object.
/// Static `__proto__`, usually set on Object instances as a key to point to their respective prototype object.
pub static INSTANCE_PROTOTYPE: &str = "__proto__";

/// `ObjectData` is the representation of an object in JavaScript
Expand All @@ -27,6 +31,8 @@ pub struct Object {
pub properties: Box<HashMap<String, Property>>,
/// Symbol Properties
pub sym_properties: Box<HashMap<usize, Property>>,
/// Some rust object that stores internal state
pub state: Option<Box<InternalStateCell>>,
}

impl Object {
Expand All @@ -37,6 +43,7 @@ impl Object {
internal_slots: Box::new(HashMap::new()),
properties: Box::new(HashMap::new()),
sym_properties: Box::new(HashMap::new()),
state: None,
}
}

Expand All @@ -47,6 +54,7 @@ impl Object {
internal_slots: Box::new(HashMap::new()),
properties: Box::new(HashMap::new()),
sym_properties: Box::new(HashMap::new()),
state: None,
};

obj.internal_slots
Expand All @@ -61,6 +69,7 @@ impl Object {
internal_slots: Box::new(HashMap::new()),
properties: Box::new(HashMap::new()),
sym_properties: Box::new(HashMap::new()),
state: None,
};

obj.internal_slots
Expand All @@ -75,6 +84,7 @@ impl Object {
internal_slots: Box::new(HashMap::new()),
properties: Box::new(HashMap::new()),
sym_properties: Box::new(HashMap::new()),
state: None,
};

obj.internal_slots
Expand Down
64 changes: 64 additions & 0 deletions src/lib/js/object/internal_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//! Implementations for storing normal rust structs inside any object as internal state.
use std::{
any::Any,
fmt::{self, Debug},
ops::{Deref, DerefMut},
rc::Rc,
};

use gc::{unsafe_empty_trace, Finalize, Trace};

/// Wrapper around `Rc` to implement `Trace` and `Finalize`.
#[derive(Clone)]
pub struct InternalStateCell {
/// The internal state.
state: Rc<dyn Any>,
}

impl Finalize for InternalStateCell {}

unsafe impl Trace for InternalStateCell {
unsafe_empty_trace!();
}

impl Deref for InternalStateCell {
type Target = dyn Any;
fn deref(&self) -> &Self::Target {
Deref::deref(&self.state)
}
}

impl DerefMut for InternalStateCell {
fn deref_mut(&mut self) -> &mut Self::Target {
Rc::get_mut(&mut self.state).expect("failed to get mutable")
}
}

/// The derived version would print 'InternalStateCell { state: ... }', this custom implementation
/// only prints the actual internal state.
impl Debug for InternalStateCell {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.state, f)
}
}

impl InternalStateCell {
/// Create new `InternalStateCell` from a value.
pub fn new<T: Any + InternalState>(value: T) -> Self {
Self {
state: Rc::new(value),
}
}
/// Get a reference to the stored value and cast it to `T`.
pub fn downcast_ref<T: Any + InternalState>(&self) -> Option<&T> {
self.deref().downcast_ref::<T>()
}
/// Get a mutable reference to the stored value and cast it to `T`.
pub fn downcast_mut<T: Any + InternalState>(&mut self) -> Option<&mut T> {
self.deref_mut().downcast_mut::<T>()
}
}

/// This trait must be implemented by all structs used for internal state.
pub trait InternalState: Debug {}
Loading

0 comments on commit 5e7df4f

Please sign in to comment.