diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 15a6681..802eaee 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -106,6 +106,7 @@ pub struct LoopStmt { #[derive(Debug, Clone, PartialEq)] pub enum Expr { BinOp(BinOp), + UnaryOp(UnaryOp), FieldAccess(FieldAccess), Call(Call), Deref(Box), @@ -144,6 +145,21 @@ pub enum BinOpKind { Xor, } +#[derive(Debug, Clone, PartialEq)] +pub struct UnaryOp { + pub expr: Box, + pub kind: UnaryOpKind, + pub span: Span, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum UnaryOpKind { + Not, + Neg, + Deref, + AddrOf, +} + #[derive(Debug, Clone, PartialEq)] pub struct FieldAccess { pub expr: Box, diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs index f4e1c41..58fe932 100644 --- a/parser/src/lexer.rs +++ b/parser/src/lexer.rs @@ -53,7 +53,7 @@ pub enum Token<'a> { #[token("|")] Or, #[token("&")] - And, + Ampersand, #[token("||")] OrOr, #[token("&&")] @@ -119,7 +119,7 @@ impl<'a> Display for Token<'a> { Token::Plus => f.write_str("+"), Token::Minus => f.write_str("-"), Token::Or => f.write_str("|"), - Token::And => f.write_str("&"), + Token::Ampersand => f.write_str("&"), Token::OrOr => f.write_str("||"), Token::AndAnd => f.write_str("&&"), Token::Caret => f.write_str("^"), diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 4180609..0f915f7 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -5,7 +5,7 @@ use chumsky::{prelude::*, Stream}; use crate::{ ast::{ Assignment, BinOp, BinOpKind, Call, ElsePart, Expr, File, FnDecl, IfStmt, Item, Literal, - NameTyPair, Stmt, StructDecl, Ty, TyKind, VarDecl, WhileStmt, + NameTyPair, Stmt, StructDecl, Ty, TyKind, UnaryOp, UnaryOpKind, VarDecl, WhileStmt, }, lexer::Token, }; @@ -77,7 +77,7 @@ fn expr_parser<'src>() -> impl Parser, Expr, Error = Error<'src>> + .map(Expr::Array); let atom = literal - .or(ident_parser().map(|str| Expr::Name(str.to_owned()))) + .or(ident_parser().map(Expr::Name)) .or(array) .or(expr .clone() @@ -97,6 +97,14 @@ fn expr_parser<'src>() -> impl Parser, Expr, Error = Error<'src>> + }) }); + // let _unary_op = just(Token::Minus) + // .to(UnaryOpKind::Neg) + // .or(just(Token::Bang).to(UnaryOpKind::Not)) + // .or(just(Token::Asterisk).to(UnaryOpKind::Deref)) + // .or(just(Token::Ampersand).to(UnaryOpKind::AddrOf)); + + // todo: unary + let op = just(Token::Asterisk) .to(BinOpKind::Mul) .or(just(Token::Slash).to(BinOpKind::Div)); @@ -176,34 +184,27 @@ fn statement_parser<'src>() -> impl Parser, Stmt, Error = Error<'src }) }); + let block = stmt + .clone() + .repeated() + .delimited_by(just(Token::BraceO), just(Token::BraceC)); + let while_loop = just(Token::While) .ignore_then(expr_parser()) - .then( - stmt.clone() - .repeated() - .delimited_by(just(Token::BraceO), just(Token::BraceC)), - ) + .then(block.clone()) .map_with_span(|(cond, body), span| Stmt::WhileStmt(WhileStmt { cond, body, span })) .labelled("while loop"); let if_stmt = recursive(|if_stmt| { just(Token::If) .ignore_then(expr_parser()) - .then( - stmt.clone() - .repeated() - .delimited_by(just(Token::BraceO), just(Token::BraceC)), - ) + .then(block.clone()) .then( just(Token::Else) .ignore_then( if_stmt .map(|if_stmt| ElsePart::ElseIf(Box::new(if_stmt))) - .or(stmt - .clone() - .repeated() - .delimited_by(just(Token::BraceO), just(Token::BraceC)) - .map_with_span(ElsePart::Else)), + .or(block.clone().map_with_span(ElsePart::Else)), ) .or_not(), ) @@ -340,6 +341,19 @@ mod tests { insta::assert_debug_snapshot!(r); } + #[test] + fn unary() { + let r = parse( + "fn main() { + -(*5); + &5; + 2 + &8; + *6 * *8; // :) +}", + ); + insta::assert_debug_snapshot!(r); + } + #[test] fn function() { let r = parse("fn foo() -> u64 { 1 + 5; }"); @@ -378,7 +392,7 @@ mod tests { #[test] fn types() { - let r = parse("fn types() -> *u64 { Test test = 2; *Hello = true; }"); + let r = parse("fn types() -> *u64 { Test test = 2; *u64 int = 25; }"); insta::assert_debug_snapshot!(r); } } diff --git a/parser/src/snapshots/parser__lexer__tests__punctuation.snap b/parser/src/snapshots/parser__lexer__tests__punctuation.snap index 7307403..cc48eca 100644 --- a/parser/src/snapshots/parser__lexer__tests__punctuation.snap +++ b/parser/src/snapshots/parser__lexer__tests__punctuation.snap @@ -1,6 +1,6 @@ --- source: parser/src/lexer.rs -assertion_line: 110 +assertion_line: 158 expression: tokens --- [ @@ -26,7 +26,7 @@ expression: tokens Slash, Or, OrOr, - And, + Ampersand, AndAnd, Caret, Arrow, diff --git a/parser/src/snapshots/parser__parser__tests__types.snap b/parser/src/snapshots/parser__parser__tests__types.snap new file mode 100644 index 0000000..ae0b0c8 --- /dev/null +++ b/parser/src/snapshots/parser__parser__tests__types.snap @@ -0,0 +1,78 @@ +--- +source: parser/src/parser.rs +assertion_line: 382 +expression: r +--- +( + Some( + File { + name: "parser__parser__tests", + items: [ + FnDecl( + FnDecl { + name: "types", + params: [], + ret_ty: Some( + Ty { + span: 14..18, + kind: Ptr( + Ty { + span: 15..18, + kind: U64, + }, + ), + }, + ), + span: 0..52, + body: [ + VarDecl( + VarDecl { + name: "test", + ty: Ty { + span: 21..25, + kind: Name( + "Test", + ), + }, + rhs: Some( + Literal( + Integer( + 2, + 33..34, + ), + ), + ), + span: 0..0, + }, + ), + VarDecl( + VarDecl { + name: "int", + ty: Ty { + span: 36..40, + kind: Ptr( + Ty { + span: 37..40, + kind: U64, + }, + ), + }, + rhs: Some( + Literal( + Integer( + 25, + 47..49, + ), + ), + ), + span: 0..0, + }, + ), + ], + }, + ), + ], + }, + ), + [], +)