diff --git a/Cargo.toml b/Cargo.toml index 11a0238..4f68ac5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dust-lang" -description = "Data-Oriented Programming Language" +description = "General purpose programming language" version = "0.3.92" repository = "https://git.jeffa.io/jeff/dust.git" edition = "2021" diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 028e984..f03a240 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -152,51 +152,3 @@ impl AbstractTree for Assignment { Ok(Type::None) } } - -#[cfg(test)] -mod tests { - use crate::{interpret, Error, List, Type, Value}; - - #[test] - fn simple_assignment() { - let test = interpret("x = 1 x").unwrap(); - - assert_eq!(Value::Integer(1), test); - } - - #[test] - fn simple_assignment_with_type() { - let test = interpret("x = 1 x").unwrap(); - - assert_eq!(Value::Integer(1), test); - } - - #[test] - fn list_add_assign() { - let test = interpret( - " - x <[int]> = [] - x += 1 - x - ", - ) - .unwrap(); - - assert_eq!(Value::List(List::with_items(vec![Value::Integer(1)])), test); - } - - #[test] - fn list_add_wrong_type() { - let result = interpret( - " - x <[str]> = [] - x += 1 - ", - ); - - assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck { - expected: Type::String, - actual: Type::Integer - })) - } -} diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index 212e7c2..29a06d5 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -162,41 +162,3 @@ impl AbstractTree for FunctionCall { } } } - -#[cfg(test)] -mod tests { - use crate::{interpret, Value}; - - #[test] - fn evaluate_function_call() { - assert_eq!( - interpret( - " - foobar = (message ) -> { message } - foobar('Hiya') - ", - ), - Ok(Value::String("Hiya".to_string())) - ); - } - - #[test] - fn evaluate_callback() { - assert_eq!( - interpret( - " - foobar = (cb <() -> str>) { - cb() - } - foobar(() { 'Hiya' }) - ", - ), - Ok(Value::String("Hiya".to_string())) - ); - } - - #[test] - fn evaluate_built_in_function_call() { - assert_eq!(interpret("output('Hiya')"), Ok(Value::Option(None))); - } -} diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 7c6886c..a03717d 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -85,68 +85,3 @@ impl AbstractTree for IfElse { self.if_block.expected_type(context) } } - -#[cfg(test)] -mod tests { - use crate::{interpret, Value}; - - #[test] - fn evaluate_if() { - assert_eq!( - interpret("if true { 'true' }"), - Ok(Value::String("true".to_string())) - ); - } - - #[test] - fn evaluate_if_else() { - assert_eq!( - interpret("if false { 1 } else { 2 }"), - Ok(Value::Integer(2)) - ); - assert_eq!( - interpret("if true { 1.0 } else { 42.0 }"), - Ok(Value::Float(1.0)) - ); - } - - #[test] - fn evaluate_if_else_else_if_else() { - assert_eq!( - interpret( - " - if false { - 'no' - } else if 1 + 1 == 3 { - 'nope' - } else { - 'ok' - } - " - ), - Ok(Value::String("ok".to_string())) - ); - } - - #[test] - fn evaluate_if_else_if_else_if_else_if_else() { - assert_eq!( - interpret( - " - if false { - 'no' - } else if 1 + 1 == 1 { - 'nope' - } else if 9 / 2 == 4 { - 'nope' - } else if 'foo' == 'bar' { - 'nope' - } else { - 'ok' - } - " - ), - Ok(Value::String("ok".to_string())) - ); - } -} diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index d35708d..55e41cc 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -98,37 +98,3 @@ impl AbstractTree for Index { } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::interpret; - - #[test] - fn list_index() { - let test = interpret("x = [1 [2] 3] x:1:0").unwrap(); - - assert_eq!(Value::Integer(2), test); - } - - #[test] - fn map_index() { - let test = interpret("x = {y = {z = 2}} x:y:z").unwrap(); - - assert_eq!(Value::Integer(2), test); - } - - #[test] - fn complex_index() { - let test = interpret( - " - x = [1 2 3] - y = () -> { 0 } - x:y() - ", - ) - .unwrap(); - - assert_eq!(Value::Integer(1), test); - } -} diff --git a/src/abstract_tree/match.rs b/src/abstract_tree/match.rs index a146489..ad27c4e 100644 --- a/src/abstract_tree/match.rs +++ b/src/abstract_tree/match.rs @@ -82,41 +82,3 @@ impl AbstractTree for Match { first_statement.expected_type(context) } } - -#[cfg(test)] -mod tests { - use crate::{interpret, Value}; - - #[test] - fn evaluate_match() { - let test = interpret( - " - match 1 { - 3 => false - 2 => { false } - 1 => true - } - ", - ) - .unwrap(); - - assert_eq!(Value::Boolean(true), test); - } - - #[test] - fn evaluate_match_assignment() { - let test = interpret( - " - x = match 1 { - 3 => false - 2 => { false } - 1 => true - } - x - ", - ) - .unwrap(); - - assert_eq!(Value::Boolean(true), test); - } -} diff --git a/src/abstract_tree/type_definition.rs b/src/abstract_tree/type_definition.rs index e2019e8..1863072 100644 --- a/src/abstract_tree/type_definition.rs +++ b/src/abstract_tree/type_definition.rs @@ -258,43 +258,3 @@ impl Display for Type { } } } - -#[cfg(test)] -mod tests { - use crate::interpret; - - use super::*; - - #[test] - fn simple_type_check() { - let result = interpret("x = 1"); - - assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck { - expected: Type::Boolean, - actual: Type::Integer - })); - } - - #[test] - fn callback_type_check() { - let result = interpret( - " - x = (cb <() -> bool>) { - cb() - } - x(() { 1 }) - ", - ); - - assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck { - expected: Type::Function { - parameter_types: vec![], - return_type: Box::new(Type::Boolean), - }, - actual: Type::Function { - parameter_types: vec![], - return_type: Box::new(Type::Integer), - }, - })); - } -} diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 50aca67..f32d9bc 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -245,121 +245,3 @@ impl AbstractTree for ValueNode { Ok(type_definition) } } -#[cfg(test)] -mod tests { - use crate::{interpret, List}; - - use super::*; - - #[test] - fn evaluate_empty() { - assert_eq!(interpret("x = 9"), Ok(Value::Option(None))); - assert_eq!(interpret("x = 1 + 1"), Ok(Value::Option(None))); - } - - #[test] - fn evaluate_integer() { - assert_eq!(interpret("1"), Ok(Value::Integer(1))); - assert_eq!(interpret("123"), Ok(Value::Integer(123))); - assert_eq!(interpret("-666"), Ok(Value::Integer(-666))); - } - - #[test] - fn evaluate_float() { - assert_eq!(interpret("0.1"), Ok(Value::Float(0.1))); - assert_eq!(interpret("12.3"), Ok(Value::Float(12.3))); - assert_eq!(interpret("-6.66"), Ok(Value::Float(-6.66))); - } - - #[test] - fn evaluate_string() { - assert_eq!(interpret("\"one\""), Ok(Value::String("one".to_string()))); - assert_eq!(interpret("'one'"), Ok(Value::String("one".to_string()))); - assert_eq!(interpret("`one`"), Ok(Value::String("one".to_string()))); - assert_eq!(interpret("`'one'`"), Ok(Value::String("'one'".to_string()))); - assert_eq!(interpret("'`one`'"), Ok(Value::String("`one`".to_string()))); - assert_eq!( - interpret("\"'one'\""), - Ok(Value::String("'one'".to_string())) - ); - } - - #[test] - fn evaluate_list() { - assert_eq!( - interpret("[1, 2, 'foobar']"), - Ok(Value::List(List::with_items(vec![ - Value::Integer(1), - Value::Integer(2), - Value::String("foobar".to_string()), - ]))) - ); - } - - #[test] - fn evaluate_map() { - let map = Map::new(); - - map.set("x".to_string(), Value::Integer(1), None).unwrap(); - map.set("foo".to_string(), Value::String("bar".to_string()), None) - .unwrap(); - - assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map))); - } - - #[test] - fn evaluate_map_types() { - let map = Map::new(); - - map.set("x".to_string(), Value::Integer(1), Some(Type::Integer)) - .unwrap(); - map.set( - "foo".to_string(), - Value::String("bar".to_string()), - Some(Type::String), - ) - .unwrap(); - - assert_eq!( - interpret("{ x = 1, foo = 'bar' }"), - Ok(Value::Map(map)) - ); - } - - #[test] - fn evaluate_map_type_errors() { - assert!(interpret("{ foo = 'bar' }") - .unwrap_err() - .is_type_check_error(&Error::TypeCheck { - expected: Type::Boolean, - actual: Type::String - })) - } - - #[test] - fn evaluate_function() { - let result = interpret("() -> { 1 }"); - let value = result.unwrap(); - let function = value.as_function().unwrap(); - - assert_eq!(&Vec::::with_capacity(0), function.parameters()); - assert_eq!(Ok(&Type::Integer), function.return_type()); - - let result = interpret("(x ) -> {true}"); - let value = result.unwrap(); - let function = value.as_function().unwrap(); - - assert_eq!( - &vec![Identifier::new("x".to_string())], - function.parameters() - ); - assert_eq!(Ok(&Type::Boolean), function.return_type()); - } - - #[test] - fn evaluate_option() { - let result = interpret("x = some(1); x").unwrap(); - - assert_eq!(Value::Option(Some(Box::new(Value::Integer(1)))), result); - } -} diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs index 944b0fb..210e19e 100644 --- a/src/abstract_tree/while.rs +++ b/src/abstract_tree/while.rs @@ -37,13 +37,3 @@ impl AbstractTree for While { self.block.expected_type(context) } } - -#[cfg(test)] -mod tests { - use crate::{interpret, Value}; - - #[test] - fn evalualate_while_loop() { - assert_eq!(interpret("while false { 'foo' }"), Ok(Value::Option(None))) - } -} diff --git a/tests/interpret.rs b/tests/interpret.rs new file mode 100644 index 0000000..9c9bfc0 --- /dev/null +++ b/tests/interpret.rs @@ -0,0 +1,400 @@ +mod assignment { + use dust_lang::*; + + #[test] + fn simple_assignment() { + let test = interpret("x = 1 x"); + + assert_eq!(Ok(Value::Integer(1)), test); + } + + #[test] + fn simple_assignment_with_type() { + let test = interpret("x = 1 x"); + + assert_eq!(Ok(Value::Integer(1)), test); + } + + #[test] + fn list_add_assign() { + let test = interpret( + " + x <[int]> = [] + x += 1 + x + ", + ); + + assert_eq!( + Ok(Value::List(List::with_items(vec![Value::Integer(1)]))), + test + ); + } + + #[test] + fn list_add_wrong_type() { + let result = interpret( + " + x <[str]> = [] + x += 1 + ", + ); + + assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck { + expected: Type::String, + actual: Type::Integer + })) + } +} + +mod logic { + use dust_lang::*; + + #[test] + fn complex_logic_sequence() { + let result = + interpret("(length([0]) == 1) && (length([0 0]) == 2) && (length([0 0 0]) == 3)"); + + assert_eq!(Ok(Value::Boolean(true)), result); + } +} + +mod value { + use dust_lang::*; + + #[test] + fn interpret_empty() { + assert_eq!(interpret("x = 9"), Ok(Value::Option(None))); + assert_eq!(interpret("x = 1 + 1"), Ok(Value::Option(None))); + } + + #[test] + fn interpret_integer() { + assert_eq!(interpret("1"), Ok(Value::Integer(1))); + assert_eq!(interpret("123"), Ok(Value::Integer(123))); + assert_eq!(interpret("-666"), Ok(Value::Integer(-666))); + } + + #[test] + fn interpret_float() { + assert_eq!(interpret("0.1"), Ok(Value::Float(0.1))); + assert_eq!(interpret("12.3"), Ok(Value::Float(12.3))); + assert_eq!(interpret("-6.66"), Ok(Value::Float(-6.66))); + } + + #[test] + fn interpret_string() { + assert_eq!(interpret("\"one\""), Ok(Value::String("one".to_string()))); + assert_eq!(interpret("'one'"), Ok(Value::String("one".to_string()))); + assert_eq!(interpret("`one`"), Ok(Value::String("one".to_string()))); + assert_eq!(interpret("`'one'`"), Ok(Value::String("'one'".to_string()))); + assert_eq!(interpret("'`one`'"), Ok(Value::String("`one`".to_string()))); + assert_eq!( + interpret("\"'one'\""), + Ok(Value::String("'one'".to_string())) + ); + } + + #[test] + fn interpret_list() { + assert_eq!( + interpret("[1, 2, 'foobar']"), + Ok(Value::List(List::with_items(vec![ + Value::Integer(1), + Value::Integer(2), + Value::String("foobar".to_string()), + ]))) + ); + } + + #[test] + fn interpret_map() { + let map = Map::new(); + + map.set("x".to_string(), Value::Integer(1), None).unwrap(); + map.set("foo".to_string(), Value::String("bar".to_string()), None) + .unwrap(); + + assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map))); + } + + #[test] + fn interpret_map_types() { + let map = Map::new(); + + map.set("x".to_string(), Value::Integer(1), Some(Type::Integer)) + .unwrap(); + map.set( + "foo".to_string(), + Value::String("bar".to_string()), + Some(Type::String), + ) + .unwrap(); + + assert_eq!( + interpret("{ x = 1, foo = 'bar' }"), + Ok(Value::Map(map)) + ); + } + + #[test] + fn interpret_map_type_errors() { + assert!(interpret("{ foo = 'bar' }") + .unwrap_err() + .is_type_check_error(&Error::TypeCheck { + expected: Type::Boolean, + actual: Type::String + })) + } + + #[test] + fn interpret_function() { + let result = interpret("() -> { 1 }"); + let value = result.unwrap(); + let function = value.as_function().unwrap(); + + assert_eq!(&Vec::::with_capacity(0), function.parameters()); + assert_eq!(Ok(&Type::Integer), function.return_type()); + + let result = interpret("(x ) -> {true}"); + let value = result.unwrap(); + let function = value.as_function().unwrap(); + + assert_eq!( + &vec![Identifier::new("x".to_string())], + function.parameters() + ); + assert_eq!(Ok(&Type::Boolean), function.return_type()); + } + + #[test] + fn interpret_option() { + let result = interpret("x = some(1); x").unwrap(); + + assert_eq!(Value::Option(Some(Box::new(Value::Integer(1)))), result); + } +} + +mod function_call { + use dust_lang::*; + + #[test] + fn interpret_function_call() { + assert_eq!( + interpret( + " + foobar = (message ) -> { message } + foobar('Hiya') + ", + ), + Ok(Value::String("Hiya".to_string())) + ); + } + + #[test] + fn interpret_callback() { + assert_eq!( + interpret( + " + foobar = (cb <() -> str>) { + cb() + } + foobar(() { 'Hiya' }) + ", + ), + Ok(Value::String("Hiya".to_string())) + ); + } + + #[test] + fn interpret_built_in_function_call() { + assert_eq!(interpret("output('Hiya')"), Ok(Value::Option(None))); + } +} + +mod if_else { + use dust_lang::*; + + #[test] + fn interpret_if() { + assert_eq!( + interpret("if true { 'true' }"), + Ok(Value::String("true".to_string())) + ); + } + + #[test] + fn interpret_if_else() { + assert_eq!( + interpret("if false { 1 } else { 2 }"), + Ok(Value::Integer(2)) + ); + assert_eq!( + interpret("if true { 1.0 } else { 42.0 }"), + Ok(Value::Float(1.0)) + ); + } + + #[test] + fn interpret_if_else_else_if_else() { + assert_eq!( + interpret( + " + if false { + 'no' + } else if 1 + 1 == 3 { + 'nope' + } else { + 'ok' + } + " + ), + Ok(Value::String("ok".to_string())) + ); + } + + #[test] + fn interpret_if_else_if_else_if_else_if_else() { + assert_eq!( + interpret( + " + if false { + 'no' + } else if 1 + 1 == 1 { + 'nope' + } else if 9 / 2 == 4 { + 'nope' + } else if 'foo' == 'bar' { + 'nope' + } else { + 'ok' + } + " + ), + Ok(Value::String("ok".to_string())) + ); + } +} + +mod index { + use dust_lang::*; + + #[test] + fn list_index() { + let test = interpret("x = [1 [2] 3] x:1:0").unwrap(); + + assert_eq!(Value::Integer(2), test); + } + + #[test] + fn map_index() { + let test = interpret("x = {y = {z = 2}} x:y:z").unwrap(); + + assert_eq!(Value::Integer(2), test); + } + + #[test] + fn complex_index() { + let test = interpret( + " + x = [1 2 3] + y = () -> { 0 } + x:y() + ", + ) + .unwrap(); + + assert_eq!(Value::Integer(1), test); + } +} + +mod r#match { + use dust_lang::*; + + #[test] + fn interpret_match() { + let test = interpret( + " + match 1 { + 3 => false + 2 => { false } + 1 => true + } + ", + ) + .unwrap(); + + assert_eq!(Value::Boolean(true), test); + } + + #[test] + fn interpret_match_assignment() { + let test = interpret( + " + x = match 1 { + 3 => false + 2 => { false } + 1 => true + } + x + ", + ) + .unwrap(); + + assert_eq!(Value::Boolean(true), test); + } +} + +mod r#while { + use dust_lang::*; + + #[test] + fn interpret_while_loop() { + assert_eq!(interpret("while false { 'foo' }"), Ok(Value::Option(None))) + } + + #[test] + fn while_loop_iteration_count() { + assert_eq!( + interpret("i = 0; while i < 3 { i += 1 }; i"), + Ok(Value::Integer(3)) + ) + } +} + +mod type_definition { + use dust_lang::*; + + #[test] + fn simple_type_check() { + let result = interpret("x = 1"); + + assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck { + expected: Type::Boolean, + actual: Type::Integer + })); + } + + #[test] + fn callback_type_check() { + let result = interpret( + " + x = (cb <() -> bool>) { + cb() + } + x(() { 1 }) + ", + ); + + assert!(result.unwrap_err().is_type_check_error(&Error::TypeCheck { + expected: Type::Function { + parameter_types: vec![], + return_type: Box::new(Type::Boolean), + }, + actual: Type::Function { + parameter_types: vec![], + return_type: Box::new(Type::Integer), + }, + })); + } +} diff --git a/tree-sitter-dust/corpus/logic.txt b/tree-sitter-dust/corpus/logic.txt index 3cc09a3..9126f86 100644 --- a/tree-sitter-dust/corpus/logic.txt +++ b/tree-sitter-dust/corpus/logic.txt @@ -101,99 +101,3 @@ Complex Logic Sequence (expression (value (integer))))))))) - -================================================================================ -\== -================================================================================ - -3 == 1 + 1 + 1 - --------------------------------------------------------------------------------- - -(root - (statement - (expression - (math - (expression - (math - (expression - (logic - (expression - (value - (integer))) - (logic_operator) - (expression - (value - (integer))))) - (math_operator) - (expression - (value - (integer))))) - (math_operator) - (expression - (value - (integer))))))) - -================================================================================ -&& -================================================================================ - -4 + 2 == 42 && true - --------------------------------------------------------------------------------- - -(root - (statement - (expression - (logic - (expression - (logic - (expression - (math - (expression - (value - (integer))) - (math_operator) - (expression - (value - (integer))))) - (logic_operator) - (expression - (value - (integer))))) - (logic_operator) - (expression - (value - (boolean))))))) - -================================================================================ -\|| -================================================================================ - -4 + 2 == 42 || true - --------------------------------------------------------------------------------- - -(root - (statement - (expression - (logic - (expression - (logic - (expression - (math - (expression - (value - (integer))) - (math_operator) - (expression - (value - (integer))))) - (logic_operator) - (expression - (value - (integer))))) - (logic_operator) - (expression - (value - (boolean)))))))