1
0

Add seperate interpreter step for type checking

This commit is contained in:
Jeff 2024-01-03 12:09:00 -05:00
parent d1ac97507b
commit 4b22221322
23 changed files with 249 additions and 97 deletions

View File

@ -26,7 +26,6 @@ impl AbstractTree for Assignment {
let identifier_node = node.child(0).unwrap();
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_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 = 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_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()) {
r#type.clone()
} else {
statement_type
statement.expected_type(context)?
};
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> {
let key = self.identifier.inner();
let value = self.statement.run(source, context)?;

View File

@ -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> {
if self.is_async {
let statements = &self.statements;

View File

@ -140,6 +140,10 @@ impl AbstractTree for BuiltInValue {
Ok(built_in_value)
}
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
Ok(())
}
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
Ok(self.get().clone())
}

View File

@ -65,27 +65,39 @@ impl AbstractTree for Expression {
Ok(expression)
}
fn run(&self, source: &str, context: &Map) -> Result<Value> {
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
match self {
Expression::Value(value_node) => value_node.run(source, context),
Expression::Identifier(identifier) => identifier.run(source, context),
Expression::Math(math) => math.run(source, context),
Expression::Logic(logic) => logic.run(source, context),
Expression::FunctionCall(function_call) => function_call.run(source, context),
Expression::Index(index) => index.run(source, context),
Expression::Yield(r#yield) => r#yield.run(source, context),
Expression::Value(value_node) => value_node.run(_source, _context),
Expression::Identifier(identifier) => identifier.run(_source, _context),
Expression::Math(math) => math.run(_source, _context),
Expression::Logic(logic) => logic.run(_source, _context),
Expression::FunctionCall(function_call) => function_call.run(_source, _context),
Expression::Index(index) => index.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 {
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),
Expression::Value(value_node) => value_node.check_type(_source, _context),
Expression::Identifier(identifier) => identifier.check_type(_source, _context),
Expression::Math(math) => math.check_type(_source, _context),
Expression::Logic(logic) => logic.check_type(_source, _context),
Expression::FunctionCall(function_call) => function_call.check_type(_source, _context),
Expression::Index(index) => index.check_type(_source, _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),
}
}
}

View File

@ -74,6 +74,10 @@ impl AbstractTree for For {
Ok(Value::none())
}
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
Ok(())
}
fn expected_type(&self, _context: &Map) -> Result<Type> {
Ok(Type::None)
}

View File

@ -25,9 +25,7 @@ impl AbstractTree for FunctionCall {
let function_node = node.child(0).unwrap();
let function_expression =
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();
for index in 2..node.child_count() - 1 {
@ -35,48 +33,53 @@ impl AbstractTree for FunctionCall {
if child.is_named() {
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);
}
}
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 {
function_expression,
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> {
let (name, value) = match &self.function_expression {
FunctionExpression::Identifier(identifier) => {

View File

@ -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> {
match self {
FunctionExpression::Identifier(identifier) => identifier.expected_type(context),

View File

@ -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> {
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
Ok(r#type.clone())

View File

@ -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> {
self.if_block.expected_type(context)
}

View File

@ -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> {
match self.collection.expected_type(context)? {
Type::List(item_type) => Ok(*item_type.clone()),

View File

@ -91,6 +91,10 @@ impl AbstractTree for IndexAssignment {
Ok(Value::none())
}
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
Ok(())
}
fn expected_type(&self, _context: &Map) -> Result<Type> {
Ok(Type::None)
}

View File

@ -48,6 +48,10 @@ impl AbstractTree for IndexExpression {
Ok(abstract_node)
}
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
Ok(())
}
fn run(&self, source: &str, context: &Map) -> Result<Value> {
match self {
IndexExpression::Value(value_node) => value_node.run(source, context),

View File

@ -88,6 +88,10 @@ impl AbstractTree for Logic {
Ok(Value::Boolean(result))
}
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
Ok(())
}
fn expected_type(&self, _context: &Map) -> Result<Type> {
Ok(Type::Boolean)
}

View File

@ -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> {
let (_, first_statement) = self.options.first().unwrap();

View File

@ -62,6 +62,10 @@ impl AbstractTree for Math {
Ok(value)
}
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
Ok(())
}
fn expected_type(&self, context: &Map) -> Result<Type> {
self.left.expected_type(context)
}

View File

@ -59,6 +59,18 @@ impl AbstractTree for Root {
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> {
let mut value = Value::none();
@ -95,5 +107,8 @@ pub trait AbstractTree: Sized {
/// Execute dust code by traversing the tree.
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>;
}

View File

@ -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> {
match self {
Statement::Assignment(assignment) => assignment.expected_type(context),

View File

@ -38,6 +38,10 @@ impl AbstractTree for TypeDefinition {
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> {
self.r#type.expected_type(context)
}
@ -239,6 +243,10 @@ impl AbstractTree for Type {
Ok(r#type)
}
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
Ok(())
}
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
Ok(Value::none())
}

View File

@ -77,10 +77,6 @@ impl AbstractTree for ValueNode {
let statement =
Statement::from_syntax_node(source, child_syntax_node, context)?;
if let Some(type_definition) = &current_type {
type_definition.check(&statement.expected_type(context)?)?;
}
child_nodes.insert(current_key.clone(), (statement, current_type.clone()));
}
}
@ -122,6 +118,38 @@ impl AbstractTree for ValueNode {
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> {
let value = match self {
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),

View File

@ -25,6 +25,11 @@ impl AbstractTree for While {
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> {
while self.expression.run(source, context)?.as_boolean()? {
self.block.run(source, context)?;

View File

@ -44,6 +44,10 @@ impl AbstractTree for Yield {
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> {
self.call.run(source, context)
}

View File

@ -115,6 +115,7 @@ impl Interpreter {
};
if let Some(abstract_tree) = &self.abstract_tree {
abstract_tree.check_type(source, &self.context)?;
abstract_tree.run(source, &self.context)
} else {
Ok(Value::none())

View File

@ -93,11 +93,6 @@ impl AbstractTree for Function {
let body_node = node.child(child_count - 1).unwrap();
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());
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> {
Ok(Value::Function(self.clone()))
}