From 90c0304af5658872276d428742441b28b7a528f9 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 10 Feb 2024 20:50:49 -0500 Subject: [PATCH] Implement context --- src/abstract_tree/built_in_value.rs | 20 ++- src/abstract_tree/index.rs | 14 +- src/abstract_tree/index_assignment.rs | 2 +- src/abstract_tree/value_node.rs | 6 +- src/built_in_functions/mod.rs | 2 +- src/context.rs | 7 +- src/error/mod.rs | 8 +- src/lib.rs | 8 +- src/main.rs | 54 ++++--- src/value/map.rs | 197 ++++---------------------- src/value/mod.rs | 6 +- tests/for_loop.rs | 12 +- tests/format.rs | 8 +- tests/functions.rs | 4 +- tests/structure.rs | 8 +- tests/value.rs | 14 +- 16 files changed, 105 insertions(+), 265 deletions(-) diff --git a/src/abstract_tree/built_in_value.rs b/src/abstract_tree/built_in_value.rs index d0d8e1e..5bc4c35 100644 --- a/src/abstract_tree/built_in_value.rs +++ b/src/abstract_tree/built_in_value.rs @@ -114,12 +114,11 @@ impl BuiltInValue { let key = fs_function.name().to_string(); let value = Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function))); - let r#type = value.r#type(); - fs_context.insert(key, (value, r#type)); + fs_context.insert(key, value); } - Value::Map(Map::with_variables(fs_context)) + Value::Map(Map::with_values(fs_context)) }), BuiltInValue::Json => JSON.get_or_init(|| { let mut json_context = BTreeMap::new(); @@ -128,12 +127,11 @@ impl BuiltInValue { let key = json_function.name().to_string(); let value = Value::Function(Function::BuiltIn(BuiltInFunction::Json(json_function))); - let r#type = value.r#type(); - json_context.insert(key, (value, r#type)); + json_context.insert(key, value); } - Value::Map(Map::with_variables(json_context)) + Value::Map(Map::with_values(json_context)) }), BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)), BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)), @@ -148,12 +146,11 @@ impl BuiltInValue { ] { let key = built_in_function.name().to_string(); let value = Value::Function(Function::BuiltIn(built_in_function)); - let r#type = built_in_function.r#type(); - random_context.insert(key, (value, r#type)); + random_context.insert(key, value); } - Value::Map(Map::with_variables(random_context)) + Value::Map(Map::with_values(random_context)) }), BuiltInValue::Str => STRING.get_or_init(|| { let mut string_context = BTreeMap::new(); @@ -163,12 +160,11 @@ impl BuiltInValue { let value = Value::Function(Function::BuiltIn(BuiltInFunction::String( string_function, ))); - let r#type = string_function.r#type(); - string_context.insert(key, (value, r#type)); + string_context.insert(key, value); } - Value::Map(Map::with_variables(string_context)) + Value::Map(Map::with_values(string_context)) }), } } diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 36af7e1..987e10f 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -86,21 +86,13 @@ impl AbstractTree for Index { Value::Map(map) => { let (key, value) = if let IndexExpression::Identifier(identifier) = &self.index { let key = identifier.inner(); - let value = map - .variables()? - .get(key) - .map(|(value, _)| value.clone()) - .unwrap_or_default(); + let value = map.get(key).unwrap_or_default(); (key.clone(), value) } else { let index_value = self.index.run(source, context)?; let key = index_value.as_string()?; - let value = map - .variables()? - .get(key.as_str()) - .map(|(value, _)| value.clone()) - .unwrap_or_default(); + let value = map.get(key.as_str()).unwrap_or_default(); (key.clone(), value) }; @@ -108,7 +100,7 @@ impl AbstractTree for Index { if value.is_none() { Err(RuntimeError::VariableIdentifierNotFound(key)) } else { - Ok(value) + Ok(value.clone()) } } Value::String(string) => { diff --git a/src/abstract_tree/index_assignment.rs b/src/abstract_tree/index_assignment.rs index ab72c89..32e946d 100644 --- a/src/abstract_tree/index_assignment.rs +++ b/src/abstract_tree/index_assignment.rs @@ -43,7 +43,7 @@ impl AbstractTree for IndexAssignment { } fn run(&self, source: &str, context: &Context) -> Result { - let index_collection = self.index.collection.run(source, context)?; + let _index_collection = self.index.collection.run(source, context)?; let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index { identifier.inner() } else { diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index acbbd57..5a3ff38 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -242,7 +242,7 @@ impl AbstractTree for ValueNode { } } ValueNode::Map(statements, source_position) => { - for (key, (statement, r#type)) in statements { + for (_key, (statement, r#type)) in statements { if let Some(expected) = r#type { let actual = statement.expected_type(context)?; @@ -294,13 +294,13 @@ impl AbstractTree for ValueNode { Value::Option(option_value) } ValueNode::Map(key_statement_pairs, _) => { - let map = Map::new(); + let mut map = Map::new(); { for (key, (statement, _)) in key_statement_pairs { let value = statement.run(source, context)?; - map.set(key.clone(), value)?; + map.set(key.clone(), value); } } diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index 4008b05..600efba 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -111,7 +111,7 @@ impl Callable for BuiltInFunction { let length = if let Ok(list) = value.as_list() { list.items().len() } else if let Ok(map) = value.as_map() { - map.variables()?.len() + map.len() } else if let Ok(str) = value.as_string() { str.chars().count() } else { diff --git a/src/context.rs b/src/context.rs index c9929e1..8d82dfa 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,6 @@ use std::{ collections::HashMap, - sync::{Arc, RwLock}, + sync::{Arc, RwLock, RwLockReadGuard}, }; use crate::{error::rw_lock_error::RwLockError, Type, Value}; @@ -16,6 +16,7 @@ pub enum ValueData { }, } +#[derive(Clone)] pub struct Context { inner: Arc>>, } @@ -27,6 +28,10 @@ impl Context { } } + pub fn inner(&self) -> Result>, RwLockError> { + Ok(self.inner.read()?) + } + pub fn inherit_from(other: &Context) -> Result { let mut new_variables = HashMap::new(); diff --git a/src/error/mod.rs b/src/error/mod.rs index bca67be..7bec030 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -11,7 +11,7 @@ pub use runtime_error::RuntimeError; pub use syntax_error::SyntaxError; pub use validation_error::ValidationError; -use tree_sitter::{LanguageError, Point}; +use tree_sitter::LanguageError; use std::fmt::{self, Formatter}; @@ -69,11 +69,7 @@ impl fmt::Display for Error { Validation(error) => write!(f, "Validation error: {error}"), Runtime(error) => write!(f, "Runtime error: {error}"), ParserCancelled => write!(f, "Parsing was cancelled because the parser took too long."), - Language(error) => write!(f, "Parser failed to load language grammar."), + Language(_error) => write!(f, "Parser failed to load language grammar."), } } } - -fn get_position(position: &Point) -> String { - format!("column {}, row {}", position.row + 1, position.column) -} diff --git a/src/lib.rs b/src/lib.rs index 66976b4..e51ca42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,8 +5,12 @@ //! You can use this library externally by calling either of the "interpret" //! functions or by constructing your own Interpreter. pub use crate::{ - abstract_tree::*, built_in_functions::BuiltInFunction, context::Context, error::Error, - interpret::*, value::*, + abstract_tree::*, + built_in_functions::BuiltInFunction, + context::{Context, ValueData}, + error::Error, + interpret::*, + value::*, }; pub use tree_sitter::Node as SyntaxNode; diff --git a/src/main.rs b/src/main.rs index 688b4f9..018715f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use reedline::{ use std::{borrow::Cow, fs::read_to_string, path::PathBuf, process::Command}; -use dust_lang::{built_in_values, Error, Interpreter, Map, Value}; +use dust_lang::{built_in_values, Context, Error, Interpreter, Value, ValueData}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -50,11 +50,11 @@ fn main() { env_logger::init(); let args = Args::parse(); - let context = Map::new(); + let context = Context::new(); if let Some(input) = args.input { context - .set("input".to_string(), Value::string(input)) + .set_value("input".to_string(), Value::string(input)) .unwrap(); } @@ -62,7 +62,7 @@ fn main() { let file_contents = read_to_string(path).unwrap(); context - .set("input".to_string(), Value::string(file_contents)) + .set_value("input".to_string(), Value::string(file_contents)) .unwrap(); } @@ -117,11 +117,11 @@ fn main() { } struct DustHighlighter { - context: Map, + context: Context, } impl DustHighlighter { - fn new(context: Map) -> Self { + fn new(context: Context) -> Self { Self { context } } } @@ -130,36 +130,27 @@ const HIGHLIGHT_TERMINATORS: [char; 8] = [' ', ':', '(', ')', '{', '}', '[', ']' impl Highlighter for DustHighlighter { fn highlight(&self, line: &str, _cursor: usize) -> reedline::StyledText { - fn highlight_identifier(styled: &mut StyledText, word: &str, map: &Map) -> bool { - for (key, (value, _type)) in map.variables().unwrap().iter() { + let mut styled = StyledText::new(); + + for word in line.split_inclusive(&HIGHLIGHT_TERMINATORS) { + let mut word_is_highlighted = false; + + for key in self.context.inner().unwrap().keys() { if key == &word { styled.push((Style::new().bold(), word.to_string())); - - return true; } - if let Value::Map(nested_map) = value { - return highlight_identifier(styled, word, nested_map); - } + word_is_highlighted = true; } for built_in_value in built_in_values() { if built_in_value.name() == word { styled.push((Style::new().bold(), word.to_string())); - - return true; } + + word_is_highlighted = true; } - false - } - - let mut styled = StyledText::new(); - - for word in line.split_inclusive(&HIGHLIGHT_TERMINATORS) { - let word_is_highlighted = - highlight_identifier(&mut styled, &word[0..word.len() - 1], &self.context); - if word_is_highlighted { let final_char = word.chars().last().unwrap(); @@ -239,11 +230,11 @@ impl Prompt for StarshipPrompt { } pub struct DustCompleter { - context: Map, + context: Context, } impl DustCompleter { - fn new(context: Map) -> Self { + fn new(context: Context) -> Self { DustCompleter { context } } } @@ -302,7 +293,7 @@ impl Completer for DustCompleter { } if let Value::Map(map) = built_in_value.get() { - for (key, (value, _type)) in map.variables().unwrap().iter() { + for (key, value) in map.iter() { if key.contains(last_word) { suggestions.push(Suggestion { value: format!("{name}:{key}"), @@ -316,7 +307,12 @@ impl Completer for DustCompleter { } } - for (key, (value, _type)) in self.context.variables().unwrap().iter() { + for (key, value_data) in self.context.inner().unwrap().iter() { + let value = match value_data { + ValueData::Value { inner, .. } => inner, + ValueData::ExpectedType { .. } => continue, + }; + if key.contains(last_word) { suggestions.push(Suggestion { value: key.to_string(), @@ -332,7 +328,7 @@ impl Completer for DustCompleter { } } -fn run_shell(context: Map) -> Result<(), Error> { +fn run_shell(context: Context) -> Result<(), Error> { let mut interpreter = Interpreter::new(context.clone()); let mut keybindings = default_emacs_keybindings(); diff --git a/src/value/map.rs b/src/value/map.rs index 10763f8..8a1eb34 100644 --- a/src/value/map.rs +++ b/src/value/map.rs @@ -1,136 +1,73 @@ -use serde::{ - de::{MapAccess, Visitor}, - ser::SerializeMap, - Deserialize, Serialize, -}; +use serde::{Deserialize, Serialize}; use stanza::{ renderer::{console::Console, Renderer}, style::{HAlign, Styles}, table::{Row, Table}, }; use std::{ - cmp::Ordering, collections::BTreeMap, fmt::{self, Display, Formatter}, - marker::PhantomData, - sync::{Arc, RwLock, RwLockReadGuard}, }; -use crate::{error::rw_lock_error::RwLockError, value::Value, Structure, Type}; +use crate::value::Value; /// A collection dust variables comprised of key-value pairs. /// /// The inner value is a BTreeMap in order to allow VariableMap instances to be sorted and compared /// to one another. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Map { - variables: Arc>>, - structure: Option, + inner: BTreeMap, } impl Map { /// Creates a new instace. pub fn new() -> Self { Map { - variables: Arc::new(RwLock::new(BTreeMap::new())), - structure: None, + inner: BTreeMap::new(), } } - pub fn from_structure(structure: Structure) -> Self { - let mut variables = BTreeMap::new(); - - for (key, (value_option, r#type)) in structure.inner() { - variables.insert( - key.clone(), - ( - value_option.clone().unwrap_or(Value::none()), - r#type.clone(), - ), - ); - } - - Map { - variables: Arc::new(RwLock::new(variables)), - structure: Some(structure), - } + pub fn with_values(variables: BTreeMap) -> Self { + Map { inner: variables } } - pub fn with_variables(variables: BTreeMap) -> Self { - Map { - variables: Arc::new(RwLock::new(variables)), - structure: None, - } + pub fn len(&self) -> usize { + self.inner.len() } - pub fn clone_from(other: &Self) -> Result { - let mut new_map = BTreeMap::new(); - - for (key, (value, r#type)) in other.variables()?.iter() { - new_map.insert(key.clone(), (value.clone(), r#type.clone())); - } - - Ok(Map { - variables: Arc::new(RwLock::new(new_map)), - structure: other.structure.clone(), - }) + pub fn iter(&self) -> impl Iterator { + self.inner.iter() } - pub fn variables( - &self, - ) -> Result>, RwLockError> { - self.variables.read().map_err(|_| RwLockError) + pub fn get(&self, key: &str) -> Option<&Value> { + self.inner.get(key) } - pub fn set(&self, key: String, value: Value) -> Result, RwLockError> { - log::info!("Setting variable {key} = {value}"); - - let value_type = value.r#type(); - let previous = self - .variables - .write()? - .insert(key, (value, value_type.clone())); - - Ok(previous) - } - - pub fn set_type( - &self, - key: String, - r#type: Type, - ) -> Result, RwLockError> { - log::info!("Setting type {key} = {}", r#type); - - let previous = self - .variables - .write() - .map_err(|_| RwLockError)? - .insert(key, (Value::none(), r#type)); - - Ok(previous) + pub fn set(&mut self, key: String, value: Value) { + self.inner.insert(key, value); } pub fn as_text_table(&self) -> Table { - let variables = self.variables.read().unwrap().clone().into_iter(); let mut table = Table::with_styles(Styles::default().with(HAlign::Centred)); - for (key, (value, r#type)) in variables { + for (key, value) in &self.inner { if let Value::Map(map) = value { - table.push_row(Row::new( - Styles::default(), - vec![key.into(), map.as_text_table().into(), "".into()], - )); - } else if let Value::List(list) = value { table.push_row(Row::new( Styles::default(), vec![ key.into(), - list.as_text_table().into(), - r#type.to_string().into(), + map.as_text_table().into(), + "".to_string().into(), ], )); + } else if let Value::List(list) = value { + table.push_row(Row::new( + Styles::default(), + vec![key.into(), list.as_text_table().into()], + )); } else { - table.push_row([key, value.to_string(), r#type.to_string()]); + table.push_row([key, &value.to_string()]); }; } @@ -148,32 +85,6 @@ 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 { - Some(self.cmp(other)) - } -} - impl Display for Map { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let renderer = Console::default(); @@ -181,63 +92,3 @@ impl Display for Map { f.write_str(&renderer.render(&self.as_text_table())) } } - -impl Serialize for Map { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - let variables = self.variables.read().unwrap(); - let mut map = serializer.serialize_map(Some(variables.len()))?; - - for (key, (value, _type)) in variables.iter() { - map.serialize_entry(key, value)?; - } - - map.end() - } -} - -struct MapVisitor { - marker: PhantomData Map>, -} - -impl MapVisitor { - fn new() -> Self { - MapVisitor { - marker: PhantomData, - } - } -} - -impl<'de> Visitor<'de> for MapVisitor { - type Value = Map; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("key-value pairs") - } - - fn visit_map(self, mut access: M) -> std::result::Result - where - M: MapAccess<'de>, - { - let map = Map::new(); - - { - while let Some((key, value)) = access.next_entry::()? { - map.set(key, value).unwrap(); - } - } - - Ok(map) - } -} - -impl<'de> Deserialize<'de> for Map { - fn deserialize(deserializer: D) -> std::result::Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_any(MapVisitor::new()) - } -} diff --git a/src/value/mod.rs b/src/value/mod.rs index c9b9be2..3342ea6 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -82,7 +82,7 @@ impl Value { Value::Map(map) => { let mut identifier_types = Vec::new(); - for (key, (value, _)) in map.variables().unwrap().iter() { + for (key, value) in map.iter() { identifier_types.push(( Identifier::new(key.clone()), TypeSpecification::new(value.r#type()), @@ -858,10 +858,10 @@ impl<'de> Visitor<'de> for ValueVisitor { where M: MapAccess<'de>, { - let map = Map::new(); + let mut map = Map::new(); while let Some((key, value)) = access.next_entry::()? { - map.set(key, value).unwrap(); + map.set(key, value); } Ok(Value::Map(map)) diff --git a/tests/for_loop.rs b/tests/for_loop.rs index 44a774a..3a4bcec 100644 --- a/tests/for_loop.rs +++ b/tests/for_loop.rs @@ -92,10 +92,10 @@ fn modify_map() { ", ); - let map = Map::new(); + let mut map = Map::new(); - map.set("x".to_string(), Value::Integer(1)).unwrap(); - map.set("y".to_string(), Value::Integer(2)).unwrap(); + map.set("x".to_string(), Value::Integer(1)); + map.set("y".to_string(), Value::Integer(2)); assert_eq!(Ok(Value::Map(map)), result); } @@ -137,10 +137,10 @@ fn modify_map_values() { ", ); - let map = Map::new(); + let mut map = Map::new(); - map.set("x".to_string(), Value::Integer(1)).unwrap(); - map.set("y".to_string(), Value::Integer(2)).unwrap(); + map.set("x".to_string(), Value::Integer(1)); + map.set("y".to_string(), Value::Integer(2)); assert_eq!(Ok(Value::Map(map)), result); } diff --git a/tests/format.rs b/tests/format.rs index e7148f7..a42b610 100644 --- a/tests/format.rs +++ b/tests/format.rs @@ -2,7 +2,7 @@ use dust_lang::*; #[test] fn format_simple_program() { - let mut interpreter = Interpreter::new(Map::new()); + let mut interpreter = Interpreter::new(Context::new()); assert_eq!(interpreter.format("x=1"), Ok("x = 1\n".to_string())); } @@ -16,7 +16,7 @@ const FORMATTED_BLOCK: &str = "{ #[test] fn format_block() { - let mut interpreter = Interpreter::new(Map::new()); + let mut interpreter = Interpreter::new(Context::new()); assert_eq!( interpreter.format("{1 2 3}"), @@ -34,7 +34,7 @@ const FORMATTED_MAP: &str = "{ #[test] fn format_map() { - let mut interpreter = Interpreter::new(Map::new()); + let mut interpreter = Interpreter::new(Context::new()); assert_eq!( interpreter.format("{{x=1 y = 2}}"), @@ -49,7 +49,7 @@ const FORMATTED_FUNCTION: &str = "(x ) { #[test] fn format_function() { - let mut interpreter = Interpreter::new(Map::new()); + let mut interpreter = Interpreter::new(Context::new()); assert_eq!( interpreter.format("( x< int > ){x/2}"), Ok(FORMATTED_FUNCTION.to_string()) diff --git a/tests/functions.rs b/tests/functions.rs index 3734ae6..acb656f 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -89,9 +89,9 @@ fn function_context_captures_functions() { #[test] fn function_context_captures_structure_definitions() { - let map = Map::new(); + let mut map = Map::new(); - map.set("name".to_string(), Value::string("bob")).unwrap(); + map.set("name".to_string(), Value::string("bob")); assert_eq!( interpret( diff --git a/tests/structure.rs b/tests/structure.rs index 634e028..341ea84 100644 --- a/tests/structure.rs +++ b/tests/structure.rs @@ -17,7 +17,7 @@ fn simple_structure() { #[test] fn new_structure() { - let result = interpret( + let _result = interpret( " Coords = struct { x = 0.0 @@ -35,7 +35,9 @@ fn new_structure() { map.insert("x".to_string(), (Some(Value::Integer(0)), Type::Integer)); - let expected = Value::Map(Map::from_structure(Structure::new(map))); + // let expected = Value::Map(Map::from_structure(Structure::new(map))); - assert_eq!(Ok(expected), result); + // assert_eq!(Ok(expected), result); + + todo!() } diff --git a/tests/value.rs b/tests/value.rs index e9bcb4c..8ec6ef0 100644 --- a/tests/value.rs +++ b/tests/value.rs @@ -69,11 +69,10 @@ fn empty_list() { #[test] fn map() { - let map = Map::new(); + let mut map = Map::new(); - map.set("x".to_string(), Value::Integer(1)).unwrap(); - map.set("foo".to_string(), Value::string("bar".to_string())) - .unwrap(); + map.set("x".to_string(), Value::Integer(1)); + map.set("foo".to_string(), Value::string("bar".to_string())); assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map))); } @@ -85,11 +84,10 @@ fn empty_map() { #[test] fn map_types() { - let map = Map::new(); + let mut map = Map::new(); - map.set("x".to_string(), Value::Integer(1)).unwrap(); - map.set("foo".to_string(), Value::string("bar".to_string())) - .unwrap(); + map.set("x".to_string(), Value::Integer(1)); + map.set("foo".to_string(), Value::string("bar".to_string())); assert_eq!( interpret("{ x = 1, foo = 'bar' }"),