Pass index tests; Begin implementing specific maps
This commit is contained in:
parent
4afc8face8
commit
52027db6c3
@ -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)
|
||||||
|
{
|
||||||
|
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)?;
|
self.index.validate(_source, _context)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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"),
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
8
tree-sitter-dust/corpus/types.txt
Normal file
8
tree-sitter-dust/corpus/types.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
================================================================================
|
||||||
|
Specific Map
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
x <{ y <int> }> = { y = 2 }
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
@ -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',
|
||||||
|
@ -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"
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user