diff --git a/dust-lang/src/compiler.rs b/dust-lang/src/compiler.rs index 22e60a8..e577672 100644 --- a/dust-lang/src/compiler.rs +++ b/dust-lang/src/compiler.rs @@ -131,7 +131,7 @@ impl<'src> Compiler<'src> { loop { self.parse(Precedence::None)?; - if self.is_eof() || self.allow(Token::RightBrace)? { + if matches!(self.current_token, Token::Eof | Token::RightBrace) { self.parse_implicit_return()?; break; @@ -150,7 +150,9 @@ impl<'src> Compiler<'src> { .iter() .rev() .find_map(|(instruction, _, _)| { - if instruction.yields_value() { + let is_get_local = matches!(instruction.operation(), Operation::GetLocal); + + if instruction.yields_value() && !is_get_local { Some(instruction.a() + 1) } else { None @@ -627,11 +629,15 @@ impl<'src> Compiler<'src> { }; let operator = self.current_token; let operator_position = self.current_position; + + Compiler::expect_addable_type(&left_type, &left_position)?; + let rule = ParseRule::from(&operator); let is_assignment = matches!( operator, Token::PlusEqual | Token::MinusEqual | Token::StarEqual | Token::SlashEqual ); + let r#type = if is_assignment { Type::None } else { @@ -647,7 +653,7 @@ impl<'src> Compiler<'src> { if push_back_left { self.instructions - .push((left_instruction, left_type, left_position)); + .push((left_instruction, left_type.clone(), left_position)); } self.advance()?; @@ -656,6 +662,9 @@ impl<'src> Compiler<'src> { let (right_instruction, right_type, right_position) = self.pop_last_instruction()?; let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?; + Compiler::expect_addable_type(&right_type, &right_position)?; + Compiler::expect_addable_types(&left_type, &left_position, &right_type, &right_position)?; + if push_back_right { self.instructions .push((right_instruction, right_type, right_position)); @@ -986,7 +995,7 @@ impl<'src> Compiler<'src> { } let destination = Destination::Register(self.next_register()); - let end = self.current_position.1; + let end = self.previous_position.1; let load_list = Instruction::from(LoadList { destination, start_register, @@ -1357,7 +1366,7 @@ impl<'src> Compiler<'src> { let mut value_parameters: Option> = None; - while function_compiler.current_token != Token::RightParenthesis { + while !function_compiler.allow(Token::RightParenthesis)? { let is_mutable = function_compiler.allow(Token::Mut)?; let parameter = if let Token::Identifier(text) = function_compiler.current_token { function_compiler.advance()?; @@ -1398,8 +1407,6 @@ impl<'src> Compiler<'src> { function_compiler.allow(Token::Comma)?; } - function_compiler.advance()?; - let return_type = if function_compiler.allow(Token::ArrowThin)? { let r#type = function_compiler.parse_type_from( function_compiler.current_token, @@ -1417,6 +1424,9 @@ impl<'src> Compiler<'src> { function_compiler.expect(Token::LeftBrace)?; function_compiler.compile()?; + function_compiler.expect(Token::RightBrace)?; + + let function_end = function_compiler.previous_position.1; self.previous_token = function_compiler.previous_token; self.previous_position = function_compiler.previous_position; @@ -1426,7 +1436,6 @@ impl<'src> Compiler<'src> { let function = ConcreteValue::Function(function_compiler.finish(None, value_parameters.clone())); let constant_index = self.push_or_get_constant(function); - let function_end = self.current_position.1; let register = self.next_register(); let function_type = FunctionType { type_parameters: None, @@ -1514,6 +1523,7 @@ impl<'src> Compiler<'src> { let start = self.current_position.0; self.advance()?; + self.expect(Token::LeftParenthesis)?; let mut argument_count = 0; @@ -1595,6 +1605,42 @@ impl<'src> Compiler<'src> { Ok(()) } + + fn expect_addable_type(argument_type: &Type, position: &Span) -> Result<(), CompileError> { + if matches!( + argument_type, + Type::Byte | Type::Character | Type::Float | Type::Integer | Type::String + ) { + Ok(()) + } else { + Err(CompileError::CannotAddType { + argument_type: argument_type.clone(), + position: *position, + }) + } + } + + fn expect_addable_types( + left: &Type, + left_position: &Span, + right: &Type, + right_position: &Span, + ) -> Result<(), CompileError> { + if matches!( + (left, right), + (Type::Integer, Type::Integer) + | (Type::Float, Type::Float) + | (Type::String, Type::String), + ) { + Ok(()) + } else { + Err(CompileError::CannotAddArguments { + left_type: left.clone(), + right_type: right.clone(), + position: Span(left_position.0, right_position.1), + }) + } + } } /// Operator precedence levels. @@ -1977,6 +2023,24 @@ pub enum CompileError { }, // Type errors + CannotAddType { + argument_type: Type, + position: Span, + }, + CannotAddArguments { + left_type: Type, + right_type: Type, + position: Span, + }, + CannotSubtractLeft { + argument_type: Type, + position: Span, + }, + CannotSubtract { + left_type: Type, + right_type: Type, + position: Span, + }, CannotResolveRegisterType { register_index: usize, position: Span, @@ -2034,10 +2098,14 @@ impl AnnotatedError for CompileError { fn description(&self) -> &'static str { match self { + Self::CannotAddArguments { .. } => "Cannot add these types", + Self::CannotAddType { .. } => "Cannot add to this type", Self::CannotChainComparison { .. } => "Cannot chain comparison operations", Self::CannotMutateImmutableVariable { .. } => "Cannot mutate immutable variable", Self::CannotResolveRegisterType { .. } => "Cannot resolve register type", Self::CannotResolveVariableType { .. } => "Cannot resolve type", + Self::CannotSubtract { .. } => "Cannot subtract these types", + Self::CannotSubtractLeft { .. } => "Cannot subtract from this type", Self::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds", Self::ExpectedExpression { .. } => "Expected an expression", Self::ExpectedFunction { .. } => "Expected a function", @@ -2133,10 +2201,14 @@ impl AnnotatedError for CompileError { fn position(&self) -> Span { match self { + Self::CannotAddArguments { position, .. } => *position, + Self::CannotAddType { position, .. } => *position, Self::CannotChainComparison { position } => *position, Self::CannotMutateImmutableVariable { position, .. } => *position, Self::CannotResolveRegisterType { position, .. } => *position, Self::CannotResolveVariableType { position, .. } => *position, + Self::CannotSubtract { position, .. } => *position, + Self::CannotSubtractLeft { position, .. } => *position, Self::ConstantIndexOutOfBounds { position, .. } => *position, Self::ExpectedExpression { position, .. } => *position, Self::ExpectedFunction { position, .. } => *position, diff --git a/dust-lang/tests/functions.rs b/dust-lang/tests/functions.rs index de353d2..9a46ed9 100644 --- a/dust-lang/tests/functions.rs +++ b/dust-lang/tests/functions.rs @@ -26,7 +26,7 @@ fn function() { ), Span(30, 31) ), - (Instruction::r#return(true), Span(35, 35)), + (Instruction::r#return(true), Span(34, 35)), ], vec![ConcreteValue::string("a"), ConcreteValue::string("b"),], vec![ @@ -53,7 +53,7 @@ fn function_call() { vec![ ( Instruction::load_constant(Destination::Register(0), 0, false), - Span(0, 36) + Span(0, 35) ), ( Instruction::load_constant(Destination::Register(1), 1, false), @@ -86,7 +86,7 @@ fn function_call() { ), Span(30, 31) ), - (Instruction::r#return(true), Span(35, 36)), + (Instruction::r#return(true), Span(34, 35)), ], vec![ConcreteValue::string("a"), ConcreteValue::string("b"),], vec![ @@ -142,7 +142,7 @@ fn function_declaration() { ), Span(35, 36) ), - (Instruction::r#return(true), Span(40, 40)), + (Instruction::r#return(true), Span(39, 40)), ], vec![ConcreteValue::string("a"), ConcreteValue::string("b")], vec![ diff --git a/dust-lang/tests/type_errors_add.rs b/dust-lang/tests/type_errors_add.rs new file mode 100644 index 0000000..a140e95 --- /dev/null +++ b/dust-lang/tests/type_errors_add.rs @@ -0,0 +1,160 @@ +use dust_lang::*; + +#[test] +fn add_boolean_left() { + let source = "true + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Boolean, + position: Span(0, 4) + }, + source, + }) + ); +} + +#[test] +fn add_boolean_right() { + let source = "1 + true"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Boolean, + position: Span(4, 8) + }, + source, + }) + ); +} + +#[test] +fn add_function_left() { + let source = "fn(){} + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Function(FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::None) + }), + position: Span(0, 6) + }, + source, + }) + ); +} + +#[test] +fn add_function_right() { + let source = "1 + fn(){}"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Function(FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::None) + }), + position: Span(4, 10) + }, + source, + }) + ); +} + +#[test] +fn add_list_left() { + let source = "[1, 2] + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::List(Box::new(Type::Integer)), + position: Span(0, 6) + }, + source, + }) + ); +} + +#[test] +fn add_list_right() { + let source = "1 + [1, 2]"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::List(Box::new(Type::Integer)), + position: Span(4, 10) + }, + source, + }) + ); +} + +// #[test] +// fn add_range_left() { +// todo!("Add ranges") +// } + +// #[test] +// fn add_range_right() { +// todo!("Add ranges") +// } + +#[test] +fn add_character_and_float() { + let source = "'a' + 1.0"; +} + +#[test] +fn add_character_and_integer() { + todo!() +} + +#[test] +fn add_character_and_string() { + todo!() +} + +#[test] +fn add_float_and_character() { + todo!() +} + +#[test] +fn add_float_and_integer() { + todo!() +} + +#[test] +fn add_float_and_string() { + todo!() +} + +#[test] +fn add_integer_and_character() { + todo!() +} + +#[test] +fn add_integer_and_float() { + todo!() +} + +#[test] +fn add_integer_and_string() { + todo!() +}