mirror of
https://github.com/danog/parser.git
synced 2025-01-22 13:01:32 +01:00
wip
This commit is contained in:
parent
aa2a6c8507
commit
7134db9472
@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "trunk_gc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
@ -1,31 +0,0 @@
|
||||
# Notes
|
||||
|
||||
```rust
|
||||
pub enum PhpValue {
|
||||
Int(i64),
|
||||
Array(Vec<GBox<PhpValue>>)
|
||||
}
|
||||
|
||||
impl Trace<Self> for PhpValue {
|
||||
fn trace(&self, tracer: Tracer) {
|
||||
match self {
|
||||
Self::Array(items) => {
|
||||
for item in items {
|
||||
item.trace(tracer);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut gc: Gc<PhpValue> = Gc::new();
|
||||
|
||||
let one = gc.hold(PhpValue::Int(1));
|
||||
|
||||
gc.root(PhpValue::Array(vec![
|
||||
one,
|
||||
]));
|
||||
|
||||
gc.collect();
|
||||
```
|
@ -1,91 +0,0 @@
|
||||
use std::{collections::{HashSet, HashMap}, hash::Hash};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Gc<T> {
|
||||
sweep: usize,
|
||||
heap: HashSet<GBox<T>>,
|
||||
roots: HashMap<GBox<T>, Rc<()>>,
|
||||
}
|
||||
|
||||
impl<T> Gc<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
sweep: 0,
|
||||
heap: HashSet::default(),
|
||||
roots: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hold(&mut self, value: T) -> GBox<T> {
|
||||
let ptr = Box::into_raw(Box::new(value));
|
||||
let gbox = GBox { ptr };
|
||||
|
||||
self.heap.insert(gbox);
|
||||
gbox
|
||||
}
|
||||
|
||||
pub fn get(&self, gbox: GBox<T>) -> Option<&T> {
|
||||
if self.heap.contains(&gbox) {
|
||||
Some(unsafe { &*gbox.ptr })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, gbox: GBox<T>) -> Option<&mut T> {
|
||||
if self.heap.contains(&gbox) {
|
||||
Some(unsafe { &mut *gbox.ptr })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root(&mut self, value: T) -> GRoot<T> {
|
||||
let gbox = self.hold(value);
|
||||
let rc = Rc::new(());
|
||||
|
||||
self.roots.insert(gbox, rc);
|
||||
|
||||
GRoot { gbox }
|
||||
}
|
||||
|
||||
pub fn collect(&mut self) {
|
||||
let sweep = self.sweep + 1;
|
||||
|
||||
for gbox in &self.heap {
|
||||
|
||||
}
|
||||
|
||||
self.sweep = sweep;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GRoot<T> {
|
||||
gbox: GBox<T>,
|
||||
}
|
||||
|
||||
pub struct GBox<T> {
|
||||
ptr: *mut T,
|
||||
}
|
||||
|
||||
impl<T> PartialEq for GBox<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ptr == other.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for GBox<T> {}
|
||||
|
||||
impl<T> Clone for GBox<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { ptr: self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for GBox<T> {}
|
||||
|
||||
impl<T> Hash for GBox<T> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.ptr.hash(state);
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
#[allow(dead_code, unused_variables)]
|
||||
|
||||
mod gc;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::gc::{Gc, GBox};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Foo {
|
||||
pub i: i64,
|
||||
}
|
||||
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
println!("I'm being dropped!");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_returns_a_gbox() {
|
||||
let mut gc: Gc<Foo> = Gc::new();
|
||||
|
||||
assert!(matches!(gc.hold(Foo { i: 100 }), GBox { .. }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_retrieve_the_value_of_a_gbox() {
|
||||
let mut gc: Gc<Foo> = Gc::new();
|
||||
|
||||
let my_gbox = gc.hold(Foo { i: 100 });
|
||||
|
||||
assert_eq!(gc.get(my_gbox), Some(&Foo { i: 100 }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_return_a_mutable_ref_to_a_gbox_value() {
|
||||
let mut gc: Gc<Foo> = Gc::new();
|
||||
|
||||
let my_gbox = gc.hold(Foo { i: 100 });
|
||||
(*gc.get_mut(my_gbox).unwrap()).i = 200;
|
||||
|
||||
assert_eq!(gc.get(my_gbox), Some(&Foo { i: 200 }));
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "trunk_interner"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
@ -1,18 +0,0 @@
|
||||
# Interner
|
||||
|
||||
This crate provides a simple string interner through the `Interner` structure. This structure allows you to retrieve a unique `Symbol` to a `&str`.
|
||||
|
||||
## Usage
|
||||
|
||||
```rust
|
||||
use trunk_interner::{Interner, Symbol};
|
||||
|
||||
fn main() {
|
||||
let mut interner = Interner::default();
|
||||
|
||||
let my_string_symbol: Symbol = interner.intern("Hello, world!");
|
||||
let my_original_string: &str = interner.get(my_string_symbol);
|
||||
}
|
||||
```
|
||||
|
||||
If a `&str` is interned multiple times, the same `Symbol` will be returned, in theory minimizing the amount of memory used by your program due to a reduced number of `String` allocations.
|
@ -1,62 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A wrapper-type pointing to a unique string in the [`Interner`].
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct Symbol(u32);
|
||||
|
||||
/// The unoptimized singleton used for interning strings.
|
||||
///
|
||||
/// The structure uses a standard `HashMap` to map strings to indexes,
|
||||
/// where those indexes point to a `String` inside of a `Vec<String>`.
|
||||
///
|
||||
/// The design of the interner isn't optimal right now since each
|
||||
/// intern results into 2 allocations.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Interner {
|
||||
map: HashMap<String, u32>,
|
||||
storage: Vec<String>,
|
||||
}
|
||||
|
||||
impl Interner {
|
||||
/// Intern a `&str` and retrieve a unique [`Symbol`].
|
||||
pub fn intern(&mut self, name: &str) -> Symbol {
|
||||
if let Some(&index) = self.map.get(name) {
|
||||
return Symbol(index);
|
||||
}
|
||||
|
||||
let index = self.map.len() as u32;
|
||||
|
||||
self.map.insert(name.to_string(), index);
|
||||
self.storage.push(name.to_string());
|
||||
|
||||
Symbol(index)
|
||||
}
|
||||
|
||||
/// Retrieve tyhe `&str` for a given [`Symbol`].
|
||||
pub fn get(&self, symbol: Symbol) -> &str {
|
||||
self.storage[symbol.0 as usize].as_str()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Interner, Symbol};
|
||||
|
||||
|
||||
#[test]
|
||||
fn it_can_intern_a_string() {
|
||||
let mut interner = Interner::default();
|
||||
|
||||
assert_eq!(interner.intern("Hello, world!"), Symbol(0));
|
||||
assert_eq!(interner.intern("Hello, world!"), Symbol(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_retrieve_an_interned_string() {
|
||||
let mut interner = Interner::default();
|
||||
let symbol = interner.intern("Hello, world!");
|
||||
|
||||
assert_eq!(interner.get(symbol), "Hello, world!");
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "trunk_value"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
indexmap = "1.9.1"
|
@ -1,43 +0,0 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use crate::{PhpValue, TypeError};
|
||||
|
||||
impl Add for PhpValue {
|
||||
type Output = Result<Self, TypeError>;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Ok(match (&self, &rhs) {
|
||||
(Self::Int(a), Self::Int(b)) => Self::Int(a + b),
|
||||
(Self::Float(a), Self::Float(b)) => Self::Float(a + b),
|
||||
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
|
||||
Self::Float(a + *b as f64)
|
||||
},
|
||||
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
|
||||
if a.parse::<i64>().is_ok() {
|
||||
Self::Int(a.parse::<i64>().unwrap() + b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "+", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
|
||||
if a.parse::<f64>().is_ok() {
|
||||
Self::Float(a.parse::<f64>().unwrap() + b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "+", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
(Self::Array(a), Self::Array(b)) => {
|
||||
let mut a_clone = a.clone();
|
||||
for (key, value) in b {
|
||||
if a_clone.contains_key(key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
a_clone.insert(key.clone(), value.clone());
|
||||
}
|
||||
Self::Array(a_clone)
|
||||
},
|
||||
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "+", rhs: rhs.inspect_type() })
|
||||
})
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
use std::ops::Div;
|
||||
|
||||
use crate::{PhpValue, TypeError};
|
||||
|
||||
impl Div for PhpValue {
|
||||
type Output = Result<Self, TypeError>;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Ok(match (&self, &rhs) {
|
||||
(Self::Int(a), Self::Int(b)) => Self::Int(a / b),
|
||||
(Self::Float(a), Self::Float(b)) => Self::Float(a / b),
|
||||
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
|
||||
Self::Float(a / *b as f64)
|
||||
},
|
||||
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
|
||||
if a.parse::<i64>().is_ok() {
|
||||
Self::Int(a.parse::<i64>().unwrap() / b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "/", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
|
||||
if a.parse::<f64>().is_ok() {
|
||||
Self::Float(a.parse::<f64>().unwrap() / b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "/", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "/", rhs: rhs.inspect_type() })
|
||||
})
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
mod value;
|
||||
mod add;
|
||||
mod sub;
|
||||
mod mul;
|
||||
mod div;
|
||||
mod rem;
|
||||
mod type_error;
|
||||
|
||||
pub use value::*;
|
||||
pub use type_error::TypeError;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::PhpValue;
|
||||
|
||||
#[test]
|
||||
fn values_can_be_added() {
|
||||
assert_eq!(PhpValue::Int(1) + PhpValue::Int(2), Ok(PhpValue::Int(3)));
|
||||
assert_eq!(PhpValue::Float(1.5) + PhpValue::Float(2.5), Ok(PhpValue::Float(4.0)));
|
||||
assert_eq!(PhpValue::Float(1.5) + PhpValue::Int(1), Ok(PhpValue::Float(2.5)));
|
||||
assert_eq!(PhpValue::Int(1) + PhpValue::Float(1.5), Ok(PhpValue::Float(2.5)));
|
||||
assert_eq!(PhpValue::String("1".into()) + PhpValue::Int(1), Ok(PhpValue::Int(2)));
|
||||
assert_eq!(PhpValue::String("1".into()) + PhpValue::Float(1.0), Ok(PhpValue::Float(2.0)));
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
use std::ops::Mul;
|
||||
|
||||
use crate::{PhpValue, TypeError};
|
||||
|
||||
impl Mul for PhpValue {
|
||||
type Output = Result<Self, TypeError>;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Ok(match (&self, &rhs) {
|
||||
(Self::Int(a), Self::Int(b)) => Self::Int(a * b),
|
||||
(Self::Float(a), Self::Float(b)) => Self::Float(a * b),
|
||||
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
|
||||
Self::Float(a * *b as f64)
|
||||
},
|
||||
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
|
||||
if a.parse::<i64>().is_ok() {
|
||||
Self::Int(a.parse::<i64>().unwrap() * b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "*", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
|
||||
if a.parse::<f64>().is_ok() {
|
||||
Self::Float(a.parse::<f64>().unwrap() * b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "*", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "*", rhs: rhs.inspect_type() })
|
||||
})
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
use std::ops::Rem;
|
||||
|
||||
use crate::{PhpValue, TypeError};
|
||||
|
||||
impl Rem for PhpValue {
|
||||
type Output = Result<Self, TypeError>;
|
||||
|
||||
fn rem(self, rhs: Self) -> Self::Output {
|
||||
Ok(match (&self, &rhs) {
|
||||
(Self::Int(a), Self::Int(b)) => Self::Int(a % b),
|
||||
(Self::Float(a), Self::Float(b)) => Self::Float(a % b),
|
||||
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
|
||||
Self::Float(a % *b as f64)
|
||||
},
|
||||
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
|
||||
if a.parse::<i64>().is_ok() {
|
||||
Self::Int(a.parse::<i64>().unwrap() % b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "%", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
|
||||
if a.parse::<f64>().is_ok() {
|
||||
Self::Float(a.parse::<f64>().unwrap() % b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "%", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "%", rhs: rhs.inspect_type() })
|
||||
})
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
use std::ops::Sub;
|
||||
|
||||
use crate::{PhpValue, TypeError};
|
||||
|
||||
impl Sub for PhpValue {
|
||||
type Output = Result<Self, TypeError>;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Ok(match (&self, &rhs) {
|
||||
(Self::Int(a), Self::Int(b)) => Self::Int(a - b),
|
||||
(Self::Float(a), Self::Float(b)) => Self::Float(a - b),
|
||||
(Self::Float(a), Self::Int(b)) | (Self::Int(b), Self::Float(a)) => {
|
||||
Self::Float(a - *b as f64)
|
||||
},
|
||||
(Self::String(a), Self::Int(b)) | (Self::Int(b), Self::String(a)) => {
|
||||
if a.parse::<i64>().is_ok() {
|
||||
Self::Int(a.parse::<i64>().unwrap() - b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "-", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
(Self::String(a), Self::Float(b)) | (Self::Float(b), Self::String(a)) => {
|
||||
if a.parse::<f64>().is_ok() {
|
||||
Self::Float(a.parse::<f64>().unwrap() - b)
|
||||
} else {
|
||||
return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "-", rhs: rhs.inspect_type() })
|
||||
}
|
||||
},
|
||||
_ => return Err(TypeError::UnsupportedOperandTypes { lhs: self.inspect_type(), op: "-", rhs: rhs.inspect_type() })
|
||||
})
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum TypeError {
|
||||
UnsupportedOperandTypes {
|
||||
lhs: String,
|
||||
op: &'static str,
|
||||
rhs: String,
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
use indexmap::IndexMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum PhpValue {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
String(String),
|
||||
Array(Array),
|
||||
}
|
||||
|
||||
pub type Array = IndexMap<ArrayKey, PhpValue>;
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub enum ArrayKey {
|
||||
Int(i64),
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl PhpValue {
|
||||
pub fn inspect_type(&self) -> String {
|
||||
match self {
|
||||
Self::Int(_) => "int".into(),
|
||||
Self::Float(_) => "float".into(),
|
||||
Self::String(_) => "string".into(),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user