Pass index tests; Begin implementing specific maps

This commit is contained in:
Jeff 2024-02-18 06:28:31 -05:00
parent 4afc8face8
commit 52027db6c3
11 changed files with 19877 additions and 19338 deletions

View File

@ -36,7 +36,19 @@ 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(map_types_option) => {
if let (Some(map_type), IndexExpression::Identifier(identifier)) =
(map_types_option, &self.index)
{
if let Some(r#type) = map_type.get(&identifier) {
Ok(r#type.clone())
} else {
Ok(Type::Any)
}
} else {
Ok(Type::Any)
}
}
Type::None => Ok(Type::None), Type::None => Ok(Type::None),
r#type => Ok(r#type), r#type => Ok(r#type),
} }
@ -46,11 +58,20 @@ impl AbstractTree for Index {
self.collection.validate(_source, _context)?; self.collection.validate(_source, _context)?;
let collection_type = self.collection.expected_type(_context)?; let collection_type = self.collection.expected_type(_context)?;
let index_type = self.index.expected_type(_context)?;
if let (Type::Map, Type::String) = (collection_type, index_type) {} if let (Type::Map(type_map_option), IndexExpression::Identifier(identifier)) =
(collection_type, &self.index)
self.index.validate(_source, _context)?; {
if let Some(type_map) = type_map_option {
if !type_map.contains_key(identifier) {
return Err(ValidationError::VariableIdentifierNotFound(
identifier.clone(),
));
}
}
} else {
self.index.validate(_source, _context)?;
}
Ok(()) Ok(())
} }

View File

@ -58,7 +58,19 @@ impl AbstractTree for MapNode {
} }
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
Ok(Type::Map) let mut type_map = BTreeMap::new();
for (identifier, (statement, r#type_option)) in &self.properties {
let r#type = if let Some(r#type) = type_option {
r#type.clone()
} else {
statement.expected_type(_context)?
};
type_map.insert(identifier.clone(), r#type);
}
Ok(Type::Map(Some(type_map)))
} }
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> { fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {

View File

@ -1,4 +1,7 @@
use std::fmt::{self, Display, Formatter}; use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node as SyntaxNode; use tree_sitter::Node as SyntaxNode;
@ -25,7 +28,7 @@ pub enum Type {
}, },
Integer, Integer,
List(Box<Type>), List(Box<Type>),
Map, Map(Option<BTreeMap<Identifier, Type>>),
Number, Number,
String, String,
Range, Range,
@ -69,13 +72,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)
@ -137,7 +140,7 @@ impl Type {
} }
pub fn is_map(&self) -> bool { pub fn is_map(&self) -> bool {
matches!(self, Type::Map) matches!(self, Type::Map(_))
} }
} }
@ -199,7 +202,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,
@ -262,7 +265,7 @@ impl Format for Type {
item_type.format(output, indent_level); item_type.format(output, indent_level);
output.push(']'); output.push(']');
} }
Type::Map => { Type::Map(_) => {
output.push_str("map"); output.push_str("map");
} }
Type::None => output.push_str("Option::None"), Type::None => output.push_str("Option::None"),
@ -306,7 +309,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

@ -144,7 +144,7 @@ impl AbstractTree for ValueNode {
Type::List(Box::new(Type::Any)) Type::List(Box::new(Type::Any))
} }
} }
ValueNode::Map(_) => Type::Map, ValueNode::Map(map_node) => map_node.expected_type(context)?,
ValueNode::Struct { name, .. } => { ValueNode::Struct { name, .. } => {
Type::Custom { name: name.clone(), argument: None } Type::Custom { name: name.clone(), argument: None }
} }

View File

@ -13,6 +13,7 @@ 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,
@ -93,7 +94,15 @@ impl Value {
Type::List(Box::new(Type::Any)) Type::List(Box::new(Type::Any))
} }
} }
Value::Map(_) => Type::Map, Value::Map(map) => {
let mut type_map = BTreeMap::new();
for (identifier, value) in map.inner() {
type_map.insert(identifier.clone(), value.r#type()?);
}
Type::Map(Some(type_map))
}
Value::Function(function) => function.r#type().clone(), Value::Function(function) => function.r#type().clone(),
Value::String(_) => Type::String, Value::String(_) => Type::String,
Value::Float(_) => Type::Float, Value::Float(_) => Type::Float,

View File

@ -39,7 +39,7 @@ fn conversion_runtime_error() {
interpret(&format!("json:parse('{JSON}') as [map]")), interpret(&format!("json:parse('{JSON}') as [map]")),
Err(Error::Runtime(RuntimeError::ConversionImpossible { Err(Error::Runtime(RuntimeError::ConversionImpossible {
from: json_value.r#type().unwrap(), from: json_value.r#type().unwrap(),
to: Type::List(Box::new(Type::Map)), to: Type::List(Box::new(Type::Map(None))),
position: SourcePosition { position: SourcePosition {
start_byte: 0, start_byte: 0,
end_byte: 0, end_byte: 0,

View File

@ -0,0 +1,8 @@
================================================================================
Specific Map
================================================================================
x <{ y <int> }> = { y = 2 }
--------------------------------------------------------------------------------

View File

@ -355,6 +355,17 @@ module.exports = grammar({
'float', 'float',
'int', 'int',
'map', 'map',
seq(
'map',
'{',
repeat1(
seq(
$.identifier,
$.type_specification,
),
),
'}',
),
'none', 'none',
'num', 'num',
'str', 'str',

View File

@ -1076,6 +1076,39 @@
"type": "STRING", "type": "STRING",
"value": "map" "value": "map"
}, },
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "map"
},
{
"type": "STRING",
"value": "{"
},
{
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "SYMBOL",
"name": "type_specification"
}
]
}
},
{
"type": "STRING",
"value": "}"
}
]
},
{ {
"type": "STRING", "type": "STRING",
"value": "none" "value": "none"

View File

@ -730,6 +730,10 @@
{ {
"type": "type", "type": "type",
"named": true "named": true
},
{
"type": "type_specification",
"named": true
} }
] ]
} }

File diff suppressed because it is too large Load Diff