From 23cbe7fd4a048ba44aee647b3b7d5a7f3aa575da Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Aug 2018 16:34:54 +0300 Subject: Pratt --- src/grammar.ron | 25 ++++--- src/grammar/expressions.rs | 79 +++++++++++++++++++--- src/syntax_kinds/generated.rs | 36 +++++----- .../data/parser/inline/0074_expr_binding_power.rs | 3 + .../data/parser/inline/0074_expr_binding_power.txt | 48 +++++++++++++ tests/data/parser/inline/0075_try_expr.rs | 3 + tests/data/parser/inline/0075_try_expr.txt | 25 +++++++ 7 files changed, 184 insertions(+), 35 deletions(-) create mode 100644 tests/data/parser/inline/0074_expr_binding_power.rs create mode 100644 tests/data/parser/inline/0074_expr_binding_power.txt create mode 100644 tests/data/parser/inline/0075_try_expr.rs create mode 100644 tests/data/parser/inline/0075_try_expr.txt diff --git a/src/grammar.ron b/src/grammar.ron index 655ed2e40..8ce5ebc49 100644 --- a/src/grammar.ron +++ b/src/grammar.ron @@ -130,23 +130,32 @@ Grammar( "STRUCT_PAT", "TUPLE_PAT", + // atoms "TUPLE_EXPR", "PATH_EXPR", - "CALL_EXPR", - "METHOD_CALL_EXPR", - "FIELD_EXPR", - "REF_EXPR", - "DEREF_EXPR", - "NOT_EXPR", "LAMBDA_EXPR", - "STRUCT_LIT", - "STRUCT_LIT_FIELD", "IF_EXPR", "BLOCK_EXPR", "RETURN_EXPR", "MATCH_EXPR", "MATCH_ARM", "MATCH_GUARD", + "STRUCT_LIT", + "STRUCT_LIT_FIELD", + + // postfix + "CALL_EXPR", + "METHOD_CALL_EXPR", + "FIELD_EXPR", + "TRY_EXPR", + + // unary + "REF_EXPR", + "DEREF_EXPR", + "NOT_EXPR", + + "BIN_EXPR", + "EXTERN_BLOCK_EXPR", "ENUM_VARIANT", diff --git a/src/grammar/expressions.rs b/src/grammar/expressions.rs index 6506892e1..ecca2a3f9 100644 --- a/src/grammar/expressions.rs +++ b/src/grammar/expressions.rs @@ -29,11 +29,54 @@ pub(super) fn literal(p: &mut Parser) -> Option { const EXPR_FIRST: TokenSet = PREFIX_EXPR_FIRST; pub(super) fn expr(p: &mut Parser) { - let mut lhs = match prefix_expr(p) { + expr_bp(p, 1) +} + +fn bp_of(op: SyntaxKind) -> u8 { + match op { + EQEQ | NEQ => 1, + MINUS | PLUS => 2, + STAR | SLASH => 3, + _ => 0 + } +} + + +// test expr_binding_power +// fn foo() { +// 1 + 2 * 3 == 1 * 2 + 3 +// } + +// Parses expression with binding power of at least bp. +fn expr_bp(p: &mut Parser, bp: u8) { + let mut lhs = match unary_expr(p) { Some(lhs) => lhs, None => return, }; + loop { + let op_bp = bp_of(p.current()); + if op_bp < bp { + break; + } + lhs = bin_expr(p, lhs, op_bp); + } +} + +fn unary_expr(p: &mut Parser) -> Option { + let done = match p.current() { + AMPERSAND => ref_expr(p), + STAR => deref_expr(p), + EXCL => not_expr(p), + _ => { + let lhs = atom_expr(p)?; + postfix_expr(p, lhs) + } + }; + Some(done) +} + +fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker { loop { lhs = match p.current() { L_PAREN => call_expr(p, lhs), @@ -43,9 +86,11 @@ pub(super) fn expr(p: &mut Parser) { field_expr(p, lhs) }, DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs), + QUESTION => try_expr(p, lhs), _ => break, } } + lhs } // test block @@ -89,16 +134,6 @@ const PREFIX_EXPR_FIRST: TokenSet = ATOM_EXPR_FIRST, ]; -fn prefix_expr(p: &mut Parser) -> Option { - let done = match p.current() { - AMPERSAND => ref_expr(p), - STAR => deref_expr(p), - EXCL => not_expr(p), - _ => return atom_expr(p), - }; - Some(done) -} - // test ref_expr // fn foo() { // let _ = &1; @@ -369,6 +404,17 @@ fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { m.complete(p, FIELD_EXPR) } +// test try_expr +// fn foo() { +// x?; +// } +fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { + assert!(p.at(QUESTION)); + let m = lhs.precede(p); + p.bump(); + m.complete(p, TRY_EXPR) +} + fn arg_list(p: &mut Parser) { assert!(p.at(L_PAREN)); let m = p.start(); @@ -432,3 +478,14 @@ fn struct_lit(p: &mut Parser) { } p.expect(R_CURLY); } + +fn bin_expr(p: &mut Parser, lhs: CompletedMarker, bp: u8) -> CompletedMarker { + assert!(match p.current() { + MINUS | PLUS | STAR | SLASH | EQEQ | NEQ => true, + _ => false, + }); + let m = lhs.precede(p); + p.bump(); + expr_bp(p, bp); + m.complete(p, BIN_EXPR) +} diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs index d7a57f4d0..7bdd0267c 100644 --- a/src/syntax_kinds/generated.rs +++ b/src/syntax_kinds/generated.rs @@ -123,21 +123,23 @@ pub enum SyntaxKind { TUPLE_PAT, TUPLE_EXPR, PATH_EXPR, - CALL_EXPR, - METHOD_CALL_EXPR, - FIELD_EXPR, - REF_EXPR, - DEREF_EXPR, - NOT_EXPR, LAMBDA_EXPR, - STRUCT_LIT, - STRUCT_LIT_FIELD, IF_EXPR, BLOCK_EXPR, RETURN_EXPR, MATCH_EXPR, MATCH_ARM, MATCH_GUARD, + STRUCT_LIT, + STRUCT_LIT_FIELD, + CALL_EXPR, + METHOD_CALL_EXPR, + FIELD_EXPR, + TRY_EXPR, + REF_EXPR, + DEREF_EXPR, + NOT_EXPR, + BIN_EXPR, EXTERN_BLOCK_EXPR, ENUM_VARIANT, NAMED_FIELD, @@ -339,21 +341,23 @@ impl SyntaxKind { TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" }, TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" }, PATH_EXPR => &SyntaxInfo { name: "PATH_EXPR" }, - CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" }, - METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" }, - FIELD_EXPR => &SyntaxInfo { name: "FIELD_EXPR" }, - REF_EXPR => &SyntaxInfo { name: "REF_EXPR" }, - DEREF_EXPR => &SyntaxInfo { name: "DEREF_EXPR" }, - NOT_EXPR => &SyntaxInfo { name: "NOT_EXPR" }, LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" }, - STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" }, - STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" }, IF_EXPR => &SyntaxInfo { name: "IF_EXPR" }, BLOCK_EXPR => &SyntaxInfo { name: "BLOCK_EXPR" }, RETURN_EXPR => &SyntaxInfo { name: "RETURN_EXPR" }, MATCH_EXPR => &SyntaxInfo { name: "MATCH_EXPR" }, MATCH_ARM => &SyntaxInfo { name: "MATCH_ARM" }, MATCH_GUARD => &SyntaxInfo { name: "MATCH_GUARD" }, + STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" }, + STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" }, + CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" }, + METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" }, + FIELD_EXPR => &SyntaxInfo { name: "FIELD_EXPR" }, + TRY_EXPR => &SyntaxInfo { name: "TRY_EXPR" }, + REF_EXPR => &SyntaxInfo { name: "REF_EXPR" }, + DEREF_EXPR => &SyntaxInfo { name: "DEREF_EXPR" }, + NOT_EXPR => &SyntaxInfo { name: "NOT_EXPR" }, + BIN_EXPR => &SyntaxInfo { name: "BIN_EXPR" }, EXTERN_BLOCK_EXPR => &SyntaxInfo { name: "EXTERN_BLOCK_EXPR" }, ENUM_VARIANT => &SyntaxInfo { name: "ENUM_VARIANT" }, NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" }, diff --git a/tests/data/parser/inline/0074_expr_binding_power.rs b/tests/data/parser/inline/0074_expr_binding_power.rs new file mode 100644 index 000000000..db855fd02 --- /dev/null +++ b/tests/data/parser/inline/0074_expr_binding_power.rs @@ -0,0 +1,3 @@ +fn foo() { + 1 + 2 * 3 == 1 * 2 + 3 +} diff --git a/tests/data/parser/inline/0074_expr_binding_power.txt b/tests/data/parser/inline/0074_expr_binding_power.txt new file mode 100644 index 000000000..05aad25e9 --- /dev/null +++ b/tests/data/parser/inline/0074_expr_binding_power.txt @@ -0,0 +1,48 @@ +FILE@[0; 40) + FN_ITEM@[0; 40) + FN_KW@[0; 2) + NAME@[2; 6) + WHITESPACE@[2; 3) + IDENT@[3; 6) "foo" + PARAM_LIST@[6; 9) + L_PAREN@[6; 7) + R_PAREN@[7; 8) + WHITESPACE@[8; 9) + BLOCK_EXPR@[9; 40) + L_CURLY@[9; 10) + BIN_EXPR@[10; 38) + BIN_EXPR@[10; 25) + LITERAL@[10; 17) + WHITESPACE@[10; 15) + INT_NUMBER@[15; 16) "1" + WHITESPACE@[16; 17) + PLUS@[17; 18) + BIN_EXPR@[18; 25) + LITERAL@[18; 21) + WHITESPACE@[18; 19) + INT_NUMBER@[19; 20) "2" + WHITESPACE@[20; 21) + STAR@[21; 22) + LITERAL@[22; 25) + WHITESPACE@[22; 23) + INT_NUMBER@[23; 24) "3" + WHITESPACE@[24; 25) + EQEQ@[25; 27) + BIN_EXPR@[27; 38) + BIN_EXPR@[27; 34) + LITERAL@[27; 30) + WHITESPACE@[27; 28) + INT_NUMBER@[28; 29) "1" + WHITESPACE@[29; 30) + STAR@[30; 31) + LITERAL@[31; 34) + WHITESPACE@[31; 32) + INT_NUMBER@[32; 33) "2" + WHITESPACE@[33; 34) + PLUS@[34; 35) + LITERAL@[35; 38) + WHITESPACE@[35; 36) + INT_NUMBER@[36; 37) "3" + WHITESPACE@[37; 38) + R_CURLY@[38; 39) + WHITESPACE@[39; 40) diff --git a/tests/data/parser/inline/0075_try_expr.rs b/tests/data/parser/inline/0075_try_expr.rs new file mode 100644 index 000000000..8b74f7bc8 --- /dev/null +++ b/tests/data/parser/inline/0075_try_expr.rs @@ -0,0 +1,3 @@ +fn foo() { + x?; +} diff --git a/tests/data/parser/inline/0075_try_expr.txt b/tests/data/parser/inline/0075_try_expr.txt new file mode 100644 index 000000000..49edce956 --- /dev/null +++ b/tests/data/parser/inline/0075_try_expr.txt @@ -0,0 +1,25 @@ +FILE@[0; 21) + FN_ITEM@[0; 21) + FN_KW@[0; 2) + NAME@[2; 6) + WHITESPACE@[2; 3) + IDENT@[3; 6) "foo" + PARAM_LIST@[6; 9) + L_PAREN@[6; 7) + R_PAREN@[7; 8) + WHITESPACE@[8; 9) + BLOCK_EXPR@[9; 21) + L_CURLY@[9; 10) + EXPR_STMT@[10; 19) + TRY_EXPR@[10; 17) + PATH_EXPR@[10; 16) + PATH@[10; 16) + PATH_SEGMENT@[10; 16) + NAME_REF@[10; 16) + WHITESPACE@[10; 15) + IDENT@[15; 16) "x" + QUESTION@[16; 17) + SEMI@[17; 18) + WHITESPACE@[18; 19) + R_CURLY@[19; 20) + WHITESPACE@[20; 21) -- cgit v1.2.3