diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 7d027eb..8eee03c 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -125,6 +125,10 @@ impl<'src> Lexer<'src> { self.position += 2; (Token::MinusEqual, Span(self.position - 2, self.position)) + } else if let Some('>') = second_char { + self.position += 2; + + (Token::ArrowThin, Span(self.position - 2, self.position)) } else if let Some('0'..='9') = second_char { self.lex_numeric()? } else if "-Infinity" == self.peek_chars(9) { diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 1b86c34..52db07c 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -1111,6 +1111,20 @@ impl<'src> Parser<'src> { } function_parser.advance()?; + + let return_type = if function_parser.allow(Token::ArrowThin)? { + let r#type = function_parser.parse_type_from( + function_parser.current_token, + function_parser.current_position, + )?; + + function_parser.advance()?; + + Some(Box::new(r#type)) + } else { + None + }; + function_parser.expect(Token::LeftCurlyBrace)?; while function_parser.current_token != Token::RightCurlyBrace { @@ -1131,7 +1145,6 @@ impl<'src> Parser<'src> { self.current_token = function_parser.current_token; self.current_position = function_parser.current_position; - let return_type = take(&mut self.latest_value_type).map(Box::new); let function_type = FunctionType { type_parameters: None, value_parameters, @@ -1300,6 +1313,11 @@ struct ParseRule<'a> { impl From<&Token<'_>> for ParseRule<'_> { fn from(token: &Token) -> Self { match token { + Token::ArrowThin => ParseRule { + prefix: Some(Parser::expect_expression), + infix: None, + precedence: Precedence::None, + }, Token::Async => todo!(), Token::Bang => ParseRule { prefix: Some(Parser::parse_unary), diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index 5360fc7..432feaf 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -38,6 +38,7 @@ pub enum Token<'src> { While, // Symbols + ArrowThin, BangEqual, Bang, Colon, @@ -84,6 +85,7 @@ impl<'src> Token<'src> { Token::Integer(text) => text.len(), Token::String(text) => text.len() + 2, Token::Async => 5, + Token::ArrowThin => 2, Token::Bool => 4, Token::Break => 5, Token::Else => 4, @@ -144,6 +146,7 @@ impl<'src> Token<'src> { Token::Integer(text) => text, Token::String(text) => text, Token::Async => "async", + Token::ArrowThin => "->", Token::Bool => "bool", Token::Break => "break", Token::Else => "else", @@ -195,6 +198,7 @@ impl<'src> Token<'src> { pub fn to_owned(&self) -> TokenOwned { match self { + Token::ArrowThin => TokenOwned::ArrowThin, Token::Async => TokenOwned::Async, Token::BangEqual => TokenOwned::BangEqual, Token::Bang => TokenOwned::Bang, @@ -255,6 +259,7 @@ impl<'src> Token<'src> { pub fn kind(&self) -> TokenKind { match self { + Token::ArrowThin => TokenKind::ArrowThin, Token::Async => TokenKind::Async, Token::BangEqual => TokenKind::BangEqual, Token::Bang => TokenKind::Bang, @@ -359,6 +364,7 @@ impl<'src> Token<'src> { impl<'src> Display for Token<'src> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { + Token::ArrowThin => write!(f, "->"), Token::Async => write!(f, "async"), Token::BangEqual => write!(f, "!="), Token::Bang => write!(f, "!"), @@ -436,6 +442,7 @@ pub enum TokenOwned { String(String), // Keywords + Async, Bool, Break, Else, @@ -452,7 +459,7 @@ pub enum TokenOwned { While, // Symbols - Async, + ArrowThin, Bang, BangEqual, Colon, @@ -490,6 +497,7 @@ pub enum TokenOwned { impl Display for TokenOwned { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { + TokenOwned::ArrowThin => Token::ArrowThin.fmt(f), TokenOwned::Async => Token::Async.fmt(f), TokenOwned::Bang => Token::Bang.fmt(f), TokenOwned::BangEqual => Token::BangEqual.fmt(f), @@ -581,6 +589,7 @@ pub enum TokenKind { While, // Symbols + ArrowThin, BangEqual, Bang, Colon, @@ -619,6 +628,7 @@ pub enum TokenKind { impl Display for TokenKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { + TokenKind::ArrowThin => Token::ArrowThin.fmt(f), TokenKind::Async => Token::Async.fmt(f), TokenKind::Bang => Token::Bang.fmt(f), TokenKind::BangEqual => Token::BangEqual.fmt(f), diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index 5632359..32a22c4 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -316,6 +316,36 @@ fn equality_assignment_short() { assert_eq!(run(source), Ok(Some(Value::boolean(true)))); } +#[test] +fn function() { + let source = "fn(a: int, b: int) -> int { a + b }"; + + assert_eq!( + run(source), + Ok(Some(Value::function( + Chunk::with_data( + vec![ + (Instruction::add(2, 0, 1), Span(30, 31)), + (Instruction::r#return(true), Span(34, 35)), + ], + vec![], + vec![ + Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0), + Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1) + ] + ), + FunctionType { + type_parameters: None, + value_parameters: Some(vec![ + (Identifier::new("a"), Type::Integer), + (Identifier::new("b"), Type::Integer) + ]), + return_type: Some(Box::new(Type::Integer)), + } + ))) + ); +} + #[test] fn greater() { let source = "1 > 2";