1
0

Begin implementing type arguments

This commit is contained in:
Jeff 2024-03-24 12:21:08 -04:00
parent a0a9bc2fdf
commit 6b0bb0016f
16 changed files with 139 additions and 78 deletions

View File

@ -161,7 +161,7 @@ impl AbstractNode for Assignment {
#[cfg(test)]
mod tests {
use crate::{
abstract_tree::{Expression, ValueNode},
abstract_tree::{Expression, ValueNode, WithPos},
error::TypeConflict,
};

View File

@ -51,7 +51,7 @@ impl AbstractNode for Block {
#[cfg(test)]
mod tests {
use crate::{
abstract_tree::{Expression, ValueNode},
abstract_tree::{Expression, ValueNode, WithPos},
Value,
};

View File

@ -1,7 +1,7 @@
use crate::{
context::Context,
error::{RuntimeError, ValidationError},
value::ValueInner,
value::{Function, ParsedFunction, ValueInner},
};
use super::{AbstractNode, Action, Expression, Type, WithPosition};
@ -32,7 +32,7 @@ impl AbstractNode for FunctionCall {
let function_node_type = self.function.node.expected_type(_context)?;
if let Type::Function { return_type, .. } = function_node_type {
Ok(*return_type)
Ok(return_type.node)
} else {
Err(ValidationError::ExpectedFunction {
actual: function_node_type,
@ -41,14 +41,31 @@ impl AbstractNode for FunctionCall {
}
}
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
for expression in &self.arguments {
expression.node.validate(_context)?;
expression.node.validate(context)?;
}
let function_node_type = self.function.node.expected_type(_context)?;
let function_node_type = self.function.node.expected_type(context)?;
if let Type::Function {
parameter_types,
return_type: _,
} = function_node_type
{
for (type_parameter, type_argument) in
parameter_types.iter().zip(self.type_arguments.iter())
{
type_parameter
.node
.check(&type_argument.node)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
actual_position: type_argument.position,
expected_position: type_parameter.position,
})?;
}
if let Type::Function { .. } = function_node_type {
Ok(())
} else {
Err(ValidationError::ExpectedFunction {
@ -94,6 +111,21 @@ impl AbstractNode for FunctionCall {
let function_context = Context::new();
if let Function::Parsed(ParsedFunction {
type_parameters, ..
}) = function
{
for (type_parameter, type_argument) in type_parameters
.iter()
.map(|r#type| r#type.node.clone())
.zip(self.type_arguments.into_iter().map(|r#type| r#type.node))
{
if let Type::Argument(identifier) = type_parameter {
function_context.set_type(identifier, type_argument)?;
}
}
};
function_context.inherit_data_from(&context)?;
function.clone().call(arguments, function_context)
}

View File

@ -95,7 +95,7 @@ impl AbstractNode for IfElse {
#[cfg(test)]
mod tests {
use crate::{
abstract_tree::{Statement, ValueNode},
abstract_tree::{Statement, ValueNode, WithPos},
Value,
};

View File

@ -90,7 +90,7 @@ impl AbstractNode for ListIndex {
let found_item = list.get(index as usize);
if let Some(item) = found_item {
Ok(Action::Return(item.clone()))
Ok(Action::Return(item.node.clone()))
} else {
Ok(Action::None)
}

View File

@ -187,7 +187,7 @@ impl AbstractNode for Logic {
#[cfg(test)]
mod tests {
use crate::abstract_tree::ValueNode;
use crate::abstract_tree::{ValueNode, WithPos};
use super::*;

View File

@ -70,7 +70,8 @@ impl Ord for Loop {
mod tests {
use crate::{
abstract_tree::{
Assignment, AssignmentOperator, Block, Expression, Identifier, IfElse, Logic, ValueNode,
Assignment, AssignmentOperator, Block, Expression, Identifier, IfElse, Logic,
ValueNode, WithPos,
},
Value,
};
@ -99,19 +100,19 @@ mod tests {
.with_position((0, 0)),
Statement::Loop(Loop::new(vec![Statement::IfElse(IfElse::new(
Expression::Logic(Box::new(Logic::Greater(
Expression::Identifier(Identifier::new("i")).with_position((10, 11)),
Expression::Value(ValueNode::Integer(2)).with_position((14, 15)),
Expression::Identifier(Identifier::new("i")).with_position((0, 0)),
Expression::Value(ValueNode::Integer(2)).with_position((0, 0)),
)))
.with_position((10, 15)),
Block::new(vec![Statement::Break.with_position((18, 24))]),
.with_position((0, 0)),
Block::new(vec![Statement::Break.with_position((0, 0))]),
Some(Block::new(vec![Statement::Assignment(Assignment::new(
Identifier::new("i").with_position((0, 0)),
None,
AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
.with_position((38, 39)),
.with_position((0, 0)),
))
.with_position((33, 39))])),
.with_position((0, 0))])),
))
.with_position((0, 0))]))
.with_position((0, 0)),

View File

@ -52,6 +52,17 @@ pub struct WithPosition<T> {
pub position: SourcePosition,
}
pub trait WithPos: Sized {
fn with_position<T: Into<SourcePosition>>(self, span: T) -> WithPosition<Self> {
WithPosition {
node: self,
position: span.into(),
}
}
}
impl<T> WithPos for T {}
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct SourcePosition(pub usize, pub usize);
@ -164,11 +175,4 @@ pub trait AbstractNode: Sized {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError>;
fn validate(&self, context: &Context) -> Result<(), ValidationError>;
fn run(self, context: &Context) -> Result<Action, RuntimeError>;
fn with_position<T: Into<SourcePosition>>(self, span: T) -> WithPosition<Self> {
WithPosition {
node: self,
position: span.into(),
}
}
}

View File

@ -17,13 +17,13 @@ pub enum Type {
Boolean,
Float,
Function {
parameter_types: Vec<Type>,
return_type: Box<Type>,
parameter_types: Vec<WithPosition<Type>>,
return_type: Box<WithPosition<Type>>,
},
Integer,
List,
ListOf(Box<Type>),
ListExact(Vec<Type>),
ListOf(Box<WithPosition<Type>>),
ListExact(Vec<WithPosition<Type>>),
Map,
None,
Range,
@ -52,27 +52,27 @@ impl Type {
| (Type::Range, Type::Range)
| (Type::String, Type::String) => return Ok(()),
(Type::ListOf(left), Type::ListOf(right)) => {
if let Ok(()) = left.check(right) {
if let Ok(()) = left.node.check(&right.node) {
return Ok(());
}
}
(Type::ListOf(list_of), Type::ListExact(list_exact)) => {
for r#type in list_exact {
list_of.check(r#type)?;
list_of.node.check(&r#type.node)?;
}
return Ok(());
}
(Type::ListExact(list_exact), Type::ListOf(list_of)) => {
for r#type in list_exact {
r#type.check(&list_of)?;
r#type.node.check(&list_of.node)?;
}
return Ok(());
}
(Type::ListExact(left), Type::ListExact(right)) => {
for (left, right) in left.iter().zip(right.iter()) {
left.check(right)?;
left.node.check(&right.node)?;
}
return Ok(());
@ -149,15 +149,15 @@ impl Display for Type {
Type::Float => write!(f, "float"),
Type::Integer => write!(f, "int"),
Type::List => write!(f, "list"),
Type::ListOf(item_type) => write!(f, "list({item_type})"),
Type::ListOf(item_type) => write!(f, "list({})", item_type.node),
Type::ListExact(item_types) => {
write!(f, "[")?;
for (index, item_type) in item_types.into_iter().enumerate() {
if index == item_types.len() - 1 {
write!(f, "{item_type}")?;
write!(f, "{}", item_type.node)?;
} else {
write!(f, "{item_type}, ")?;
write!(f, "{}, ", item_type.node)?;
}
}
@ -174,10 +174,10 @@ impl Display for Type {
write!(f, "(")?;
for r#type in parameter_types {
write!(f, "{} ", r#type)?;
write!(f, "{} ", r#type.node)?;
}
write!(f, ") : {return_type}")
write!(f, ") : {}", return_type.node)
}
Type::Structure { name, .. } => write!(f, "{name}"),
Type::Argument(_) => todo!(),
@ -187,6 +187,8 @@ impl Display for Type {
#[cfg(test)]
mod tests {
use crate::abstract_tree::WithPos;
use super::*;
#[test]
@ -197,12 +199,14 @@ mod tests {
assert_eq!(Type::Integer.check(&Type::Integer), Ok(()));
assert_eq!(Type::List.check(&Type::List), Ok(()));
assert_eq!(
Type::ListOf(Box::new(Type::Integer)).check(&Type::ListOf(Box::new(Type::Integer))),
Type::ListOf(Box::new(Type::Integer.with_position((0, 0))))
.check(&Type::ListOf(Box::new(Type::Integer.with_position((0, 0))))),
Ok(())
);
assert_eq!(
Type::ListExact(vec![Type::Float]).check(&Type::ListExact(vec![Type::Float])),
Type::ListExact(vec![Type::Float.with_position((0, 0))])
.check(&Type::ListExact(vec![Type::Float.with_position((0, 0))])),
Ok(())
);
assert_eq!(Type::Map.check(&Type::Map), Ok(()));
@ -237,8 +241,8 @@ mod tests {
Type::Float,
Type::Integer,
Type::List,
Type::ListOf(Box::new(Type::Boolean)),
Type::ListExact(vec![Type::Integer]),
Type::ListOf(Box::new(Type::Boolean.with_position((0, 0)))),
Type::ListExact(vec![Type::Integer.with_position((0, 0))]),
Type::Map,
Type::None,
Type::Range,
@ -263,8 +267,11 @@ mod tests {
#[test]
fn check_list_types() {
let list = Type::List;
let list_exact = Type::ListExact(vec![Type::Integer, Type::Integer]);
let list_of = Type::ListOf(Box::new(Type::Integer));
let list_exact = Type::ListExact(vec![
Type::Integer.with_position((0, 0)),
Type::Integer.with_position((0, 0)),
]);
let list_of = Type::ListOf(Box::new(Type::Integer.with_position((0, 0))));
assert_eq!(list.check(&list_exact), Ok(()));
assert_eq!(list.check(&list_of), Ok(()));

View File

@ -7,7 +7,7 @@ use crate::{
Value,
};
use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPosition};
use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPos, WithPosition};
#[derive(Clone, Debug, PartialEq)]
pub enum ValueNode {
@ -47,7 +47,12 @@ impl AbstractNode for ValueNode {
let mut item_types = Vec::with_capacity(items.len());
for expression in items {
item_types.push(expression.node.expected_type(context)?);
item_types.push(
expression
.node
.expected_type(context)?
.with_position(expression.position),
);
}
Type::ListExact(item_types)
@ -61,10 +66,10 @@ impl AbstractNode for ValueNode {
..
} => Type::Function {
parameter_types: parameters
.into_iter()
.map(|(_, r#type)| r#type.node.clone())
.iter()
.map(|(_, r#type)| r#type.clone())
.collect(),
return_type: Box::new(return_type.node.clone()),
return_type: Box::new(return_type.clone()),
},
ValueNode::Structure {
name,
@ -185,7 +190,10 @@ impl AbstractNode for ValueNode {
for expression in expression_list {
let action = expression.node.run(_context)?;
let value = if let Action::Return(value) = action {
value
WithPosition {
node: value,
position: expression.position,
}
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(expression.position),

View File

@ -74,7 +74,7 @@ impl AbstractNode for While {
#[cfg(test)]
mod tests {
use crate::abstract_tree::{
Assignment, AssignmentOperator, Block, Identifier, Logic, ValueNode,
Assignment, AssignmentOperator, Block, Identifier, Logic, ValueNode, WithPos,
};
use super::*;

View File

@ -6,7 +6,7 @@ use std::{
};
use crate::{
abstract_tree::{Action, Type},
abstract_tree::{Action, Type, WithPos},
context::Context,
error::RuntimeError,
value::ValueInner,
@ -36,8 +36,8 @@ impl BuiltInFunction {
pub fn r#type(&self) -> Type {
match self {
BuiltInFunction::WriteLine => Type::Function {
parameter_types: vec![Type::String],
return_type: Box::new(Type::None),
parameter_types: vec![Type::String.with_position((0, 0))],
return_type: Box::new(Type::None.with_position((0, 0))),
},
_ => {
todo!()

View File

@ -121,8 +121,8 @@ pub fn parser<'src>() -> impl Parser<
}
}),
))
})
.map_with(|r#type, state| r#type.with_position(state.span()));
.map_with(|r#type, state| r#type.with_position(state.span()))
});
let type_argument = identifier
.clone()
@ -759,7 +759,10 @@ mod tests {
parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0].node,
Statement::Assignment(Assignment::new(
Identifier::new("foobar").with_position((0, 6)),
Some(Type::ListOf(Box::new(Type::Boolean)).with_position((9, 19))),
Some(
Type::ListOf(Box::new(Type::Boolean.with_position((14, 18))))
.with_position((9, 19))
),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value(
ValueNode::Boolean(true)
@ -776,7 +779,13 @@ mod tests {
parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new(
Identifier::new("foobar").with_position((0, 6)),
Some(Type::ListExact(vec![Type::Boolean, Type::String]).with_position((9, 20))),
Some(
Type::ListExact(vec![
Type::Boolean.with_position((10, 14)),
Type::String.with_position((16, 19))
])
.with_position((9, 20))
),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Boolean(true)).with_position((24, 28)),
@ -797,7 +806,7 @@ mod tests {
Some(
Type::Function {
parameter_types: vec![],
return_type: Box::new(Type::Any)
return_type: Box::new(Type::Any.with_position((17, 20)))
}
.with_position((9, 20))
),

View File

@ -13,7 +13,7 @@ use stanza::{
};
use crate::{
abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPosition},
abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPos, WithPosition},
built_in_functions::BuiltInFunction,
context::Context,
error::{RuntimeError, ValidationError},
@ -39,7 +39,7 @@ impl Value {
Value(Arc::new(ValueInner::Integer(integer)))
}
pub fn list(list: Vec<Value>) -> Self {
pub fn list(list: Vec<WithPosition<Value>>) -> Self {
Value(Arc::new(ValueInner::List(list)))
}
@ -63,7 +63,7 @@ impl Value {
) -> Self {
Value(Arc::new(ValueInner::Function(Function::Parsed(
ParsedFunction {
type_arguments,
type_parameters: type_arguments,
parameters,
return_type,
body,
@ -91,7 +91,7 @@ impl Value {
}
}
pub fn as_list(&self) -> Option<&Vec<Value>> {
pub fn as_list(&self) -> Option<&Vec<WithPosition<Value>>> {
if let ValueInner::List(list) = self.inner().as_ref() {
Some(list)
} else {
@ -122,7 +122,7 @@ impl Display for Value {
let mut table = create_table();
for value in list {
table = table.with_row([value.to_string()]);
table = table.with_row([value.node.to_string()]);
}
write!(f, "{}", Console::default().render(&table))
@ -139,7 +139,7 @@ impl Display for Value {
ValueInner::Range(_) => todo!(),
ValueInner::String(string) => write!(f, "{string}"),
ValueInner::Function(Function::Parsed(ParsedFunction {
type_arguments,
type_parameters: type_arguments,
parameters,
return_type,
body,
@ -202,7 +202,7 @@ pub enum ValueInner {
Float(f64),
Function(Function),
Integer(i64),
List(Vec<Value>),
List(Vec<WithPosition<Value>>),
Map(BTreeMap<Identifier, Value>),
Range(Range<i64>),
String(String),
@ -222,7 +222,7 @@ impl ValueInner {
let mut types = Vec::with_capacity(values.len());
for value in values {
types.push(value.r#type(context)?);
types.push(value.node.r#type(context)?.with_position(value.position));
}
Type::ListExact(types)
@ -235,9 +235,9 @@ impl ValueInner {
parameter_types: parsed_function
.parameters
.iter()
.map(|(_, r#type)| r#type.node.clone())
.map(|(_, r#type)| r#type.clone())
.collect(),
return_type: Box::new(parsed_function.return_type.node.clone()),
return_type: Box::new(parsed_function.return_type.clone()),
},
Function::BuiltIn(built_in_function) => {
built_in_function.clone().as_value().r#type(context)?
@ -343,8 +343,8 @@ impl Function {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct ParsedFunction {
type_arguments: Vec<WithPosition<Type>>,
parameters: Vec<(Identifier, WithPosition<Type>)>,
return_type: WithPosition<Type>,
body: WithPosition<Block>,
pub type_parameters: Vec<WithPosition<Type>>,
pub parameters: Vec<(Identifier, WithPosition<Type>)>,
pub return_type: WithPosition<Type>,
pub body: WithPosition<Block>,
}

View File

@ -1,7 +1,7 @@
use std::{collections::BTreeMap, rc::Rc};
use dust_lang::{
abstract_tree::{Identifier, Type},
abstract_tree::{Identifier, Type, WithPos},
error::{Error, TypeConflict, ValidationError},
*,
};
@ -100,9 +100,9 @@ fn list() {
assert_eq!(
interpret(Rc::new("test".to_string()), "[1, 2, 'foobar']"),
Ok(Some(Value::list(vec![
Value::integer(1),
Value::integer(2),
Value::string("foobar".to_string()),
Value::integer(1).with_position((1, 2)),
Value::integer(2).with_position((4, 5)),
Value::string("foobar".to_string()).with_position((7, 15)),
])))
);
}

View File

@ -1,7 +1,7 @@
use std::rc::Rc;
use dust_lang::{
abstract_tree::{AbstractNode, Block, Expression, Identifier, Statement, Type},
abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos},
error::{Error, TypeConflict, ValidationError},
*,
};