1
0

Implement list type checks

This commit is contained in:
Jeff 2023-11-30 00:57:15 -05:00
parent b6422a438b
commit 8826d08392
22 changed files with 160 additions and 141 deletions

View File

@ -1,12 +1,12 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Identifier, Map, Result, Statement, Type, TypeDefintion, Value}; use crate::{AbstractTree, Error, Identifier, Map, Result, Statement, Type, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Assignment { pub struct Assignment {
identifier: Identifier, identifier: Identifier,
type_definition: Option<TypeDefintion>, type_definition: Option<TypeDefinition>,
operator: AssignmentOperator, operator: AssignmentOperator,
statement: Statement, statement: Statement,
} }
@ -27,7 +27,9 @@ impl AbstractTree for Assignment {
let type_node = node.child_by_field_name("type"); let type_node = node.child_by_field_name("type");
let type_definition = if let Some(type_node) = type_node { let type_definition = if let Some(type_node) = type_node {
Some(TypeDefintion::from_syntax_node(source, type_node, context)?) Some(TypeDefinition::from_syntax_node(
source, type_node, context,
)?)
} else { } else {
None None
}; };
@ -57,14 +59,7 @@ impl AbstractTree for Assignment {
if let Some(type_defintion) = &type_definition { if let Some(type_defintion) = &type_definition {
let statement_type = statement.expected_type(context)?; let statement_type = statement.expected_type(context)?;
if type_defintion.r#type() != &statement_type { type_defintion.check(&statement_type, context)?;
return Err(Error::TypeCheck {
expected: type_defintion.r#type().clone(),
actual: statement_type,
location: node.start_position(),
source: source[node.byte_range()].to_string(),
});
}
} }
Ok(Assignment { Ok(Assignment {
@ -100,7 +95,9 @@ impl AbstractTree for Assignment {
}; };
if let Some(type_definition) = &self.type_definition { if let Some(type_definition) = &self.type_definition {
type_definition.check(&new_value, context)?; let new_value_type = new_value.r#type(context)?;
type_definition.check(&new_value_type, context)?;
} }
context.variables_mut()?.insert(key.clone(), new_value); context.variables_mut()?.insert(key.clone(), new_value);
@ -108,7 +105,7 @@ impl AbstractTree for Assignment {
Ok(Value::Empty) Ok(Value::Empty)
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
Ok(Type::Empty) Ok(TypeDefinition::new(Type::Empty))
} }
} }

View File

@ -4,7 +4,7 @@ use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Map, Result, Statement, Type, Value}; use crate::{AbstractTree, Error, Map, Result, Statement, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Block { pub struct Block {
@ -82,7 +82,7 @@ impl AbstractTree for Block {
} }
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.statements.last().unwrap().expected_type(context) self.statements.last().unwrap().expected_type(context)
} }
} }

View File

@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{ use crate::{
value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, Type, Value, Yield, value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, TypeDefinition,
Value, Yield,
}; };
use super::{function_call::FunctionCall, logic::Logic, math::Math}; use super::{function_call::FunctionCall, logic::Logic, math::Math};
@ -71,7 +72,7 @@ impl AbstractTree for Expression {
} }
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
match self { match self {
Expression::Value(value_node) => value_node.expected_type(context), Expression::Value(value_node) => value_node.expected_type(context),
Expression::Identifier(identifier) => identifier.expected_type(context), Expression::Identifier(identifier) => identifier.expected_type(context),

View File

@ -2,7 +2,9 @@ use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, Value}; use crate::{
AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, TypeDefinition, Value,
};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct For { pub struct For {
@ -77,7 +79,7 @@ impl AbstractTree for For {
Ok(Value::Empty) Ok(Value::Empty)
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
Ok(Type::Empty) Ok(TypeDefinition::new(Type::Empty))
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Map, Result, Type, Value, BUILT_IN_FUNCTIONS}; use crate::{AbstractTree, Error, Map, Result, TypeDefinition, Value, BUILT_IN_FUNCTIONS};
use super::expression::Expression; use super::expression::Expression;
@ -87,7 +87,7 @@ impl AbstractTree for FunctionCall {
function.run(source, &mut function_context) function.run(source, &mut function_context)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.function.expected_type(context) self.function.expected_type(context)
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Map, Result, Type, Value}; use crate::{AbstractTree, Error, Map, Result, Type, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Identifier(String); pub struct Identifier(String);
@ -37,11 +37,11 @@ impl AbstractTree for Identifier {
} }
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
if let Some(value) = context.variables()?.get(&self.0) { if let Some(value) = context.variables()?.get(&self.0) {
Ok(value.r#type(context)?) value.r#type(context)
} else { } else {
Ok(Type::Empty) Ok(TypeDefinition::new(Type::Empty))
} }
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Block, Expression, Map, Result, Type, Value}; use crate::{AbstractTree, Block, Expression, Map, Result, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct IfElse { pub struct IfElse {
@ -81,7 +81,7 @@ impl AbstractTree for IfElse {
} }
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.if_block.expected_type(context) self.if_block.expected_type(context)
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Expression, List, Map, Result, Type, Value}; use crate::{AbstractTree, Error, Expression, List, Map, Result, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Index { pub struct Index {
@ -78,7 +78,7 @@ impl AbstractTree for Index {
} }
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.collection.expected_type(context) self.collection.expected_type(context)
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Index, Map, Result, Statement, Type, Value}; use crate::{AbstractTree, Error, Index, Map, Result, Statement, Type, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct IndexAssignment { pub struct IndexAssignment {
@ -91,7 +91,7 @@ impl AbstractTree for IndexAssignment {
Ok(Value::Empty) Ok(Value::Empty)
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
Ok(Type::Empty) Ok(TypeDefinition::new(Type::Empty))
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Expression, Map, Result, Type, Value}; use crate::{AbstractTree, Error, Expression, Map, Result, Type, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Logic { pub struct Logic {
@ -74,8 +74,8 @@ impl AbstractTree for Logic {
Ok(Value::Boolean(result)) Ok(Value::Boolean(result))
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
Ok(Type::Boolean) Ok(TypeDefinition::new(Type::Boolean))
} }
} }

View File

@ -6,7 +6,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Map, Result, Type, Value}; use crate::{AbstractTree, Map, Result, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Match {} pub struct Match {}
@ -20,7 +20,7 @@ impl AbstractTree for Match {
todo!() todo!()
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
todo!() todo!()
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Error, Expression, Map, Result, Type, Value}; use crate::{AbstractTree, Error, Expression, Map, Result, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Math { pub struct Math {
@ -56,7 +56,7 @@ impl AbstractTree for Math {
Ok(value) Ok(value)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.left.expected_type(context) self.left.expected_type(context)
} }
} }

View File

@ -66,7 +66,7 @@ impl AbstractTree for Root {
Ok(value) Ok(value)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.statements.last().unwrap().expected_type(context) self.statements.last().unwrap().expected_type(context)
} }
} }
@ -88,5 +88,5 @@ pub trait AbstractTree: Sized {
/// Execute dust code by traversing the tree. /// Execute dust code by traversing the tree.
fn run(&self, source: &str, context: &Map) -> Result<Value>; fn run(&self, source: &str, context: &Map) -> Result<Value>;
fn expected_type(&self, context: &Map) -> Result<Type>; fn expected_type(&self, context: &Map) -> Result<TypeDefinition>;
} }

View File

@ -3,7 +3,7 @@ use tree_sitter::Node;
use crate::{ use crate::{
AbstractTree, Assignment, Block, Error, Expression, For, IfElse, IndexAssignment, Map, Match, AbstractTree, Assignment, Block, Error, Expression, For, IfElse, IndexAssignment, Map, Match,
Result, Type, Use, Value, While, Result, TypeDefinition, Use, Value, While,
}; };
/// Abstract representation of a statement. /// Abstract representation of a statement.
@ -82,7 +82,7 @@ impl AbstractTree for Statement {
} }
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
match self { match self {
Statement::Assignment(assignment) => assignment.expected_type(context), Statement::Assignment(assignment) => assignment.expected_type(context),
Statement::Return(expression) => expression.expected_type(context), Statement::Return(expression) => expression.expected_type(context),

View File

@ -6,44 +6,83 @@ use tree_sitter::Node;
use crate::{AbstractTree, Error, Map, Result, Value}; use crate::{AbstractTree, Error, Map, Result, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct TypeDefintion { pub struct TypeDefinition {
r#type: Type, r#type: Type,
} }
impl TypeDefintion { impl TypeDefinition {
pub fn new(r#type: Type) -> Self {
Self { r#type }
}
pub fn r#type(&self) -> &Type { pub fn r#type(&self) -> &Type {
&self.r#type &self.r#type
} }
pub fn check(&self, other: &TypeDefinition, context: &Map) -> Result<()> {
match (&self.r#type, &other.r#type) {
(Type::Any, _)
| (_, Type::Any)
| (Type::Boolean, Type::Boolean)
| (Type::Empty, Type::Empty)
| (Type::Float, Type::Float)
| (Type::Integer, Type::Integer)
| (Type::Map, Type::Map)
| (Type::Number, Type::Number)
| (Type::Number, Type::Integer)
| (Type::Number, Type::Float)
| (Type::Integer, Type::Number)
| (Type::Float, Type::Number)
| (Type::String, Type::String)
| (Type::Table, Type::Table) => Ok(()),
(Type::List(self_item_type), Type::List(other_item_type)) => {
let self_defintion = TypeDefinition::new(self_item_type.as_ref().clone());
let other_definition = &TypeDefinition::new(other_item_type.as_ref().clone());
self_defintion.check(other_definition, context)
}
_ => Err(Error::RuntimeTypeCheck {
expected: self.clone(),
actual: other.clone(),
}),
}
}
} }
impl AbstractTree for TypeDefintion { impl AbstractTree for TypeDefinition {
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> { fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
Error::expect_syntax_node(source, "type_definition", node)?; Error::expect_syntax_node(source, "type_definition", node)?;
let type_node = node.child(1).unwrap(); let type_node = node.child(1).unwrap();
let r#type = Type::from_syntax_node(source, type_node, context)?; let r#type = Type::from_syntax_node(source, type_node, context)?;
Ok(TypeDefintion { r#type }) Ok(TypeDefinition { r#type })
} }
fn run(&self, source: &str, context: &Map) -> Result<Value> { fn run(&self, source: &str, context: &Map) -> Result<Value> {
self.r#type.run(source, context) self.r#type.run(source, context)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.r#type.expected_type(context) self.r#type.expected_type(context)
} }
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialOrd, Ord)] impl Display for TypeDefinition {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "<{}>", self.r#type)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Type { pub enum Type {
Any, Any,
Boolean, Boolean,
Empty, Empty,
Float, Float,
Function { Function {
parameter_types: Vec<Type>, parameter_types: Vec<TypeDefinition>,
return_type: Box<Type>, return_type: Box<TypeDefinition>,
}, },
Integer, Integer,
List(Box<Type>), List(Box<Type>),
@ -53,19 +92,6 @@ pub enum Type {
Table, Table,
} }
impl TypeDefintion {
pub fn check(&self, value: &Value, context: &Map) -> Result<()> {
if self.r#type == value.r#type(context)? {
Ok(())
} else {
Err(Error::RuntimeTypeCheck {
expected: self.r#type.clone(),
actual: value.clone(),
})
}
}
}
impl AbstractTree for Type { impl AbstractTree for Type {
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> { fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
Error::expect_syntax_node(source, "type", node)?; Error::expect_syntax_node(source, "type", node)?;
@ -85,7 +111,7 @@ impl AbstractTree for Type {
let parameter_type = let parameter_type =
Type::from_syntax_node(source, parameter_type_node, context)?; Type::from_syntax_node(source, parameter_type_node, context)?;
parameter_types.push(parameter_type); parameter_types.push(TypeDefinition::new(parameter_type));
} }
let return_type_node = node.child(child_count - 1).unwrap(); let return_type_node = node.child(child_count - 1).unwrap();
@ -93,7 +119,7 @@ impl AbstractTree for Type {
Type::Function { Type::Function {
parameter_types, parameter_types,
return_type: Box::new(return_type), return_type: Box::new(TypeDefinition::new(return_type)),
} }
} }
"int" => Type::Integer, "int" => Type::Integer,
@ -124,35 +150,8 @@ impl AbstractTree for Type {
Ok(Value::Empty) Ok(Value::Empty)
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
Ok(Type::Empty) Ok(TypeDefinition::new(Type::Empty))
}
}
impl Eq for Type {}
impl PartialEq for Type {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Type::Any, _)
| (_, Type::Any)
| (Type::Boolean, Type::Boolean)
| (Type::Empty, Type::Empty)
| (Type::Float, Type::Float)
| (Type::Integer, Type::Integer)
| (Type::Map, Type::Map)
| (Type::Number, Type::Number)
| (Type::Number, Type::Integer)
| (Type::Number, Type::Float)
| (Type::Integer, Type::Number)
| (Type::Float, Type::Number)
| (Type::String, Type::String)
| (Type::Table, Type::Table) => true,
(Type::List(self_item_type), Type::List(other_item_type)) => {
self_item_type == other_item_type
}
_ => false,
}
} }
} }
@ -175,11 +174,11 @@ impl Display for Type {
write!(f, "-> {return_type}") write!(f, "-> {return_type}")
} }
Type::Integer => write!(f, "integer"), Type::Integer => write!(f, "int"),
Type::List(item_type) => write!(f, "list {item_type}"), Type::List(item_type) => write!(f, "list {item_type}"),
Type::Map => write!(f, "map"), Type::Map => write!(f, "map"),
Type::Number => write!(f, "number"), Type::Number => write!(f, "num"),
Type::String => write!(f, "string"), Type::String => write!(f, "str"),
Type::Table => write!(f, "table"), Type::Table => write!(f, "table"),
} }
} }

View File

@ -3,7 +3,7 @@ use std::fs::read_to_string;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, Type, Value}; use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, Type, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Use { pub struct Use {
@ -29,7 +29,7 @@ impl AbstractTree for Use {
Ok(Value::Map(file_context)) Ok(Value::Map(file_context))
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
Ok(Type::Map) Ok(TypeDefinition::new(Type::Map))
} }
} }

View File

@ -5,7 +5,7 @@ use tree_sitter::Node;
use crate::{ use crate::{
AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table, AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table,
Type, Value, Type, TypeDefinition, Value,
}; };
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
@ -181,30 +181,42 @@ impl AbstractTree for ValueNode {
Ok(value) Ok(value)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
let r#type = match self { let type_definition = match self {
ValueNode::Boolean(_) => Type::Boolean, ValueNode::Boolean(_) => TypeDefinition::new(Type::Boolean),
ValueNode::Float(_) => Type::Float, ValueNode::Float(_) => TypeDefinition::new(Type::Float),
ValueNode::Integer(_) => Type::Integer, ValueNode::Integer(_) => TypeDefinition::new(Type::Integer),
ValueNode::String(_) => Type::String, ValueNode::String(_) => TypeDefinition::new(Type::String),
ValueNode::List(expressions) => { ValueNode::List(expressions) => {
let first_expression_type = if let Some(first) = expressions.first() { let mut previous_type = None;
first.expected_type(context)?
} else {
Type::Any
};
Type::List(Box::new(first_expression_type)) for expression in expressions {
let expression_type = expression.expected_type(context)?;
if let Some(previous) = previous_type {
if expression_type != previous {
return Ok(TypeDefinition::new(Type::Any));
}
}
previous_type = Some(expression_type);
}
if let Some(previous) = previous_type {
previous
} else {
TypeDefinition::new(Type::Any)
}
} }
ValueNode::Empty => Type::Any, ValueNode::Empty => TypeDefinition::new(Type::Any),
ValueNode::Map(_) => Type::Map, ValueNode::Map(_) => TypeDefinition::new(Type::Map),
ValueNode::Table { ValueNode::Table {
column_names: _, column_names: _,
rows: _, rows: _,
} => Type::Table, } => TypeDefinition::new(Type::Table),
ValueNode::Function(function) => function.expected_type(context)?, ValueNode::Function(function) => return function.expected_type(context),
}; };
Ok(r#type) Ok(type_definition)
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Block, Expression, Map, Result, Type, Value}; use crate::{AbstractTree, Block, Expression, Map, Result, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct While { pub struct While {
@ -30,7 +30,7 @@ impl AbstractTree for While {
Ok(Value::Empty) Ok(Value::Empty)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.block.expected_type(context) self.block.expected_type(context)
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, Expression, FunctionCall, Map, Result, Type, Value}; use crate::{AbstractTree, Expression, FunctionCall, Map, Result, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Yield { pub struct Yield {
@ -39,7 +39,7 @@ impl AbstractTree for Yield {
self.call.run(source, context) self.call.run(source, context)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.call.expected_type(context) self.call.expected_type(context)
} }
} }

View File

@ -5,7 +5,7 @@
use tree_sitter::{Node, Point}; use tree_sitter::{Node, Point};
use crate::{value::Value, Identifier, Type}; use crate::{value::Value, Identifier, TypeDefinition};
use std::{fmt, io, num::ParseFloatError, string::FromUtf8Error, sync::PoisonError, time}; use std::{fmt, io, num::ParseFloatError, string::FromUtf8Error, sync::PoisonError, time};
@ -21,15 +21,15 @@ pub enum Error {
}, },
TypeCheck { TypeCheck {
expected: Type, expected: TypeDefinition,
actual: Type, actual: TypeDefinition,
location: Point, location: Point,
source: String, source: String,
}, },
RuntimeTypeCheck { RuntimeTypeCheck {
expected: Type, expected: TypeDefinition,
actual: Value, actual: TypeDefinition,
}, },
/// The 'assert' macro did not resolve successfully. /// The 'assert' macro did not resolve successfully.

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, Block, Error, Identifier, Map, Result, Type, Value}; use crate::{AbstractTree, Block, Error, Identifier, Map, Result, TypeDefinition, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function { pub struct Function {
@ -49,7 +49,7 @@ impl AbstractTree for Function {
Ok(return_value) Ok(return_value)
} }
fn expected_type(&self, context: &Map) -> Result<Type> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.body.expected_type(context) self.body.expected_type(context)
} }
} }

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},
AbstractTree, Function, List, Map, Table, Type, AbstractTree, Function, List, Map, Table, Type, TypeDefinition,
}; };
use serde::{ use serde::{
@ -43,16 +43,24 @@ pub enum Value {
} }
impl Value { impl Value {
pub fn r#type(&self, context: &Map) -> Result<Type> { pub fn r#type(&self, context: &Map) -> Result<TypeDefinition> {
let r#type = match self { let r#type = match self {
Value::List(list) => { Value::List(list) => {
let first_item_type = if let Some(first) = list.items().first() { let mut previous_type = None;
first.r#type(context)?
} else {
Type::Any
};
Type::List(Box::new(first_item_type)) for value in list.items().iter() {
let value_type = value.r#type(context)?;
if let Some(previous) = &previous_type {
if &value_type != previous {
break;
}
}
previous_type = Some(value_type);
}
Type::List(Box::new(Type::Any))
} }
Value::Map(_) => Type::Map, Value::Map(_) => Type::Map,
Value::Table(_) => Type::Table, Value::Table(_) => Type::Table,
@ -77,7 +85,7 @@ impl Value {
Value::Empty => Type::Empty, Value::Empty => Type::Empty,
}; };
Ok(r#type) Ok(TypeDefinition::new(r#type))
} }
pub fn is_table(&self) -> bool { pub fn is_table(&self) -> bool {