Fix tests; Implement type generics

This commit is contained in:
Jeff 2024-06-17 17:38:24 -04:00
parent d53ddd07eb
commit cddf199156
9 changed files with 131 additions and 109 deletions

View File

@ -44,6 +44,9 @@ impl AbstractNode for Expression {
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
match self { match self {
Expression::As(r#as) => r#as.node.validate(context, manage_memory), Expression::As(r#as) => r#as.node.validate(context, manage_memory),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.node.validate(context, manage_memory)
}
Expression::FunctionCall(function_call) => { Expression::FunctionCall(function_call) => {
function_call.node.validate(context, manage_memory) function_call.node.validate(context, manage_memory)
} }
@ -68,9 +71,6 @@ impl AbstractNode for Expression {
Expression::Logic(logic) => logic.node.validate(context, manage_memory), Expression::Logic(logic) => logic.node.validate(context, manage_memory),
Expression::Math(math) => math.node.validate(context, manage_memory), Expression::Math(math) => math.node.validate(context, manage_memory),
Expression::Value(value_node) => value_node.node.validate(context, manage_memory), Expression::Value(value_node) => value_node.node.validate(context, manage_memory),
Expression::BuiltInFunctionCall(built_in_function_call) => {
built_in_function_call.node.validate(context, manage_memory)
}
} }
} }

View File

@ -3,6 +3,7 @@ pub mod assignment;
pub mod async_block; pub mod async_block;
pub mod block; pub mod block;
pub mod built_in_function_call; pub mod built_in_function_call;
pub mod expression;
pub mod function_call; pub mod function_call;
pub mod if_else; pub mod if_else;
pub mod list_index; pub mod list_index;
@ -15,7 +16,6 @@ pub mod structure_definition;
pub mod r#type; pub mod r#type;
pub mod type_alias; pub mod type_alias;
pub mod type_constructor; pub mod type_constructor;
pub mod value_expression;
pub mod value_node; pub mod value_node;
pub mod r#while; pub mod r#while;
@ -29,6 +29,7 @@ pub use self::{
async_block::AsyncBlock, async_block::AsyncBlock,
block::Block, block::Block,
built_in_function_call::BuiltInFunctionCall, built_in_function_call::BuiltInFunctionCall,
expression::Expression,
function_call::FunctionCall, function_call::FunctionCall,
if_else::IfElse, if_else::IfElse,
list_index::ListIndex, list_index::ListIndex,
@ -43,7 +44,6 @@ pub use self::{
structure_definition::StructureDefinition, structure_definition::StructureDefinition,
type_alias::TypeAssignment, type_alias::TypeAssignment,
type_constructor::{FunctionTypeConstructor, ListTypeConstructor, TypeConstructor}, type_constructor::{FunctionTypeConstructor, ListTypeConstructor, TypeConstructor},
value_expression::Expression,
value_node::ValueNode, value_node::ValueNode,
}; };

View File

@ -21,6 +21,7 @@ pub enum Type {
value_parameters: Vec<(Identifier, Type)>, value_parameters: Vec<(Identifier, Type)>,
return_type: Box<Type>, return_type: Box<Type>,
}, },
Generic(Option<Box<Type>>),
Integer, Integer,
List { List {
length: usize, length: usize,
@ -49,8 +50,19 @@ impl Type {
| (Type::None, Type::None) | (Type::None, Type::None)
| (Type::Range, Type::Range) | (Type::Range, Type::Range)
| (Type::String, Type::String) => return Ok(()), | (Type::String, Type::String) => return Ok(()),
(Type::Generic(left), Type::Generic(right)) => match (left, right) {
(Some(left), Some(right)) => {
if left.check(&right).is_ok() {
return Ok(());
}
}
(None, None) => {
return Ok(());
}
_ => {}
},
(Type::ListOf(left), Type::ListOf(right)) => { (Type::ListOf(left), Type::ListOf(right)) => {
if let Ok(()) = left.check(&right) { if left.check(&right).is_ok() {
return Ok(()); return Ok(());
} }
} }
@ -195,6 +207,13 @@ impl Display for Type {
Type::Any => write!(f, "any"), Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"), Type::Boolean => write!(f, "bool"),
Type::Float => write!(f, "float"), Type::Float => write!(f, "float"),
Type::Generic(type_option) => {
if let Some(concrete_type) = type_option {
write!(f, "implied to be {concrete_type}")
} else {
todo!()
}
}
Type::Integer => write!(f, "int"), Type::Integer => write!(f, "int"),
Type::List { length, item_type } => write!(f, "[{length}; {}]", item_type), Type::List { length, item_type } => write!(f, "[{length}; {}]", item_type),
Type::ListOf(item_type) => write!(f, "list({})", item_type), Type::ListOf(item_type) => write!(f, "list({})", item_type),

View File

@ -26,7 +26,7 @@ pub enum ValueNode {
name: WithPosition<Identifier>, name: WithPosition<Identifier>,
fields: Vec<(WithPosition<Identifier>, Expression)>, fields: Vec<(WithPosition<Identifier>, Expression)>,
}, },
Parsed { Function {
type_parameters: Option<Vec<Identifier>>, type_parameters: Option<Vec<Identifier>>,
value_parameters: Vec<(Identifier, TypeConstructor)>, value_parameters: Vec<(Identifier, TypeConstructor)>,
return_type: TypeConstructor, return_type: TypeConstructor,
@ -57,8 +57,8 @@ impl AbstractNode for ValueNode {
return Ok(()); return Ok(());
} }
if let ValueNode::Parsed { if let ValueNode::Function {
type_parameters: _, type_parameters,
value_parameters, value_parameters,
return_type, return_type,
body, body,
@ -66,6 +66,12 @@ impl AbstractNode for ValueNode {
{ {
let mut function_context = Context::new(Some(&context)); let mut function_context = Context::new(Some(&context));
if let Some(type_parameters) = type_parameters {
for identifier in type_parameters {
function_context.set_type(identifier.clone(), Type::Generic(None))?;
}
}
for (identifier, type_constructor) in value_parameters { for (identifier, type_constructor) in value_parameters {
let r#type = type_constructor.clone().construct(&function_context)?; let r#type = type_constructor.clone().construct(&function_context)?;
@ -175,18 +181,14 @@ impl AbstractNode for ValueNode {
} }
ValueNode::Range(range) => Value::range(range), ValueNode::Range(range) => Value::range(range),
ValueNode::String(string) => Value::string(string), ValueNode::String(string) => Value::string(string),
ValueNode::Parsed { ValueNode::Function {
type_parameters, type_parameters,
value_parameters: constructors, value_parameters: constructors,
return_type, return_type,
body, body,
} => { } => {
let type_parameters = type_parameters.map(|parameter_list| { let type_parameters =
parameter_list type_parameters.map(|parameter_list| parameter_list.into_iter().collect());
.into_iter()
.map(|parameter| parameter)
.collect()
});
let mut value_parameters = Vec::with_capacity(constructors.len()); let mut value_parameters = Vec::with_capacity(constructors.len());
for (identifier, constructor) in constructors { for (identifier, constructor) in constructors {
@ -263,13 +265,13 @@ impl Ord for ValueNode {
(String(left), String(right)) => left.cmp(right), (String(left), String(right)) => left.cmp(right),
(String(_), _) => Ordering::Greater, (String(_), _) => Ordering::Greater,
( (
Parsed { Function {
type_parameters: left_type_arguments, type_parameters: left_type_arguments,
value_parameters: left_parameters, value_parameters: left_parameters,
return_type: left_return, return_type: left_return,
body: left_body, body: left_body,
}, },
Parsed { Function {
type_parameters: right_type_arguments, type_parameters: right_type_arguments,
value_parameters: right_parameters, value_parameters: right_parameters,
return_type: right_return, return_type: right_return,
@ -296,7 +298,7 @@ impl Ord for ValueNode {
parameter_cmp parameter_cmp
} }
} }
(Parsed { .. }, _) => Ordering::Greater, (Function { .. }, _) => Ordering::Greater,
( (
Structure { Structure {
name: left_name, name: left_name,
@ -337,7 +339,7 @@ impl ExpectedType for ValueNode {
ValueNode::Map(_) => Type::Map, ValueNode::Map(_) => Type::Map,
ValueNode::Range(_) => Type::Range, ValueNode::Range(_) => Type::Range,
ValueNode::String(_) => Type::String, ValueNode::String(_) => Type::String,
ValueNode::Parsed { ValueNode::Function {
type_parameters, type_parameters,
value_parameters, value_parameters,
return_type, return_type,

View File

@ -26,6 +26,10 @@ impl<'a> Context<'a> {
} }
} }
pub fn create_child<'b>(&'b self) -> Context<'b> {
Context::new(Some(self))
}
pub fn inner( pub fn inner(
&self, &self,
) -> Result<RwLockReadGuard<BTreeMap<Identifier, (VariableData, UsageData)>>, RwLockPoisonError> ) -> Result<RwLockReadGuard<BTreeMap<Identifier, (VariableData, UsageData)>>, RwLockPoisonError>

View File

@ -10,16 +10,16 @@ use crate::{
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
Parse {
expected: String,
span: (usize, usize),
found: Option<String>,
},
Lex { Lex {
expected: String, expected: String,
span: (usize, usize), span: (usize, usize),
reason: String, reason: String,
}, },
Parse {
expected: String,
span: (usize, usize),
found: Option<String>,
},
Runtime { Runtime {
error: RuntimeError, error: RuntimeError,
position: SourcePosition, position: SourcePosition,

View File

@ -237,11 +237,7 @@ impl InterpreterError {
} else { } else {
format!("Expected {expected}.") format!("Expected {expected}.")
}; };
let found = found.unwrap_or_else(|| "End of input".to_string());
let label_message = format!(
"{} is not valid in this position.",
found.unwrap_or_else(|| String::with_capacity(0))
);
( (
Report::build( Report::build(
@ -252,7 +248,7 @@ impl InterpreterError {
.with_message(description) .with_message(description)
.with_label( .with_label(
Label::new((self.source_id.clone(), span.0..span.1)) Label::new((self.source_id.clone(), span.0..span.1))
.with_message(label_message) .with_message(format!("{found} is not valid in this position."))
.with_color(Color::Red), .with_color(Color::Red),
), ),
None, None,

View File

@ -246,7 +246,7 @@ pub fn parser<'src>(
.map_with( .map_with(
|(((type_parameters, value_parameters), return_type), body), state| { |(((type_parameters, value_parameters), return_type), body), state| {
Expression::Value( Expression::Value(
ValueNode::Parsed { ValueNode::Function {
type_parameters, type_parameters,
value_parameters, value_parameters,
return_type, return_type,
@ -640,6 +640,73 @@ mod tests {
use super::*; use super::*;
// Reuse these tests when structures are reimplemented
// #[test]
// fn structure_instance() {
// assert_eq!(
// parse(
// &lex("
// Foo {
// bar = 42,
// baz = 'hiya',
// }
// ")
// .unwrap()
// )
// .unwrap()[0],
// Statement::Expression(Expression::Value(
// ValueNode::Structure {
// name: Identifier::new("Foo").with_position((21, 24)),
// fields: vec![
// (
// Identifier::new("bar").with_position((0, 0)),
// Expression::Value(ValueNode::Integer(42).with_position((57, 59)))
// ),
// (
// Identifier::new("baz").with_position((0, 0)),
// Expression::Value(
// ValueNode::String("hiya".to_string()).with_position((91, 97))
// )
// ),
// ]
// }
// .with_position((21, 120))
// ))
// )
// }
// #[test]
// fn structure_definition() {
// assert_eq!(
// parse(
// &lex("
// struct Foo {
// bar : int,
// baz : str,
// }
// ")
// .unwrap()
// )
// .unwrap()[0],
// Statement::StructureDefinition(
// StructureDefinition::new(
// Identifier::new("Foo"),
// vec![
// (
// Identifier::new("bar"),
// TypeConstructor::Type(Type::Integer.with_position((64, 67)))
// ),
// (
// Identifier::new("baz"),
// TypeConstructor::Type(Type::String.with_position((99, 102)))
// ),
// ]
// )
// .with_position((21, 125))
// )
// )
// }
#[test] #[test]
fn type_alias() { fn type_alias() {
assert_eq!( assert_eq!(
@ -743,72 +810,6 @@ mod tests {
) )
} }
#[test]
fn structure_instance() {
assert_eq!(
parse(
&lex("
Foo {
bar = 42,
baz = 'hiya',
}
")
.unwrap()
)
.unwrap()[0],
Statement::Expression(Expression::Value(
ValueNode::Structure {
name: Identifier::new("Foo").with_position((21, 24)),
fields: vec![
(
Identifier::new("bar").with_position((0, 0)),
Expression::Value(ValueNode::Integer(42).with_position((57, 59)))
),
(
Identifier::new("baz").with_position((0, 0)),
Expression::Value(
ValueNode::String("hiya".to_string()).with_position((91, 97))
)
),
]
}
.with_position((21, 120))
))
)
}
#[test]
fn structure_definition() {
assert_eq!(
parse(
&lex("
struct Foo {
bar : int,
baz : str,
}
")
.unwrap()
)
.unwrap()[0],
Statement::StructureDefinition(
StructureDefinition::new(
Identifier::new("Foo"),
vec![
(
Identifier::new("bar"),
TypeConstructor::Type(Type::Integer.with_position((64, 67)))
),
(
Identifier::new("baz"),
TypeConstructor::Type(Type::String.with_position((99, 102)))
),
]
)
.with_position((21, 125))
)
)
}
#[test] #[test]
fn map_index() { fn map_index() {
assert_eq!( assert_eq!(
@ -912,23 +913,23 @@ mod tests {
#[test] #[test]
fn list_of_type() { fn list_of_type() {
assert_eq!( assert_eq!(
parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0], parse(&lex("foobar : [bool] = [true]").unwrap()).unwrap()[0],
Statement::Assignment( Statement::Assignment(
Assignment::new( Assignment::new(
Identifier::new("foobar").with_position((0, 6)), Identifier::new("foobar").with_position((0, 6)),
Some(TypeConstructor::ListOf( Some(TypeConstructor::ListOf(
Box::new(TypeConstructor::Type(Type::Boolean.with_position((9, 19)))) Box::new(TypeConstructor::Type(Type::Boolean.with_position((10, 14))))
.with_position((0, 0)) .with_position((9, 15))
)), )),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value( Statement::Expression(Expression::Value(
ValueNode::List(vec![Expression::Value( ValueNode::List(vec![Expression::Value(
ValueNode::Boolean(true).with_position((23, 27)) ValueNode::Boolean(true).with_position((19, 23))
)]) )])
.with_position((22, 28)) .with_position((18, 24))
)) ))
) )
.with_position((0, 28)) .with_position((0, 24))
) )
); );
} }
@ -1009,7 +1010,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(&lex("fn () -> int { 0 }").unwrap()).unwrap()[0], parse(&lex("fn () -> int { 0 }").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value( Statement::Expression(Expression::Value(
ValueNode::Parsed { ValueNode::Function {
type_parameters: None, type_parameters: None,
value_parameters: vec![], value_parameters: vec![],
return_type: TypeConstructor::Type(Type::Integer.with_position((9, 12))), return_type: TypeConstructor::Type(Type::Integer.with_position((9, 12))),
@ -1025,7 +1026,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(&lex("fn (x: int) -> int { x }").unwrap()).unwrap()[0], parse(&lex("fn (x: int) -> int { x }").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value( Statement::Expression(Expression::Value(
ValueNode::Parsed { ValueNode::Function {
type_parameters: None, type_parameters: None,
value_parameters: vec![( value_parameters: vec![(
Identifier::new("x"), Identifier::new("x"),
@ -1047,7 +1048,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(&lex("fn T, U (x: T, y: U) -> T { x }").unwrap()).unwrap()[0], parse(&lex("fn T, U (x: T, y: U) -> T { x }").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value( Statement::Expression(Expression::Value(
ValueNode::Parsed { ValueNode::Function {
type_parameters: Some(vec![Identifier::new("T"), Identifier::new("U"),]), type_parameters: Some(vec![Identifier::new("T"), Identifier::new("U"),]),
value_parameters: vec![ value_parameters: vec![
( (

View File

@ -1,5 +1,5 @@
json = { json = {
parse = fn (T)(input: str) -> T { parse = fn T (input: str) -> T {
JSON_PARSE T input JSON_PARSE T input
} }
} }