1
0

Convert maps to structures for advanced type checks

This commit is contained in:
Jeff 2024-02-13 12:04:02 -05:00
parent 1f5dacad7d
commit 85419c47be
6 changed files with 66 additions and 17 deletions

View File

@ -57,7 +57,11 @@ impl AbstractTree for As {
}); });
} }
} }
Type::Any => todo!(), Type::Any => {
// Do no validation when converting from "any" to a list.
// This effectively defers to runtime behavior, potentially
// causing a runtime error.
}
Type::Boolean => todo!(), Type::Boolean => todo!(),
Type::Collection => todo!(), Type::Collection => todo!(),
Type::Custom(_) => todo!(), Type::Custom(_) => todo!(),
@ -91,14 +95,12 @@ impl AbstractTree for As {
Value::List(List::with_items(chars)) Value::List(List::with_items(chars))
} }
Value::Map(_) => todo!(), _ => {
Value::Function(_) => todo!(), return Err(RuntimeError::ConversionImpossible {
Value::Float(_) => todo!(), value,
Value::Integer(_) => todo!(), target_type: self.r#type.clone(),
Value::Boolean(_) => todo!(), });
Value::Range(_) => todo!(), }
Value::Option(_) => todo!(),
Value::Structure(_) => todo!(),
} }
} else { } else {
todo!() todo!()

View File

@ -6,7 +6,8 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable}, built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable},
error::{RuntimeError, SyntaxError, ValidationError}, error::{RuntimeError, SyntaxError, ValidationError},
AbstractTree, BuiltInFunction, Context, Format, Function, List, Map, SyntaxNode, Type, Value, AbstractTree, BuiltInFunction, Context, Format, Function, List, Map, Structure, SyntaxNode,
Type, Value,
}; };
static ARGS: OnceLock<Value> = OnceLock::new(); static ARGS: OnceLock<Value> = OnceLock::new();
@ -87,7 +88,9 @@ impl BuiltInValue {
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(None), BuiltInValue::Fs => Type::Map(None),
BuiltInValue::Json => Type::Map(None), BuiltInValue::Json => Type::Map(Some(
Structure::from_map(self.get().as_map().unwrap()).unwrap(),
)),
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(None), BuiltInValue::Random => Type::Map(None),

View File

@ -48,7 +48,17 @@ impl AbstractTree for Index {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
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(structure) => {
if let Some(structure) = structure {
if let IndexExpression::Identifier(identifier) = &self.index {
if let Some((_, r#type)) = structure.inner().get(identifier.inner()) {
return Ok(r#type.clone());
}
}
}
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

@ -7,12 +7,18 @@ use std::{
time, time,
}; };
use crate::Value; use crate::{Type, Value};
use super::rw_lock_error::RwLockError; use super::rw_lock_error::RwLockError;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum RuntimeError { pub enum RuntimeError {
/// The attempted conversion is impossible.
ConversionImpossible {
value: Value,
target_type: Type,
},
Csv(String), Csv(String),
Io(String), Io(String),

View File

@ -11,7 +11,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Serializer, Deserialize, Deserializer, Serialize, Serializer,
}; };
use crate::{Type, Value}; use crate::{error::rw_lock_error::RwLockError, Map, Type, Value};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Structure(Arc<BTreeMap<String, (Option<Value>, Type)>>); pub struct Structure(Arc<BTreeMap<String, (Option<Value>, Type)>>);
@ -21,6 +21,16 @@ impl Structure {
Structure(Arc::new(map)) Structure(Arc::new(map))
} }
pub fn from_map(map: &Map) -> Result<Self, RwLockError> {
let mut structure = BTreeMap::new();
for (key, value) in map.inner()?.iter() {
structure.insert(key.clone(), (Some(value.clone()), value.r#type()));
}
Ok(Structure(Arc::new(structure)))
}
pub fn inner(&self) -> &BTreeMap<String, (Option<Value>, Type)> { pub fn inner(&self) -> &BTreeMap<String, (Option<Value>, Type)> {
&self.0 &self.0
} }
@ -42,7 +52,7 @@ impl Display for Structure {
} }
impl Serialize for Structure { impl Serialize for Structure {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
{ {
@ -94,7 +104,7 @@ impl<'de> Visitor<'de> for StructureVisitor {
} }
impl<'de> Deserialize<'de> for Structure { impl<'de> Deserialize<'de> for Structure {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {

View File

@ -1,4 +1,7 @@
use dust_lang::{error::ValidationError, *}; use dust_lang::{
error::{RuntimeError, ValidationError},
*,
};
#[test] #[test]
fn string_as_list() { fn string_as_list() {
@ -25,3 +28,18 @@ fn string_as_list_conversion_error() {
})) }))
) )
} }
const JSON: &str = "{ \"x\": 1 }";
#[test]
fn conversion_runtime_error() {
let json_value = interpret(&format!("json:parse('{JSON}')")).unwrap();
assert_eq!(
interpret(&format!("json:parse('{JSON}') as [map]")),
Err(Error::Runtime(RuntimeError::ConversionImpossible {
value: json_value,
target_type: Type::List(Box::new(Type::Float))
}))
)
}