This commit is contained in:
Jeff 2023-11-30 05:40:39 -05:00
parent 3dc78a7066
commit 57b06df9c2
4 changed files with 143 additions and 26 deletions

View File

@ -1,7 +1,9 @@
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, TypeDefinition, Value}; use crate::{
AbstractTree, Error, Function, 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 {
@ -56,6 +58,45 @@ impl AbstractTree for Assignment {
let statement_node = node.child_by_field_name("statement").unwrap(); let statement_node = node.child_by_field_name("statement").unwrap();
let statement = Statement::from_syntax_node(source, statement_node, context)?; let statement = Statement::from_syntax_node(source, statement_node, context)?;
if let Some(type_definition) = &type_definition {
let statement_type = statement.expected_type(context)?;
match operator {
AssignmentOperator::Equal => {
type_definition.abstract_check(
&statement_type,
context,
statement_node,
source,
)?;
}
AssignmentOperator::PlusEqual => {
let identifier_type = identifier.expected_type(context)?;
type_definition.abstract_check(
&identifier_type,
context,
type_node.unwrap(),
source,
)?;
let type_definition = if let Type::List(item_type) = type_definition.inner() {
TypeDefinition::new(item_type.as_ref().clone())
} else {
type_definition.clone()
};
type_definition.abstract_check(
&statement_type,
context,
statement_node,
source,
)?;
}
AssignmentOperator::MinusEqual => todo!(),
}
}
Ok(Assignment { Ok(Assignment {
identifier, identifier,
type_definition, type_definition,
@ -72,13 +113,19 @@ impl AbstractTree for Assignment {
AssignmentOperator::PlusEqual => { AssignmentOperator::PlusEqual => {
if let Some(mut previous_value) = context.variables()?.get(key).cloned() { if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
if let Ok(list) = previous_value.as_list() { if let Ok(list) = previous_value.as_list() {
let first_item_type = if let Some(first) = list.items().first() { let item_type = if let Some(type_defintion) = &self.type_definition {
if let Type::List(item_type) = type_defintion.inner() {
TypeDefinition::new(item_type.as_ref().clone())
} else {
TypeDefinition::new(Type::Empty)
}
} else if let Some(first) = list.items().first() {
first.r#type(context)? first.r#type(context)?
} else { } else {
TypeDefinition::new(Type::Any) TypeDefinition::new(Type::Any)
}; };
first_item_type.check(&value.r#type(context)?, context)?; item_type.runtime_check(&value.r#type(context)?, context)?;
} }
previous_value += value; previous_value += value;
@ -95,15 +142,24 @@ impl AbstractTree for Assignment {
return Err(Error::VariableIdentifierNotFound(key.clone())); return Err(Error::VariableIdentifierNotFound(key.clone()));
} }
} }
AssignmentOperator::Equal => { AssignmentOperator::Equal => value,
if let Some(type_definition) = &self.type_definition { };
let new_value_type = value.r#type(context)?;
type_definition.check(&new_value_type, context)?; let new_value = if let Some(type_definition) = &self.type_definition {
} let new_value_type = new_value.r#type(context)?;
value type_definition.runtime_check(&new_value_type, context)?;
if let Value::Function(function) = new_value {
Value::Function(Function::new(
function.parameters().clone(),
function.body().clone(),
))
} else {
new_value
} }
} else {
new_value
}; };
context.variables_mut()?.insert(key.clone(), new_value); context.variables_mut()?.insert(key.clone(), new_value);
@ -115,3 +171,49 @@ impl AbstractTree for Assignment {
Ok(TypeDefinition::new(Type::Empty)) Ok(TypeDefinition::new(Type::Empty))
} }
} }
#[cfg(test)]
mod tests {
use crate::{evaluate, List, Value};
#[test]
fn simple_assignment() {
let test = evaluate("x = 1 x").unwrap();
assert_eq!(Value::Integer(1), test);
}
#[test]
fn simple_assignment_with_type() {
let test = evaluate("x <int> = 1 x").unwrap();
assert_eq!(Value::Integer(1), test);
}
#[test]
fn list_add_assign() {
let test = evaluate(
"
x <list int> = []
x += 1
x
",
)
.unwrap();
assert_eq!(Value::List(List::with_items(vec![Value::Integer(1)])), test);
}
#[test]
fn function_assignment() {
let test = evaluate(
"
foobar <fn str -> str> = |text| { 'hi' }
foobar
",
)
.unwrap();
assert_eq!(Value::String("hi".to_string()), test);
}
}

View File

@ -23,7 +23,23 @@ impl TypeDefinition {
self.r#type self.r#type
} }
pub fn check(&self, other: &TypeDefinition, context: &Map) -> Result<()> { pub fn abstract_check(
&self,
other: &TypeDefinition,
context: &Map,
node: Node,
source: &str,
) -> Result<()> {
self.runtime_check(other, context)
.map_err(|_| Error::TypeCheck {
expected: self.clone(),
actual: other.clone(),
location: node.start_position(),
source: source[node.byte_range()].to_string(),
})
}
pub fn runtime_check(&self, other: &TypeDefinition, context: &Map) -> Result<()> {
match (&self.r#type, &other.r#type) { match (&self.r#type, &other.r#type) {
(Type::Any, _) (Type::Any, _)
| (_, Type::Any) | (_, Type::Any)
@ -43,7 +59,7 @@ impl TypeDefinition {
let self_defintion = TypeDefinition::new(self_item_type.as_ref().clone()); let self_defintion = TypeDefinition::new(self_item_type.as_ref().clone());
let other_definition = &TypeDefinition::new(other_item_type.as_ref().clone()); let other_definition = &TypeDefinition::new(other_item_type.as_ref().clone());
self_defintion.check(other_definition, context) self_defintion.runtime_check(other_definition, context)
} }
_ => Err(Error::RuntimeTypeCheck { _ => Err(Error::RuntimeTypeCheck {
expected: self.clone(), expected: self.clone(),
@ -85,8 +101,8 @@ pub enum Type {
Empty, Empty,
Float, Float,
Function { Function {
parameter_types: Vec<TypeDefinition>, parameter_types: Vec<Type>,
return_type: Box<TypeDefinition>, return_type: Box<Type>,
}, },
Integer, Integer,
List(Box<Type>), List(Box<Type>),
@ -115,7 +131,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(TypeDefinition::new(parameter_type)); parameter_types.push(parameter_type);
} }
let return_type_node = node.child(child_count - 1).unwrap(); let return_type_node = node.child(child_count - 1).unwrap();
@ -123,7 +139,7 @@ impl AbstractTree for Type {
Type::Function { Type::Function {
parameter_types, parameter_types,
return_type: Box::new(TypeDefinition::new(return_type)), return_type: Box::new(return_type),
} }
} }
"int" => Type::Integer, "int" => Type::Integer,

View File

@ -12,6 +12,10 @@ pub struct Function {
} }
impl Function { impl Function {
pub fn new(parameters: Vec<Identifier>, body: Block) -> Self {
Self { parameters, body }
}
pub fn parameters(&self) -> &Vec<Identifier> { pub fn parameters(&self) -> &Vec<Identifier> {
&self.parameters &self.parameters
} }
@ -44,13 +48,11 @@ impl AbstractTree for Function {
} }
fn run(&self, source: &str, context: &Map) -> Result<Value> { fn run(&self, source: &str, context: &Map) -> Result<Value> {
let return_value = self.body.run(source, context)?; self.body.run(source, context)
Ok(return_value)
} }
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> { fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
self.body.expected_type(context) Value::Function(self.clone()).r#type(context)
} }
} }

View File

@ -69,13 +69,10 @@ impl Value {
Value::Map(_) => Type::Map, Value::Map(_) => Type::Map,
Value::Table(_) => Type::Table, Value::Table(_) => Type::Table,
Value::Function(function) => { Value::Function(function) => {
let parameter_types = Vec::new(); let parameters = function.parameters();
let parameter_types = vec![Type::Any; parameters.len()];
for identifier in function.parameters() { let body = function.body();
let _type = identifier.expected_type(context)?; let return_type = body.expected_type(context)?.take_inner();
}
let return_type = function.body().expected_type(context)?;
Type::Function { Type::Function {
parameter_types, parameter_types,