Implement context

This commit is contained in:
Jeff 2024-02-10 20:50:49 -05:00
parent d997bbd08a
commit 90c0304af5
16 changed files with 105 additions and 265 deletions

View File

@ -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))
}),
}
}

View File

@ -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) => {

View File

@ -43,7 +43,7 @@ impl AbstractTree for IndexAssignment {
}
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
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 {

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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<RwLock<HashMap<String, ValueData>>>,
}
@ -27,6 +28,10 @@ impl Context {
}
}
pub fn inner(&self) -> Result<RwLockReadGuard<HashMap<String, ValueData>>, RwLockError> {
Ok(self.inner.read()?)
}
pub fn inherit_from(other: &Context) -> Result<Context, RwLockError> {
let mut new_variables = HashMap::new();

View File

@ -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)
}

View File

@ -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;

View File

@ -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;
}
}
false
word_is_highlighted = true;
}
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();

View File

@ -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<RwLock<BTreeMap<String, (Value, Type)>>>,
structure: Option<Structure>,
inner: BTreeMap<String, Value>,
}
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(),
),
);
pub fn with_values(variables: BTreeMap<String, Value>) -> Self {
Map { inner: variables }
}
Map {
variables: Arc::new(RwLock::new(variables)),
structure: Some(structure),
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn with_variables(variables: BTreeMap<String, (Value, Type)>) -> Self {
Map {
variables: Arc::new(RwLock::new(variables)),
structure: None,
}
pub fn iter(&self) -> impl Iterator<Item = (&String, &Value)> {
self.inner.iter()
}
pub fn clone_from(other: &Self) -> Result<Self, RwLockError> {
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()));
pub fn get(&self, key: &str) -> Option<&Value> {
self.inner.get(key)
}
Ok(Map {
variables: Arc::new(RwLock::new(new_map)),
structure: other.structure.clone(),
})
}
pub fn variables(
&self,
) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>, RwLockError> {
self.variables.read().map_err(|_| RwLockError)
}
pub fn set(&self, key: String, value: Value) -> Result<Option<(Value, Type)>, 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<Option<(Value, Type)>, 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<Ordering> {
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<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
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<fn() -> 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<M>(self, mut access: M) -> std::result::Result<Map, M::Error>
where
M: MapAccess<'de>,
{
let map = Map::new();
{
while let Some((key, value)) = access.next_entry::<String, Value>()? {
map.set(key, value).unwrap();
}
}
Ok(map)
}
}
impl<'de> Deserialize<'de> for Map {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(MapVisitor::new())
}
}

View File

@ -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::<String, Value>()? {
map.set(key, value).unwrap();
map.set(key, value);
}
Ok(Value::Map(map))

View File

@ -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);
}

View File

@ -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 <int> = 2}}"),
@ -49,7 +49,7 @@ const FORMATTED_FUNCTION: &str = "(x <int>) <num> {
#[test]
fn format_function() {
let mut interpreter = Interpreter::new(Map::new());
let mut interpreter = Interpreter::new(Context::new());
assert_eq!(
interpreter.format("( x< int > )<num>{x/2}"),
Ok(FORMATTED_FUNCTION.to_string())

View File

@ -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(

View File

@ -17,7 +17,7 @@ fn simple_structure() {
#[test]
fn new_structure() {
let result = interpret(
let _result = interpret(
"
Coords = struct {
x <float> = 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!()
}

View File

@ -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 <int> = 1, foo <str> = 'bar' }"),