Add lots of type checking
This commit is contained in:
parent
2a7988f9a6
commit
99ba7b78ab
@ -172,6 +172,10 @@ impl AbstractTree for BuiltInValue {
|
|||||||
Ok(self.get().clone())
|
Ok(self.get().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Structure) -> Result<Type> {
|
fn expected_type(&self, _context: &Structure) -> Result<Type> {
|
||||||
Ok(self.r#type())
|
Ok(self.r#type())
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ pub struct For {
|
|||||||
item_id: Identifier,
|
item_id: Identifier,
|
||||||
collection: Expression,
|
collection: Expression,
|
||||||
block: Block,
|
block: Block,
|
||||||
|
context: Structure,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for For {
|
impl AbstractTree for For {
|
||||||
@ -45,29 +46,42 @@ impl AbstractTree for For {
|
|||||||
item_id: identifier,
|
item_id: identifier,
|
||||||
collection: expression,
|
collection: expression,
|
||||||
block: item,
|
block: item,
|
||||||
|
context: Structure::clone_from(context)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, context: &Structure) -> Result<()> {
|
||||||
|
self.collection.check_type(context)?;
|
||||||
|
|
||||||
|
let key = self.item_id.inner();
|
||||||
|
let collection_type = self.collection.expected_type(context)?;
|
||||||
|
|
||||||
|
Type::list(Type::Any).check(&collection_type)?;
|
||||||
|
|
||||||
|
if let Type::List(item_type) = self.collection.expected_type(context)? {
|
||||||
|
self.context
|
||||||
|
.set(key.to_string(), Value::none(), Some(*item_type))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.block.check_type(&self.context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
let expression_run = self.collection.run(source, context)?;
|
let expression_run = self.collection.run(source, context)?;
|
||||||
let values = expression_run.as_list()?.items();
|
|
||||||
let key = self.item_id.inner();
|
let key = self.item_id.inner();
|
||||||
|
let values = expression_run.as_list()?.items();
|
||||||
|
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
values.par_iter().try_for_each(|value| {
|
values.par_iter().try_for_each(|value| {
|
||||||
let iter_context = Structure::clone_from(context)?;
|
self.context.set(key.clone(), value.clone(), None)?;
|
||||||
|
|
||||||
iter_context.set(key.clone(), value.clone(), None)?;
|
self.block.run(source, &self.context).map(|_value| ())
|
||||||
|
|
||||||
self.block.run(source, &iter_context).map(|_value| ())
|
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
let loop_context = Structure::clone_from(context)?;
|
|
||||||
|
|
||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
loop_context.set(key.clone(), value.clone(), None)?;
|
self.context.set(key.clone(), value.clone(), None)?;
|
||||||
|
|
||||||
self.block.run(source, &loop_context)?;
|
self.block.run(source, &self.context)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_type(&self, context: &Structure) -> Result<()> {
|
fn check_type(&self, context: &Structure) -> Result<()> {
|
||||||
|
self.function_expression.check_type(context)?;
|
||||||
|
|
||||||
let variables = context.variables()?;
|
let variables = context.variables()?;
|
||||||
let function_type = match &self.function_expression {
|
let function_type = match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
@ -72,6 +74,8 @@ impl AbstractTree for FunctionCall {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (index, expression) in self.arguments.iter().enumerate() {
|
for (index, expression) in self.arguments.iter().enumerate() {
|
||||||
|
expression.check_type(context)?;
|
||||||
|
|
||||||
if let Some(r#type) = parameter_types.get(index) {
|
if let Some(r#type) = parameter_types.get(index) {
|
||||||
r#type.check(&expression.expected_type(context)?)?;
|
r#type.check(&expression.expected_type(context)?)?;
|
||||||
}
|
}
|
||||||
@ -133,32 +137,14 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
||||||
match &self.function_expression {
|
let function_type = self.function_expression.expected_type(context)?;
|
||||||
FunctionExpression::Identifier(identifier) => {
|
|
||||||
let identifier_type = identifier.expected_type(context)?;
|
|
||||||
|
|
||||||
if let Type::Function {
|
if let Type::Function { return_type, .. } = function_type {
|
||||||
parameter_types: _,
|
|
||||||
return_type,
|
|
||||||
} = &identifier_type
|
|
||||||
{
|
|
||||||
Ok(*return_type.clone())
|
|
||||||
} else {
|
|
||||||
Ok(identifier_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FunctionExpression::FunctionCall(function_call) => function_call.expected_type(context),
|
|
||||||
FunctionExpression::Value(value_node) => {
|
|
||||||
let value_type = value_node.expected_type(context)?;
|
|
||||||
|
|
||||||
if let Type::Function { return_type, .. } = value_type {
|
|
||||||
Ok(*return_type)
|
Ok(*return_type)
|
||||||
} else {
|
} else {
|
||||||
Ok(value_type)
|
Err(Error::ExpectedFunctionExpression {
|
||||||
}
|
actual: self.function_expression.clone(),
|
||||||
}
|
})
|
||||||
FunctionExpression::Index(index) => index.expected_type(context),
|
|
||||||
FunctionExpression::Yield(r#yield) => r#yield.expected_type(context),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,16 @@ impl AbstractTree for FunctionExpression {
|
|||||||
Ok(function_expression)
|
Ok(function_expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
FunctionExpression::Identifier(identifier) => identifier.check_type(_context),
|
||||||
|
FunctionExpression::FunctionCall(function_call) => function_call.check_type(_context),
|
||||||
|
FunctionExpression::Value(value_node) => value_node.check_type(_context),
|
||||||
|
FunctionExpression::Index(index) => index.check_type(_context),
|
||||||
|
FunctionExpression::Yield(r#yield) => r#yield.check_type(_context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
FunctionExpression::Identifier(identifier) => identifier.run(source, context),
|
FunctionExpression::Identifier(identifier) => identifier.run(source, context),
|
||||||
|
@ -45,10 +45,12 @@ impl AbstractTree for Identifier {
|
|||||||
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
Ok(())
|
||||||
println!("{_value}");
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
||||||
|
if let Some((_, r#type)) = context.variables()?.get(&self.0) {
|
||||||
Ok(r#type.clone())
|
Ok(r#type.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
||||||
|
@ -55,6 +55,25 @@ impl AbstractTree for IfElse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
self.if_expression.check_type(_context)?;
|
||||||
|
self.if_block.check_type(_context)?;
|
||||||
|
|
||||||
|
for expression in &self.else_if_expressions {
|
||||||
|
expression.check_type(_context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for block in &self.else_if_blocks {
|
||||||
|
block.check_type(_context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(block) = &self.else_block {
|
||||||
|
block.check_type(_context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
let if_boolean = self.if_expression.run(source, context)?.as_boolean()?;
|
let if_boolean = self.if_expression.run(source, context)?.as_boolean()?;
|
||||||
|
|
||||||
|
@ -93,6 +93,20 @@ impl AbstractTree for Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, context: &Structure) -> Result<()> {
|
||||||
|
let collection_type = self.collection.expected_type(context)?;
|
||||||
|
|
||||||
|
match collection_type {
|
||||||
|
Type::List(_) | Type::String | Type::Structure(_) | Type::StructureDefinition(_) => {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::TypeCheck {
|
||||||
|
expected: Type::Collection,
|
||||||
|
actual: collection_type,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
fn expected_type(&self, context: &Structure) -> 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()),
|
||||||
|
@ -51,6 +51,11 @@ impl AbstractTree for IndexAssignment {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
self.index.check_type(_context)?;
|
||||||
|
self.statement.check_type(_context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
let index_collection = self.index.collection.run(source, context)?;
|
let index_collection = self.index.collection.run(source, context)?;
|
||||||
let index_context = index_collection.as_structure().unwrap_or(context);
|
let index_context = index_collection.as_structure().unwrap_or(context);
|
||||||
|
@ -52,6 +52,15 @@ impl AbstractTree for IndexExpression {
|
|||||||
Ok(abstract_node)
|
Ok(abstract_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
IndexExpression::Value(value_node) => value_node.check_type(_context),
|
||||||
|
IndexExpression::Identifier(identifier) => identifier.check_type(_context),
|
||||||
|
IndexExpression::Index(index) => index.check_type(_context),
|
||||||
|
IndexExpression::FunctionCall(function_call) => function_call.check_type(_context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
IndexExpression::Value(value_node) => value_node.run(source, context),
|
IndexExpression::Value(value_node) => value_node.run(source, context),
|
||||||
|
@ -59,6 +59,11 @@ impl AbstractTree for Logic {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
self.left.check_type(_context)?;
|
||||||
|
self.right.check_type(_context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
|
@ -58,6 +58,21 @@ impl AbstractTree for Match {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
self.matcher.check_type(_context)?;
|
||||||
|
|
||||||
|
for (expression, statement) in &self.options {
|
||||||
|
expression.check_type(_context)?;
|
||||||
|
statement.check_type(_context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(statement) = &self.fallback {
|
||||||
|
statement.check_type(_context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
let matcher_value = self.matcher.run(source, context)?;
|
let matcher_value = self.matcher.run(source, context)?;
|
||||||
|
|
||||||
|
@ -48,6 +48,11 @@ impl AbstractTree for Math {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
self.left.check_type(_context)?;
|
||||||
|
self.right.check_type(_context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
|
@ -108,9 +108,7 @@ pub trait AbstractTree: Sized {
|
|||||||
fn from_syntax_node(source: &str, node: Node, context: &Structure) -> Result<Self>;
|
fn from_syntax_node(source: &str, node: Node, context: &Structure) -> Result<Self>;
|
||||||
|
|
||||||
/// Verify the type integrity of the node.
|
/// Verify the type integrity of the node.
|
||||||
fn check_type(&self, _context: &Structure) -> Result<()> {
|
fn check_type(&self, _context: &Structure) -> Result<()>;
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execute dust code by traversing the tree.
|
/// Execute dust code by traversing the tree.
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value>;
|
fn run(&self, source: &str, context: &Structure) -> Result<Value>;
|
||||||
|
@ -79,6 +79,25 @@ impl AbstractTree for StructureInstantiator {
|
|||||||
Ok(instantiator)
|
Ok(instantiator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, context: &Structure) -> Result<()> {
|
||||||
|
for (_key, (statement_option, type_definition_option)) in &self.0 {
|
||||||
|
let statement_type = if let Some(statement) = statement_option {
|
||||||
|
statement.check_type(context)?;
|
||||||
|
Some(statement.expected_type(context)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let (Some(statement_type), Some(type_definition)) =
|
||||||
|
(statement_type, type_definition_option)
|
||||||
|
{
|
||||||
|
type_definition.inner().check(&statement_type)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
let mut variables = BTreeMap::new();
|
let mut variables = BTreeMap::new();
|
||||||
|
|
||||||
|
@ -34,6 +34,10 @@ impl AbstractTree for TypeDefinition {
|
|||||||
Ok(TypeDefinition { r#type })
|
Ok(TypeDefinition { r#type })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
self.r#type.run(source, context)
|
self.r#type.run(source, context)
|
||||||
}
|
}
|
||||||
@ -251,6 +255,10 @@ impl AbstractTree for Type {
|
|||||||
Ok(r#type)
|
Ok(r#type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Structure) -> Result<Value> {
|
fn run(&self, _source: &str, _context: &Structure) -> Result<Value> {
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,11 @@ impl AbstractTree for While {
|
|||||||
Ok(While { expression, block })
|
Ok(While { expression, block })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
self.expression.check_type(_context)?;
|
||||||
|
self.block.check_type(_context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
while self.expression.run(source, context)?.as_boolean()? {
|
while self.expression.run(source, context)?.as_boolean()? {
|
||||||
self.block.run(source, context)?;
|
self.block.run(source, context)?;
|
||||||
|
@ -44,6 +44,10 @@ impl AbstractTree for Yield {
|
|||||||
Ok(Yield { call })
|
Ok(Yield { call })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||||
|
self.call.check_type(_context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||||
self.call.run(source, context)
|
self.call.run(source, context)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user