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 for_loop { use dust_lang::*; #[test] fn simple_for_loop() { let result = interpret("for i in [1 2 3] { output(i) }"); assert_eq!(Ok(Value::none()), result); } #[test] fn modify_value() { let result = interpret( " list = [] for i in [1 2 3] { list += i } list ", ); assert_eq!( Ok(Value::List(List::with_items(vec![ Value::Integer(1), Value::Integer(2), Value::Integer(3), ]))), result ); } } 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!(&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!(&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), }, })); } #[test] fn modify_value_async() { let result = interpret( " fn = (x ) { } fn(1) ", ); assert_eq!(Ok(Value::none()), result); } }