Implement structured maps

This commit is contained in:
Jeff 2024-01-06 03:47:54 -05:00
parent dcb0133a4b
commit 9cee46cfe5
10 changed files with 88 additions and 44 deletions

View File

@ -31,12 +31,12 @@ impl BuiltInValue {
match self { match self {
BuiltInValue::Args => Type::list(Type::String), BuiltInValue::Args => Type::list(Type::String),
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(), BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
BuiltInValue::Fs => Type::Map, BuiltInValue::Fs => Type::Map(None),
BuiltInValue::Json => Type::Map, BuiltInValue::Json => Type::Map(None),
BuiltInValue::Length => BuiltInFunction::Length.r#type(), BuiltInValue::Length => BuiltInFunction::Length.r#type(),
BuiltInValue::Output => BuiltInFunction::Output.r#type(), BuiltInValue::Output => BuiltInFunction::Output.r#type(),
BuiltInValue::Random => Type::Map, BuiltInValue::Random => Type::Map(None),
BuiltInValue::String => Type::Map, BuiltInValue::String => Type::Map(None),
} }
} }

View File

@ -92,7 +92,7 @@ impl AbstractTree for Index {
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<Type> {
match self.collection.expected_type(context)? { match self.collection.expected_type(context)? {
Type::List(item_type) => Ok(*item_type.clone()), Type::List(item_type) => Ok(*item_type.clone()),
Type::Map => Ok(Type::Any), Type::Map(_) => Ok(Type::Any),
Type::None => Ok(Type::None), Type::None => Ok(Type::None),
r#type => Ok(r#type), r#type => Ok(r#type),
} }

View File

@ -40,7 +40,7 @@ use tree_sitter::Node;
use crate::{Error, Map, Result, Value}; use crate::{Error, Map, Result, Value};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SyntaxPosition { pub struct SyntaxPosition {
pub start_byte: usize, pub start_byte: usize,
pub end_byte: usize, pub end_byte: usize,
@ -63,6 +63,7 @@ impl From<tree_sitter::Range> for SyntaxPosition {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Root { pub struct Root {
statements: Vec<Statement>, statements: Vec<Statement>,
} }

View File

@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Map, Result, Value}; use crate::{AbstractTree, Error, Map, Result, Structure, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct TypeDefinition { pub struct TypeDefinition {
@ -61,7 +61,7 @@ pub enum Type {
}, },
Integer, Integer,
List(Box<Type>), List(Box<Type>),
Map, Map(Option<Structure>),
None, None,
Number, Number,
String, String,
@ -92,13 +92,13 @@ impl Type {
| (Type::Collection, Type::Collection) | (Type::Collection, Type::Collection)
| (Type::Collection, Type::List(_)) | (Type::Collection, Type::List(_))
| (Type::List(_), Type::Collection) | (Type::List(_), Type::Collection)
| (Type::Collection, Type::Map) | (Type::Collection, Type::Map(_))
| (Type::Map, Type::Collection) | (Type::Map(_), Type::Collection)
| (Type::Collection, Type::String) | (Type::Collection, Type::String)
| (Type::String, Type::Collection) | (Type::String, Type::Collection)
| (Type::Float, Type::Float) | (Type::Float, Type::Float)
| (Type::Integer, Type::Integer) | (Type::Integer, Type::Integer)
| (Type::Map, Type::Map) | (Type::Map(_), Type::Map(_))
| (Type::Number, Type::Number) | (Type::Number, Type::Number)
| (Type::Number, Type::Integer) | (Type::Number, Type::Integer)
| (Type::Number, Type::Float) | (Type::Number, Type::Float)
@ -215,7 +215,7 @@ impl AbstractTree for Type {
} }
} }
"int" => Type::Integer, "int" => Type::Integer,
"map" => Type::Map, "map" => Type::Map(None),
"num" => Type::Number, "num" => Type::Number,
"none" => Type::None, "none" => Type::None,
"str" => Type::String, "str" => Type::String,
@ -273,7 +273,7 @@ impl Display for Type {
} }
Type::Integer => write!(f, "int"), Type::Integer => write!(f, "int"),
Type::List(item_type) => write!(f, "[{item_type}]"), Type::List(item_type) => write!(f, "[{item_type}]"),
Type::Map => write!(f, "map"), Type::Map(_) => write!(f, "map"),
Type::Number => write!(f, "num"), Type::Number => write!(f, "num"),
Type::None => write!(f, "none"), Type::None => write!(f, "none"),
Type::String => write!(f, "str"), Type::String => write!(f, "str"),

View File

@ -5,7 +5,7 @@ use tree_sitter::Node;
use crate::{ use crate::{
AbstractTree, BuiltInValue, Error, Expression, Function, Identifier, List, Map, Result, AbstractTree, BuiltInValue, Error, Expression, Function, Identifier, List, Map, Result,
Statement, Type, TypeDefinition, Value, Statement, Structure, Type, TypeDefinition, Value,
}; };
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
@ -116,7 +116,7 @@ impl AbstractTree for ValueNode {
let mut current_type: Option<Type> = None; let mut current_type: Option<Type> = None;
let mut current_statement = None; let mut current_statement = None;
for index in 0..child.child_count() - 1 { for index in 2..child.child_count() - 1 {
let child_syntax_node = child.child(index).unwrap(); let child_syntax_node = child.child(index).unwrap();
if child_syntax_node.kind() == "identifier" { if child_syntax_node.kind() == "identifier" {
@ -151,9 +151,15 @@ impl AbstractTree for ValueNode {
context, context,
)?); )?);
if let (Some(identifier), Some(r#type)) = if let Some(identifier) = &current_identifier {
(&current_identifier, &current_type) let r#type = if let Some(r#type) = &current_type {
{ r#type.clone()
} else if let Some(statement) = &current_statement {
statement.expected_type(context)?
} else {
Type::None
};
btree_map.insert( btree_map.insert(
identifier.inner().clone(), identifier.inner().clone(),
(current_statement.clone(), r#type.clone()), (current_statement.clone(), r#type.clone()),
@ -223,16 +229,16 @@ impl AbstractTree for ValueNode {
let mut value_map = BTreeMap::new(); let mut value_map = BTreeMap::new();
for (key, (statement_option, r#type)) in node_map { for (key, (statement_option, r#type)) in node_map {
let value = if let Some(statement) = statement_option { let value_option = if let Some(statement) = statement_option {
statement.run(source, context)? Some(statement.run(source, context)?)
} else { } else {
Value::none() None
}; };
value_map.insert(key.to_string(), (Some(value), r#type.clone())); value_map.insert(key.to_string(), (value_option, r#type.clone()));
} }
Value::Structure(value_map) Value::Structure(Structure::new(value_map))
} }
}; };
@ -274,9 +280,17 @@ impl AbstractTree for ValueNode {
Type::None Type::None
} }
} }
ValueNode::Map(_) => Type::Map, ValueNode::Map(_) => Type::Map(None),
ValueNode::BuiltInValue(built_in_value) => built_in_value.expected_type(context)?, ValueNode::BuiltInValue(built_in_value) => built_in_value.expected_type(context)?,
ValueNode::Structure(_) => todo!(), ValueNode::Structure(node_map) => {
let mut value_map = BTreeMap::new();
for (key, (_statement_option, r#type)) in node_map {
value_map.insert(key.to_string(), (None, r#type.clone()));
}
Type::Map(Some(Structure::new(value_map)))
}
}; };
Ok(r#type) Ok(r#type)

View File

@ -8,7 +8,7 @@ pub use crate::{
built_in_functions::BuiltInFunction, built_in_functions::BuiltInFunction,
error::*, error::*,
interpret::*, interpret::*,
value::{function::Function, list::List, map::Map, Value}, value::{function::Function, list::List, map::Map, structure::Structure, Value},
}; };
pub use tree_sitter::Node as SyntaxNode; pub use tree_sitter::Node as SyntaxNode;

View File

@ -11,7 +11,7 @@ use std::{
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}, sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
}; };
use crate::{value::Value, Result, Type}; use crate::{value::Value, Result, Structure, Type};
/// A collection dust variables comprised of key-value pairs. /// A collection dust variables comprised of key-value pairs.
/// ///
@ -20,6 +20,7 @@ use crate::{value::Value, Result, Type};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Map { pub struct Map {
variables: Arc<RwLock<BTreeMap<String, (Value, Type)>>>, variables: Arc<RwLock<BTreeMap<String, (Value, Type)>>>,
structure: Option<Structure>,
} }
impl Map { impl Map {
@ -27,6 +28,7 @@ impl Map {
pub fn new() -> Self { pub fn new() -> Self {
Map { Map {
variables: Arc::new(RwLock::new(BTreeMap::new())), variables: Arc::new(RwLock::new(BTreeMap::new())),
structure: None,
} }
} }
@ -39,6 +41,7 @@ impl Map {
Ok(Map { Ok(Map {
variables: Arc::new(RwLock::new(new_map)), variables: Arc::new(RwLock::new(new_map)),
structure: other.structure.clone(),
}) })
} }

View File

@ -1,7 +1,7 @@
//! Types that represent runtime values. //! Types that represent runtime values.
use crate::{ use crate::{
error::{Error, Result}, error::{Error, Result},
Function, Identifier, List, Map, Type, TypeDefinition, Function, Identifier, List, Map, Structure, Type, TypeDefinition,
}; };
use serde::{ use serde::{
@ -12,7 +12,6 @@ use serde::{
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::BTreeMap,
convert::TryFrom, convert::TryFrom,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
marker::PhantomData, marker::PhantomData,
@ -23,6 +22,7 @@ use std::{
pub mod function; pub mod function;
pub mod list; pub mod list;
pub mod map; pub mod map;
pub mod structure;
/// Dust value representation. /// Dust value representation.
/// ///
@ -39,7 +39,7 @@ pub enum Value {
Integer(i64), Integer(i64),
Boolean(bool), Boolean(bool),
Option(Option<Box<Value>>), Option(Option<Box<Value>>),
Structure(BTreeMap<String, (Option<Value>, Type)>), Structure(Structure),
} }
impl Default for Value { impl Default for Value {
@ -86,7 +86,7 @@ impl Value {
)); ));
} }
Type::Map Type::Map(None)
} }
Value::Function(function) => function.r#type().clone(), Value::Function(function) => function.r#type().clone(),
Value::String(_) => Type::String, Value::String(_) => Type::String,
@ -541,18 +541,7 @@ impl Display for Value {
Value::List(list) => write!(f, "{list}"), Value::List(list) => write!(f, "{list}"),
Value::Map(map) => write!(f, "{map}"), Value::Map(map) => write!(f, "{map}"),
Value::Function(function) => write!(f, "{function}"), Value::Function(function) => write!(f, "{function}"),
Value::Structure(btree_map) => { Value::Structure(structure) => write!(f, "{structure}"),
writeln!(f, "{{")?;
for (key, (value_option, r#type)) in btree_map {
if let Some(value) = value_option {
writeln!(f, " {key} {} = {value}", r#type)?;
} else {
writeln!(f, " {key} {}", r#type)?;
}
}
write!(f, "}}")
}
} }
} }
} }

37
src/value/structure.rs Normal file
View File

@ -0,0 +1,37 @@
use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
sync::Arc,
};
use serde::{Deserialize, Serialize};
use crate::{Type, Value};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Structure(Arc<BTreeMap<String, (Option<Value>, Type)>>);
impl Structure {
pub fn new(map: BTreeMap<String, (Option<Value>, Type)>) -> Self {
Structure(Arc::new(map))
}
pub fn inner(&self) -> &BTreeMap<String, (Option<Value>, Type)> {
&self.0
}
}
impl Display for Structure {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
writeln!(f, "{{")?;
for (key, (value_option, r#type)) in self.0.as_ref() {
if let Some(value) = value_option {
writeln!(f, " {key} <{}> = {value}", r#type)?;
} else {
writeln!(f, " {key} <{}>", r#type)?;
}
}
write!(f, "}}")
}
}

View File

@ -10,5 +10,5 @@ fn simple_structure() {
btree_map.insert("x".to_string(), (Some(Value::Integer(0)), Type::Integer)); btree_map.insert("x".to_string(), (Some(Value::Integer(0)), Type::Integer));
assert_eq!(Ok(Value::Structure(btree_map)), result); assert_eq!(Ok(Value::Structure(Structure::new(btree_map))), result);
} }