Add reference counting for map values

This commit is contained in:
Jeff 2023-10-26 16:00:06 -04:00
parent 86499367fc
commit a5390c5150
4 changed files with 97 additions and 25 deletions

View File

@ -1,4 +1,4 @@
//! Command line interface for the whale programming language.
//! Command line interface for the dust programming language.
use clap::Parser;
use rustyline::{
completion::FilenameCompleter,
@ -17,10 +17,18 @@ use dust_lang::{evaluate, evaluate_with_context, Map, Value};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Whale source code to evaluate.
/// Dust source code to evaluate.
#[arg(short, long)]
command: Option<String>,
/// Data to assign to the "input" variable.
#[arg(short, long)]
input: Option<String>,
/// A path to file whose contents will be assigned to the "input" variable.
#[arg(short = 'p', long)]
input_path: Option<String>,
/// Location of the file to run.
path: Option<String>,
}
@ -32,12 +40,22 @@ fn main() {
return run_cli_shell();
}
let mut context = Map::new();
if let Some(path) = args.input_path {
let file_contents = read_to_string(path).unwrap();
context
.set_value("input".to_string(), Value::String(file_contents))
.unwrap();
}
let eval_result = if let Some(path) = args.path {
let file_contents = read_to_string(path).unwrap();
evaluate(&file_contents)
evaluate_with_context(&file_contents, &mut context)
} else if let Some(command) = args.command {
evaluate(&command)
evaluate_with_context(&command, &mut context)
} else {
Ok(Value::Empty)
};

View File

@ -1,7 +1,12 @@
use rayon::collections::btree_map;
use reqwest::header::ACCESS_CONTROL_EXPOSE_HEADERS;
use serde::{Deserialize, Serialize};
use std::{
cmp::Ordering,
collections::BTreeMap,
fmt::{self, Display, Formatter},
marker::PhantomData,
sync::{Arc, RwLock, RwLockReadGuard},
};
use crate::{value::Value, Error, Result, Table};
@ -10,30 +15,32 @@ use crate::{value::Value, Error, Result, Table};
///
/// The inner value is a BTreeMap in order to allow VariableMap instances to be sorted and compared
/// to one another.
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Deserialize)]
#[derive(Clone, Debug)]
pub struct Map {
variables: BTreeMap<String, Value>,
variables: Arc<RwLock<BTreeMap<String, Value>>>,
}
impl Map {
/// Creates a new instace.
pub fn new() -> Self {
Map {
variables: BTreeMap::new(),
variables: Arc::new(RwLock::new(BTreeMap::new())),
}
}
/// Returns a Value assigned to the identifer, allowing dot notation to retrieve Values that are /// nested in Lists or Maps. Returns None if there is no variable with a key matching the /// identifier. Returns an error if a Map or List is indexed incorrectly.
pub fn get_value(&self, identifier: &str) -> Result<Option<Value>> {
let variables = self.variables.read().unwrap();
let split = identifier.rsplit_once('.');
let (found_value, next_identifier) = if let Some((identifier, next_identifier)) = split {
if identifier.contains('.') {
(self.get_value(identifier)?, next_identifier)
} else {
(self.variables.get(identifier).cloned(), next_identifier)
(variables.get(identifier).cloned(), next_identifier)
}
} else {
return Ok(self.variables.get(identifier).cloned());
return Ok(variables.get(identifier).cloned());
};
if let Some(value) = found_value {
@ -63,7 +70,8 @@ impl Map {
let split = key.split_once('.');
if let Some((identifier, next_identifier)) = split {
let get_value = self.variables.get_mut(identifier);
let mut variables = self.variables.write().unwrap();
let get_value = variables.get_mut(identifier);
if let Some(found_value) = get_value {
if let Value::List(list) = found_value {
@ -97,12 +105,17 @@ impl Map {
new_map.set_value(next_identifier.to_string(), value)?;
self.variables
.write()
.unwrap()
.insert(identifier.to_string(), Value::Map(new_map));
Ok(())
}
} else {
self.variables.insert(key.to_string(), value);
self.variables
.write()
.unwrap()
.insert(key.to_string(), value);
Ok(())
}
@ -112,22 +125,22 @@ impl Map {
///
/// TODO: Support dot notation.
pub fn remove(&mut self, key: &str) -> Option<Value> {
self.variables.remove(key)
self.variables.write().unwrap().remove(key)
}
/// Returns a reference to the inner BTreeMap.
pub fn inner(&self) -> &BTreeMap<String, Value> {
&self.variables
pub fn inner(&self) -> Arc<RwLock<BTreeMap<String, Value>>> {
Arc::clone(&self.variables)
}
/// Returns the number of stored variables.
pub fn len(&self) -> usize {
self.variables.len()
self.variables.read().unwrap().len()
}
/// Returns true if the length is zero.
pub fn is_empty(&self) -> bool {
self.variables.is_empty()
self.variables.read().unwrap().is_empty()
}
}
@ -137,10 +150,42 @@ impl Default for Map {
}
}
impl Eq for Map {}
impl PartialEq for Map {
fn eq(&self, other: &Self) -> bool {
let left = self.variables.read().unwrap().clone().into_iter();
let right = other.variables.read().unwrap().clone().into_iter();
left.eq(right)
}
}
impl Ord for Map {
fn cmp(&self, other: &Self) -> Ordering {
let left = self.variables.read().unwrap().clone().into_iter();
let right = other.variables.read().unwrap().clone().into_iter();
left.cmp(right)
}
}
impl PartialOrd for Map {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let left = self.variables.read().unwrap().clone().into_iter();
let right = other.variables.read().unwrap().clone().into_iter();
left.partial_cmp(right)
}
}
impl Display for Map {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{{\n")?;
for (key, value) in &self.variables {
let variables = self.variables.read().unwrap().clone().into_iter();
for (key, value) in variables {
write!(f, " {key} = {value}\n")?;
}
write!(f, "}}")

View File

@ -282,8 +282,10 @@ impl From<&mut Vec<Value>> for Table {
impl From<Map> for Table {
fn from(map: Map) -> Self {
let keys = map.inner().keys().cloned().collect();
let values = map.inner().values().cloned().collect();
let inner_map = map.inner();
let read_map = inner_map.read().unwrap();
let keys = read_map.keys().cloned().collect();
let values = read_map.values().cloned().collect();
let mut table = Table::new(keys);
table
@ -296,8 +298,10 @@ impl From<Map> for Table {
impl From<&Map> for Table {
fn from(map: &Map) -> Self {
let keys = map.inner().keys().cloned().collect();
let values = map.inner().values().cloned().collect();
let inner_map = map.inner();
let read_map = inner_map.read().unwrap();
let keys = read_map.keys().cloned().collect();
let values = read_map.values().cloned().collect();
let mut table = Table::new(keys);
table
@ -310,8 +314,10 @@ impl From<&Map> for Table {
impl From<&mut Map> for Table {
fn from(map: &mut Map) -> Self {
let keys = map.inner().keys().cloned().collect();
let values = map.inner().values().cloned().collect();
let inner_map = map.inner();
let read_map = inner_map.read().unwrap();
let keys = read_map.keys().cloned().collect();
let values = read_map.values().cloned().collect();
let mut table = Table::new(keys);
table

View File

@ -113,8 +113,11 @@ impl From<&Value> for ValueType {
Value::Map(map) => {
let mut value_nodes = BTreeMap::new();
for (key, value) in map.inner() {
let value_type = ValueType::from(value);
let inner_map = map.inner().clone();
let read_map = inner_map.read().unwrap();
for (key, value) in read_map.clone() {
let value_type = value.value_type();
let value_node = ValueNode::new(value_type, 0, 0);
let expression = Expression::Value(value_node);