Add seperate interpreter step for type checking
This commit is contained in:
parent
d1ac97507b
commit
4b22221322
@ -26,7 +26,6 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
let identifier_node = node.child(0).unwrap();
|
let identifier_node = node.child(0).unwrap();
|
||||||
let identifier = Identifier::from_syntax_node(source, identifier_node, context)?;
|
let identifier = Identifier::from_syntax_node(source, identifier_node, context)?;
|
||||||
let identifier_type = identifier.expected_type(context)?;
|
|
||||||
|
|
||||||
let type_node = node.child(1).unwrap();
|
let type_node = node.child(1).unwrap();
|
||||||
let type_definition = if type_node.kind() == "type_definition" {
|
let type_definition = if type_node.kind() == "type_definition" {
|
||||||
@ -54,43 +53,6 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
let statement_node = node.child(child_count - 1).unwrap();
|
let statement_node = node.child(child_count - 1).unwrap();
|
||||||
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
||||||
let statement_type = statement.expected_type(context)?;
|
|
||||||
|
|
||||||
if let Some(type_definition) = &type_definition {
|
|
||||||
match operator {
|
|
||||||
AssignmentOperator::Equal => {
|
|
||||||
type_definition
|
|
||||||
.inner()
|
|
||||||
.check(&statement_type)
|
|
||||||
.map_err(|error| error.at_node(statement_node, source))?;
|
|
||||||
}
|
|
||||||
AssignmentOperator::PlusEqual => {
|
|
||||||
if let Type::List(item_type) = type_definition.inner() {
|
|
||||||
item_type
|
|
||||||
.check(&statement_type)
|
|
||||||
.map_err(|error| error.at_node(statement_node, source))?;
|
|
||||||
} else {
|
|
||||||
type_definition
|
|
||||||
.inner()
|
|
||||||
.check(&identifier_type)
|
|
||||||
.map_err(|error| error.at_node(identifier_node, source))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AssignmentOperator::MinusEqual => todo!(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match operator {
|
|
||||||
AssignmentOperator::Equal => {}
|
|
||||||
AssignmentOperator::PlusEqual => {
|
|
||||||
if let Type::List(item_type) = identifier_type {
|
|
||||||
item_type
|
|
||||||
.check(&statement_type)
|
|
||||||
.map_err(|error| error.at_node(statement_node, source))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AssignmentOperator::MinusEqual => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let variable_key = identifier.inner().clone();
|
let variable_key = identifier.inner().clone();
|
||||||
let variable_type = if let Some(definition) = &type_definition {
|
let variable_type = if let Some(definition) = &type_definition {
|
||||||
@ -98,7 +60,7 @@ impl AbstractTree for Assignment {
|
|||||||
} else if let Some((_, r#type)) = context.variables()?.get(identifier.inner()) {
|
} else if let Some((_, r#type)) = context.variables()?.get(identifier.inner()) {
|
||||||
r#type.clone()
|
r#type.clone()
|
||||||
} else {
|
} else {
|
||||||
statement_type
|
statement.expected_type(context)?
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set(variable_key, Value::none(), Some(variable_type))?;
|
context.set(variable_key, Value::none(), Some(variable_type))?;
|
||||||
@ -111,6 +73,40 @@ impl AbstractTree for Assignment {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
let statement_type = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
|
if let Some(type_definition) = &self.type_definition {
|
||||||
|
match self.operator {
|
||||||
|
AssignmentOperator::Equal => {
|
||||||
|
type_definition.inner().check(&statement_type)?;
|
||||||
|
}
|
||||||
|
AssignmentOperator::PlusEqual => {
|
||||||
|
if let Type::List(item_type) = type_definition.inner() {
|
||||||
|
item_type.check(&statement_type)?;
|
||||||
|
} else {
|
||||||
|
type_definition
|
||||||
|
.inner()
|
||||||
|
.check(&self.identifier.expected_type(context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssignmentOperator::MinusEqual => todo!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match self.operator {
|
||||||
|
AssignmentOperator::Equal => {}
|
||||||
|
AssignmentOperator::PlusEqual => {
|
||||||
|
if let Type::List(item_type) = self.identifier.expected_type(context)? {
|
||||||
|
item_type.check(&statement_type)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssignmentOperator::MinusEqual => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
let key = self.identifier.inner();
|
let key = self.identifier.inner();
|
||||||
let value = self.statement.run(source, context)?;
|
let value = self.statement.run(source, context)?;
|
||||||
|
@ -50,6 +50,18 @@ impl AbstractTree for Block {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
for statement in &self.statements {
|
||||||
|
if let Statement::Return(inner_statement) = statement {
|
||||||
|
return inner_statement.check_type(_source, _context);
|
||||||
|
} else {
|
||||||
|
statement.check_type(_source, _context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
let statements = &self.statements;
|
let statements = &self.statements;
|
||||||
|
@ -140,6 +140,10 @@ impl AbstractTree for BuiltInValue {
|
|||||||
Ok(built_in_value)
|
Ok(built_in_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||||
Ok(self.get().clone())
|
Ok(self.get().clone())
|
||||||
}
|
}
|
||||||
|
@ -65,27 +65,39 @@ impl AbstractTree for Expression {
|
|||||||
Ok(expression)
|
Ok(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.run(source, context),
|
Expression::Value(value_node) => value_node.run(_source, _context),
|
||||||
Expression::Identifier(identifier) => identifier.run(source, context),
|
Expression::Identifier(identifier) => identifier.run(_source, _context),
|
||||||
Expression::Math(math) => math.run(source, context),
|
Expression::Math(math) => math.run(_source, _context),
|
||||||
Expression::Logic(logic) => logic.run(source, context),
|
Expression::Logic(logic) => logic.run(_source, _context),
|
||||||
Expression::FunctionCall(function_call) => function_call.run(source, context),
|
Expression::FunctionCall(function_call) => function_call.run(_source, _context),
|
||||||
Expression::Index(index) => index.run(source, context),
|
Expression::Index(index) => index.run(_source, _context),
|
||||||
Expression::Yield(r#yield) => r#yield.run(source, context),
|
Expression::Yield(r#yield) => r#yield.run(_source, _context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.expected_type(context),
|
Expression::Value(value_node) => value_node.check_type(_source, _context),
|
||||||
Expression::Identifier(identifier) => identifier.expected_type(context),
|
Expression::Identifier(identifier) => identifier.check_type(_source, _context),
|
||||||
Expression::Math(math) => math.expected_type(context),
|
Expression::Math(math) => math.check_type(_source, _context),
|
||||||
Expression::Logic(logic) => logic.expected_type(context),
|
Expression::Logic(logic) => logic.check_type(_source, _context),
|
||||||
Expression::FunctionCall(function_call) => function_call.expected_type(context),
|
Expression::FunctionCall(function_call) => function_call.check_type(_source, _context),
|
||||||
Expression::Index(index) => index.expected_type(context),
|
Expression::Index(index) => index.check_type(_source, _context),
|
||||||
Expression::Yield(r#yield) => r#yield.expected_type(context),
|
Expression::Yield(r#yield) => r#yield.check_type(_source, _context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
|
match self {
|
||||||
|
Expression::Value(value_node) => value_node.expected_type(_context),
|
||||||
|
Expression::Identifier(identifier) => identifier.expected_type(_context),
|
||||||
|
Expression::Math(math) => math.expected_type(_context),
|
||||||
|
Expression::Logic(logic) => logic.expected_type(_context),
|
||||||
|
Expression::FunctionCall(function_call) => function_call.expected_type(_context),
|
||||||
|
Expression::Index(index) => index.expected_type(_context),
|
||||||
|
Expression::Yield(r#yield) => r#yield.expected_type(_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,10 @@ impl AbstractTree for For {
|
|||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
let function_node = node.child(0).unwrap();
|
let function_node = node.child(0).unwrap();
|
||||||
let function_expression =
|
let function_expression =
|
||||||
FunctionExpression::from_syntax_node(source, function_node, context)?;
|
FunctionExpression::from_syntax_node(source, function_node, context)?;
|
||||||
let function_type = function_expression.expected_type(context)?;
|
|
||||||
|
|
||||||
let mut minimum_parameter_count = 0;
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
for index in 2..node.child_count() - 1 {
|
for index in 2..node.child_count() - 1 {
|
||||||
@ -35,48 +33,53 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
if child.is_named() {
|
if child.is_named() {
|
||||||
let expression = Expression::from_syntax_node(source, child, context)?;
|
let expression = Expression::from_syntax_node(source, child, context)?;
|
||||||
let expression_type = expression.expected_type(context)?;
|
|
||||||
let argument_index = arguments.len();
|
|
||||||
|
|
||||||
if let Type::Function {
|
|
||||||
parameter_types, ..
|
|
||||||
} = &function_type
|
|
||||||
{
|
|
||||||
if let Some(r#type) = parameter_types.get(argument_index) {
|
|
||||||
if let Type::Option(_) = r#type {
|
|
||||||
} else {
|
|
||||||
minimum_parameter_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
r#type
|
|
||||||
.check(&expression_type)
|
|
||||||
.map_err(|error| error.at_node(child, source))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arguments.push(expression);
|
arguments.push(expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Type::Function {
|
|
||||||
parameter_types: _, ..
|
|
||||||
} = &function_type
|
|
||||||
{
|
|
||||||
if arguments.len() < minimum_parameter_count {
|
|
||||||
return Err(Error::ExpectedFunctionArgumentMinimum {
|
|
||||||
source: source[function_node.byte_range()].to_string(),
|
|
||||||
minumum_expected: minimum_parameter_count,
|
|
||||||
actual: arguments.len(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(FunctionCall {
|
Ok(FunctionCall {
|
||||||
function_expression,
|
function_expression,
|
||||||
arguments,
|
arguments,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
let function_type = self.function_expression.expected_type(context)?;
|
||||||
|
let mut minimum_parameter_count = 0;
|
||||||
|
|
||||||
|
for (index, expression) in self.arguments.iter().enumerate() {
|
||||||
|
if let Type::Function {
|
||||||
|
parameter_types, ..
|
||||||
|
} = &function_type
|
||||||
|
{
|
||||||
|
if let Some(r#type) = parameter_types.get(index) {
|
||||||
|
if let Type::Option(_) = r#type {
|
||||||
|
} else {
|
||||||
|
minimum_parameter_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r#type.check(&expression.expected_type(context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Type::Function {
|
||||||
|
parameter_types: _, ..
|
||||||
|
} = &function_type
|
||||||
|
{
|
||||||
|
if self.arguments.len() < minimum_parameter_count {
|
||||||
|
return Err(Error::ExpectedFunctionArgumentMinimum {
|
||||||
|
source: "TODO".to_string(),
|
||||||
|
minumum_expected: minimum_parameter_count,
|
||||||
|
actual: self.arguments.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
let (name, value) = match &self.function_expression {
|
let (name, value) = match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
|
@ -64,6 +64,10 @@ impl AbstractTree for FunctionExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
match self {
|
match self {
|
||||||
FunctionExpression::Identifier(identifier) => identifier.expected_type(context),
|
FunctionExpression::Identifier(identifier) => identifier.expected_type(context),
|
||||||
|
@ -43,6 +43,10 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
||||||
Ok(r#type.clone())
|
Ok(r#type.clone())
|
||||||
|
@ -81,6 +81,10 @@ impl AbstractTree for IfElse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.if_block.expected_type(context)
|
self.if_block.expected_type(context)
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,10 @@ impl AbstractTree for Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> 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()),
|
||||||
|
@ -91,6 +91,10 @@ impl AbstractTree for IndexAssignment {
|
|||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,10 @@ impl AbstractTree for IndexExpression {
|
|||||||
Ok(abstract_node)
|
Ok(abstract_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
IndexExpression::Value(value_node) => value_node.run(source, context),
|
IndexExpression::Value(value_node) => value_node.run(source, context),
|
||||||
|
@ -88,6 +88,10 @@ impl AbstractTree for Logic {
|
|||||||
Ok(Value::Boolean(result))
|
Ok(Value::Boolean(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(Type::Boolean)
|
Ok(Type::Boolean)
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,10 @@ impl AbstractTree for Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
let (_, first_statement) = self.options.first().unwrap();
|
let (_, first_statement) = self.options.first().unwrap();
|
||||||
|
|
||||||
|
@ -62,6 +62,10 @@ impl AbstractTree for Math {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.left.expected_type(context)
|
self.left.expected_type(context)
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,18 @@ impl AbstractTree for Root {
|
|||||||
Ok(Root { statements })
|
Ok(Root { statements })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
for statement in &self.statements {
|
||||||
|
if let Statement::Return(inner_statement) = statement {
|
||||||
|
return inner_statement.check_type(_source, _context);
|
||||||
|
} else {
|
||||||
|
statement.check_type(_source, _context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
let mut value = Value::none();
|
let mut value = Value::none();
|
||||||
|
|
||||||
@ -95,5 +107,8 @@ 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>;
|
||||||
|
|
||||||
|
/// Verify the type compatibility of this node.
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()>;
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type>;
|
fn expected_type(&self, context: &Map) -> Result<Type>;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,22 @@ impl AbstractTree for Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Statement::Assignment(assignment) => assignment.check_type(_source, _context),
|
||||||
|
Statement::Expression(expression) => expression.check_type(_source, _context),
|
||||||
|
Statement::IfElse(if_else) => if_else.check_type(_source, _context),
|
||||||
|
Statement::Match(r#match) => r#match.check_type(_source, _context),
|
||||||
|
Statement::While(r#while) => r#while.check_type(_source, _context),
|
||||||
|
Statement::Block(block) => block.check_type(_source, _context),
|
||||||
|
Statement::For(r#for) => r#for.check_type(_source, _context),
|
||||||
|
Statement::IndexAssignment(index_assignment) => {
|
||||||
|
index_assignment.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
Statement::Return(statement) => statement.check_type(_source, _context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.expected_type(context),
|
Statement::Assignment(assignment) => assignment.expected_type(context),
|
||||||
|
@ -38,6 +38,10 @@ impl AbstractTree for TypeDefinition {
|
|||||||
self.r#type.run(source, context)
|
self.r#type.run(source, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
self.r#type.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.r#type.expected_type(context)
|
self.r#type.expected_type(context)
|
||||||
}
|
}
|
||||||
@ -239,6 +243,10 @@ impl AbstractTree for Type {
|
|||||||
Ok(r#type)
|
Ok(r#type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
@ -77,10 +77,6 @@ impl AbstractTree for ValueNode {
|
|||||||
let statement =
|
let statement =
|
||||||
Statement::from_syntax_node(source, child_syntax_node, context)?;
|
Statement::from_syntax_node(source, child_syntax_node, context)?;
|
||||||
|
|
||||||
if let Some(type_definition) = ¤t_type {
|
|
||||||
type_definition.check(&statement.expected_type(context)?)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
child_nodes.insert(current_key.clone(), (statement, current_type.clone()));
|
child_nodes.insert(current_key.clone(), (statement, current_type.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,6 +118,38 @@ impl AbstractTree for ValueNode {
|
|||||||
Ok(value_node)
|
Ok(value_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
ValueNode::Function(function) => function.check_type(_source, context)?,
|
||||||
|
ValueNode::List(expression_list) => {
|
||||||
|
for expression in expression_list {
|
||||||
|
expression.check_type(_source, context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValueNode::BuiltInValue(built_in_value) => {
|
||||||
|
built_in_value.check_type(_source, context)?
|
||||||
|
}
|
||||||
|
ValueNode::Map(map) => {
|
||||||
|
for (_, (statement, r#type)) in map {
|
||||||
|
statement.check_type(_source, context)?;
|
||||||
|
|
||||||
|
if let Some(r#type) = r#type {
|
||||||
|
r#type.check_type(_source, context)?;
|
||||||
|
r#type.check(&statement.expected_type(context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValueNode::Option(option) => {
|
||||||
|
if let Some(expression) = option {
|
||||||
|
expression.check_type(_source, context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
|
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
|
||||||
|
@ -25,6 +25,11 @@ impl AbstractTree for While {
|
|||||||
Ok(While { expression, block })
|
Ok(While { expression, block })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
self.expression.check_type(_source, _context)?;
|
||||||
|
self.block.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> 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, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
self.call.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
self.call.run(source, context)
|
self.call.run(source, context)
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,7 @@ impl Interpreter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(abstract_tree) = &self.abstract_tree {
|
if let Some(abstract_tree) = &self.abstract_tree {
|
||||||
|
abstract_tree.check_type(source, &self.context)?;
|
||||||
abstract_tree.run(source, &self.context)
|
abstract_tree.run(source, &self.context)
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
|
@ -93,11 +93,6 @@ impl AbstractTree for Function {
|
|||||||
let body_node = node.child(child_count - 1).unwrap();
|
let body_node = node.child(child_count - 1).unwrap();
|
||||||
let body = Block::from_syntax_node(source, body_node, &function_context)?;
|
let body = Block::from_syntax_node(source, body_node, &function_context)?;
|
||||||
|
|
||||||
return_type
|
|
||||||
.inner()
|
|
||||||
.check(&body.expected_type(&function_context)?)
|
|
||||||
.map_err(|error| error.at_node(body_node, source))?;
|
|
||||||
|
|
||||||
let r#type = Type::function(parameter_types, return_type.take_inner());
|
let r#type = Type::function(parameter_types, return_type.take_inner());
|
||||||
|
|
||||||
Ok(Self::ContextDefined(ContextDefinedFunction::new(
|
Ok(Self::ContextDefined(ContextDefinedFunction::new(
|
||||||
@ -105,6 +100,19 @@ impl AbstractTree for Function {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Function::BuiltIn(_built_in_function) => {}
|
||||||
|
Function::ContextDefined(function) => {
|
||||||
|
function
|
||||||
|
.return_type()
|
||||||
|
.check(&function.body.expected_type(&context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||||
Ok(Value::Function(self.clone()))
|
Ok(Value::Function(self.clone()))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user