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())
|
||||
}
|
||||
|
||||
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Structure) -> Result<Type> {
|
||||
Ok(self.r#type())
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ pub struct For {
|
||||
item_id: Identifier,
|
||||
collection: Expression,
|
||||
block: Block,
|
||||
context: Structure,
|
||||
}
|
||||
|
||||
impl AbstractTree for For {
|
||||
@ -45,29 +46,42 @@ impl AbstractTree for For {
|
||||
item_id: identifier,
|
||||
collection: expression,
|
||||
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> {
|
||||
let expression_run = self.collection.run(source, context)?;
|
||||
let values = expression_run.as_list()?.items();
|
||||
let key = self.item_id.inner();
|
||||
let values = expression_run.as_list()?.items();
|
||||
|
||||
if self.is_async {
|
||||
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, &iter_context).map(|_value| ())
|
||||
self.block.run(source, &self.context).map(|_value| ())
|
||||
})?;
|
||||
} else {
|
||||
let loop_context = Structure::clone_from(context)?;
|
||||
|
||||
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<()> {
|
||||
self.function_expression.check_type(context)?;
|
||||
|
||||
let variables = context.variables()?;
|
||||
let function_type = match &self.function_expression {
|
||||
FunctionExpression::Identifier(identifier) => {
|
||||
@ -72,6 +74,8 @@ impl AbstractTree for FunctionCall {
|
||||
};
|
||||
|
||||
for (index, expression) in self.arguments.iter().enumerate() {
|
||||
expression.check_type(context)?;
|
||||
|
||||
if let Some(r#type) = parameter_types.get(index) {
|
||||
r#type.check(&expression.expected_type(context)?)?;
|
||||
}
|
||||
@ -133,32 +137,14 @@ impl AbstractTree for FunctionCall {
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
||||
match &self.function_expression {
|
||||
FunctionExpression::Identifier(identifier) => {
|
||||
let identifier_type = identifier.expected_type(context)?;
|
||||
let function_type = self.function_expression.expected_type(context)?;
|
||||
|
||||
if let Type::Function {
|
||||
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)
|
||||
} else {
|
||||
Ok(value_type)
|
||||
}
|
||||
}
|
||||
FunctionExpression::Index(index) => index.expected_type(context),
|
||||
FunctionExpression::Yield(r#yield) => r#yield.expected_type(context),
|
||||
if let Type::Function { return_type, .. } = function_type {
|
||||
Ok(*return_type)
|
||||
} else {
|
||||
Err(Error::ExpectedFunctionExpression {
|
||||
actual: self.function_expression.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,16 @@ impl AbstractTree for FunctionExpression {
|
||||
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> {
|
||||
match self {
|
||||
FunctionExpression::Identifier(identifier) => identifier.run(source, context),
|
||||
|
@ -45,10 +45,12 @@ impl AbstractTree for Identifier {
|
||||
Err(Error::VariableIdentifierNotFound(self.0.clone()))
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
||||
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
||||
println!("{_value}");
|
||||
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Structure) -> Result<Type> {
|
||||
if let Some((_, r#type)) = context.variables()?.get(&self.0) {
|
||||
Ok(r#type.clone())
|
||||
} else {
|
||||
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> {
|
||||
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> {
|
||||
match self.collection.expected_type(context)? {
|
||||
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> {
|
||||
let index_collection = self.index.collection.run(source, context)?;
|
||||
let index_context = index_collection.as_structure().unwrap_or(context);
|
||||
|
@ -52,6 +52,15 @@ impl AbstractTree for IndexExpression {
|
||||
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> {
|
||||
match self {
|
||||
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> {
|
||||
let left = self.left.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> {
|
||||
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> {
|
||||
let left = self.left.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>;
|
||||
|
||||
/// Verify the type integrity of the node.
|
||||
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn check_type(&self, _context: &Structure) -> Result<()>;
|
||||
|
||||
/// Execute dust code by traversing the tree.
|
||||
fn run(&self, source: &str, context: &Structure) -> Result<Value>;
|
||||
|
@ -79,6 +79,25 @@ impl AbstractTree for StructureInstantiator {
|
||||
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> {
|
||||
let mut variables = BTreeMap::new();
|
||||
|
||||
|
@ -34,6 +34,10 @@ impl AbstractTree for TypeDefinition {
|
||||
Ok(TypeDefinition { r#type })
|
||||
}
|
||||
|
||||
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||
self.r#type.run(source, context)
|
||||
}
|
||||
@ -251,6 +255,10 @@ impl AbstractTree for Type {
|
||||
Ok(r#type)
|
||||
}
|
||||
|
||||
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Structure) -> Result<Value> {
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
@ -25,6 +25,11 @@ impl AbstractTree for While {
|
||||
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> {
|
||||
while self.expression.run(source, context)?.as_boolean()? {
|
||||
self.block.run(source, context)?;
|
||||
|
@ -44,6 +44,10 @@ impl AbstractTree for Yield {
|
||||
Ok(Yield { call })
|
||||
}
|
||||
|
||||
fn check_type(&self, _context: &Structure) -> Result<()> {
|
||||
self.call.check_type(_context)
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Structure) -> Result<Value> {
|
||||
self.call.run(source, context)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user