Implement structured maps
This commit is contained in:
parent
dcb0133a4b
commit
9cee46cfe5
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
@ -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"),
|
||||||
|
@ -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) = ¤t_identifier {
|
||||||
(¤t_identifier, ¤t_type)
|
let r#type = if let Some(r#type) = ¤t_type {
|
||||||
{
|
r#type.clone()
|
||||||
|
} else if let Some(statement) = ¤t_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)
|
||||||
|
@ -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;
|
||||||
|
@ -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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
37
src/value/structure.rs
Normal 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, "}}")
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user