diff options
-rw-r--r-- | src/grammar.ron | 4 | ||||
-rw-r--r-- | src/grammar/expressions/mod.rs | 47 | ||||
-rw-r--r-- | src/parser_api.rs | 11 | ||||
-rw-r--r-- | src/parser_impl/input.rs | 17 | ||||
-rw-r--r-- | src/parser_impl/mod.rs | 19 | ||||
-rw-r--r-- | src/syntax_kinds/generated.rs | 12 | ||||
-rw-r--r-- | tests/data/parser/inline/0079_compound_ops.rs | 5 | ||||
-rw-r--r-- | tests/data/parser/inline/0079_compound_ops.txt | 72 |
8 files changed, 171 insertions, 16 deletions
diff --git a/src/grammar.ron b/src/grammar.ron index 0a79eeb95..67022b296 100644 --- a/src/grammar.ron +++ b/src/grammar.ron | |||
@@ -37,6 +37,10 @@ Grammar( | |||
37 | ["!=", "NEQ"], | 37 | ["!=", "NEQ"], |
38 | ["-", "MINUS"], | 38 | ["-", "MINUS"], |
39 | ["->", "THIN_ARROW"], | 39 | ["->", "THIN_ARROW"], |
40 | ["<=", "LTEQ"], | ||
41 | [">=", "GTEQ"], | ||
42 | ["+=", "PLUSEQ"], | ||
43 | ["-=", "MINUSEQ"], | ||
40 | ], | 44 | ], |
41 | keywords: [ | 45 | keywords: [ |
42 | "use", | 46 | "use", |
diff --git a/src/grammar/expressions/mod.rs b/src/grammar/expressions/mod.rs index 15669f99d..baff0da52 100644 --- a/src/grammar/expressions/mod.rs +++ b/src/grammar/expressions/mod.rs | |||
@@ -33,19 +33,45 @@ struct Restrictions { | |||
33 | forbid_structs: bool | 33 | forbid_structs: bool |
34 | } | 34 | } |
35 | 35 | ||
36 | enum Op { | ||
37 | Simple, | ||
38 | Composite(SyntaxKind, u8) | ||
39 | } | ||
40 | |||
36 | // test expr_binding_power | 41 | // test expr_binding_power |
37 | // fn foo() { | 42 | // fn foo() { |
38 | // 1 + 2 * 3 == 1 * 2 + 3; | 43 | // 1 + 2 * 3 == 1 * 2 + 3; |
39 | // *x = 1 + 1; | 44 | // *x = 1 + 1; |
40 | // } | 45 | // } |
41 | fn bp_of(op: SyntaxKind) -> u8 { | 46 | |
42 | match op { | 47 | // test compound_ops |
48 | // fn foo() { | ||
49 | // x += 1; | ||
50 | // 1 + 1 <= 2 * 3; | ||
51 | // z -= 3 >= 0; | ||
52 | // } | ||
53 | fn current_op(p: &Parser) -> (u8, Op) { | ||
54 | if p.at_compound2(L_ANGLE, EQ) { | ||
55 | return (2, Op::Composite(LTEQ, 2)) | ||
56 | } | ||
57 | if p.at_compound2(R_ANGLE, EQ) { | ||
58 | return (2, Op::Composite(GTEQ, 2)) | ||
59 | } | ||
60 | if p.at_compound2(PLUS, EQ) { | ||
61 | return (1, Op::Composite(PLUSEQ, 2)) | ||
62 | } | ||
63 | if p.at_compound2(MINUS, EQ) { | ||
64 | return (1, Op::Composite(MINUSEQ, 2)) | ||
65 | } | ||
66 | |||
67 | let bp = match p.current() { | ||
43 | EQ => 1, | 68 | EQ => 1, |
44 | EQEQ | NEQ => 2, | 69 | EQEQ | NEQ => 2, |
45 | MINUS | PLUS => 3, | 70 | MINUS | PLUS => 3, |
46 | STAR | SLASH => 4, | 71 | STAR | SLASH => 4, |
47 | _ => 0 | 72 | _ => 0, |
48 | } | 73 | }; |
74 | (bp, Op::Simple) | ||
49 | } | 75 | } |
50 | 76 | ||
51 | // Parses expression with binding power of at least bp. | 77 | // Parses expression with binding power of at least bp. |
@@ -56,10 +82,16 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) { | |||
56 | }; | 82 | }; |
57 | 83 | ||
58 | loop { | 84 | loop { |
59 | let op_bp = bp_of(p.current()); | 85 | let (op_bp, op) = current_op(p); |
60 | if op_bp < bp { | 86 | if op_bp < bp { |
61 | break; | 87 | break; |
62 | } | 88 | } |
89 | match op { | ||
90 | Op::Simple => p.bump(), | ||
91 | Op::Composite(kind, n) => { | ||
92 | p.bump_compound(kind, n); | ||
93 | }, | ||
94 | } | ||
63 | lhs = bin_expr(p, r, lhs, op_bp); | 95 | lhs = bin_expr(p, r, lhs, op_bp); |
64 | } | 96 | } |
65 | } | 97 | } |
@@ -254,12 +286,7 @@ fn struct_lit(p: &mut Parser) { | |||
254 | } | 286 | } |
255 | 287 | ||
256 | fn bin_expr(p: &mut Parser, r: Restrictions, lhs: CompletedMarker, bp: u8) -> CompletedMarker { | 288 | fn bin_expr(p: &mut Parser, r: Restrictions, lhs: CompletedMarker, bp: u8) -> CompletedMarker { |
257 | assert!(match p.current() { | ||
258 | MINUS | PLUS | STAR | SLASH | EQEQ | NEQ | EQ => true, | ||
259 | _ => false, | ||
260 | }); | ||
261 | let m = lhs.precede(p); | 289 | let m = lhs.precede(p); |
262 | p.bump(); | ||
263 | expr_bp(p, r, bp); | 290 | expr_bp(p, r, bp); |
264 | m.complete(p, BIN_EXPR) | 291 | m.complete(p, BIN_EXPR) |
265 | } | 292 | } |
diff --git a/src/parser_api.rs b/src/parser_api.rs index 95394e39d..fef21c5fd 100644 --- a/src/parser_api.rs +++ b/src/parser_api.rs | |||
@@ -58,6 +58,10 @@ impl<'t> Parser<'t> { | |||
58 | self.current() == kind | 58 | self.current() == kind |
59 | } | 59 | } |
60 | 60 | ||
61 | pub(crate) fn at_compound2(&self, c1: SyntaxKind, c2: SyntaxKind) -> bool { | ||
62 | self.0.at_compound2(c1, c2) | ||
63 | } | ||
64 | |||
61 | /// Checks if the current token is contextual keyword with text `t`. | 65 | /// Checks if the current token is contextual keyword with text `t`. |
62 | pub(crate) fn at_contextual_kw(&self, t: &str) -> bool { | 66 | pub(crate) fn at_contextual_kw(&self, t: &str) -> bool { |
63 | self.0.at_kw(t) | 67 | self.0.at_kw(t) |
@@ -85,6 +89,13 @@ impl<'t> Parser<'t> { | |||
85 | self.0.bump_remap(kind); | 89 | self.0.bump_remap(kind); |
86 | } | 90 | } |
87 | 91 | ||
92 | /// Advances the parser by `n` tokens, remapping its kind. | ||
93 | /// This is useful to create compound tokens from parts. For | ||
94 | /// example, an `<<` token is two consecutive remapped `<` tokens | ||
95 | pub(crate) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) { | ||
96 | self.0.bump_compound(kind, n); | ||
97 | } | ||
98 | |||
88 | /// Emit error with the `message` | 99 | /// Emit error with the `message` |
89 | /// TODO: this should be much more fancy and support | 100 | /// TODO: this should be much more fancy and support |
90 | /// structured errors with spans and notes, like rustc | 101 | /// structured errors with spans and notes, like rustc |
diff --git a/src/parser_impl/input.rs b/src/parser_impl/input.rs index db76364b2..c0fe4d488 100644 --- a/src/parser_impl/input.rs +++ b/src/parser_impl/input.rs | |||
@@ -36,7 +36,22 @@ impl<'t> ParserInput<'t> { | |||
36 | self.tokens[idx].kind | 36 | self.tokens[idx].kind |
37 | } | 37 | } |
38 | 38 | ||
39 | #[allow(unused)] | 39 | pub fn len(&self, pos: InputPosition) -> TextUnit { |
40 | let idx = pos.0 as usize; | ||
41 | if !(idx < self.tokens.len()) { | ||
42 | return 0.into(); | ||
43 | } | ||
44 | self.tokens[idx].len | ||
45 | } | ||
46 | |||
47 | pub fn start(&self, pos: InputPosition) -> TextUnit { | ||
48 | let idx = pos.0 as usize; | ||
49 | if !(idx < self.tokens.len()) { | ||
50 | return 0.into(); | ||
51 | } | ||
52 | self.start_offsets[idx] | ||
53 | } | ||
54 | |||
40 | pub fn text(&self, pos: InputPosition) -> &'t str { | 55 | pub fn text(&self, pos: InputPosition) -> &'t str { |
41 | let idx = pos.0 as usize; | 56 | let idx = pos.0 as usize; |
42 | if !(idx < self.tokens.len()) { | 57 | if !(idx < self.tokens.len()) { |
diff --git a/src/parser_impl/mod.rs b/src/parser_impl/mod.rs index 2791c8da5..d640a7784 100644 --- a/src/parser_impl/mod.rs +++ b/src/parser_impl/mod.rs | |||
@@ -65,6 +65,11 @@ impl<'t> ParserImpl<'t> { | |||
65 | self.events | 65 | self.events |
66 | } | 66 | } |
67 | 67 | ||
68 | pub(super) fn at_compound2(&self, c1: SyntaxKind, c2: SyntaxKind) -> bool { | ||
69 | self.inp.kind(self.pos) == c1 && self.inp.kind(self.pos + 1) == c2 | ||
70 | && self.inp.start(self.pos + 1) == self.inp.start(self.pos) + self.inp.len(self.pos) | ||
71 | } | ||
72 | |||
68 | pub(super) fn nth(&self, n: u32) -> SyntaxKind { | 73 | pub(super) fn nth(&self, n: u32) -> SyntaxKind { |
69 | self.inp.kind(self.pos + n) | 74 | self.inp.kind(self.pos + n) |
70 | } | 75 | } |
@@ -87,7 +92,7 @@ impl<'t> ParserImpl<'t> { | |||
87 | if kind == EOF { | 92 | if kind == EOF { |
88 | return; | 93 | return; |
89 | } | 94 | } |
90 | self.do_bump(kind); | 95 | self.do_bump(kind, 1); |
91 | } | 96 | } |
92 | 97 | ||
93 | pub(super) fn bump_remap(&mut self, kind: SyntaxKind) { | 98 | pub(super) fn bump_remap(&mut self, kind: SyntaxKind) { |
@@ -95,14 +100,18 @@ impl<'t> ParserImpl<'t> { | |||
95 | // TODO: panic!? | 100 | // TODO: panic!? |
96 | return; | 101 | return; |
97 | } | 102 | } |
98 | self.do_bump(kind); | 103 | self.do_bump(kind, 1); |
104 | } | ||
105 | |||
106 | pub(super) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) { | ||
107 | self.do_bump(kind, n); | ||
99 | } | 108 | } |
100 | 109 | ||
101 | fn do_bump(&mut self, kind: SyntaxKind) { | 110 | fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { |
102 | self.pos += 1; | 111 | self.pos += u32::from(n_raw_tokens); |
103 | self.event(Event::Token { | 112 | self.event(Event::Token { |
104 | kind, | 113 | kind, |
105 | n_raw_tokens: 1, | 114 | n_raw_tokens, |
106 | }); | 115 | }); |
107 | } | 116 | } |
108 | 117 | ||
diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs index 8ac13fd63..8dfeb2b82 100644 --- a/src/syntax_kinds/generated.rs +++ b/src/syntax_kinds/generated.rs | |||
@@ -40,6 +40,10 @@ pub enum SyntaxKind { | |||
40 | NEQ, | 40 | NEQ, |
41 | MINUS, | 41 | MINUS, |
42 | THIN_ARROW, | 42 | THIN_ARROW, |
43 | LTEQ, | ||
44 | GTEQ, | ||
45 | PLUSEQ, | ||
46 | MINUSEQ, | ||
43 | USE_KW, | 47 | USE_KW, |
44 | FN_KW, | 48 | FN_KW, |
45 | STRUCT_KW, | 49 | STRUCT_KW, |
@@ -261,6 +265,10 @@ impl SyntaxKind { | |||
261 | NEQ => &SyntaxInfo { name: "NEQ" }, | 265 | NEQ => &SyntaxInfo { name: "NEQ" }, |
262 | MINUS => &SyntaxInfo { name: "MINUS" }, | 266 | MINUS => &SyntaxInfo { name: "MINUS" }, |
263 | THIN_ARROW => &SyntaxInfo { name: "THIN_ARROW" }, | 267 | THIN_ARROW => &SyntaxInfo { name: "THIN_ARROW" }, |
268 | LTEQ => &SyntaxInfo { name: "LTEQ" }, | ||
269 | GTEQ => &SyntaxInfo { name: "GTEQ" }, | ||
270 | PLUSEQ => &SyntaxInfo { name: "PLUSEQ" }, | ||
271 | MINUSEQ => &SyntaxInfo { name: "MINUSEQ" }, | ||
264 | USE_KW => &SyntaxInfo { name: "USE_KW" }, | 272 | USE_KW => &SyntaxInfo { name: "USE_KW" }, |
265 | FN_KW => &SyntaxInfo { name: "FN_KW" }, | 273 | FN_KW => &SyntaxInfo { name: "FN_KW" }, |
266 | STRUCT_KW => &SyntaxInfo { name: "STRUCT_KW" }, | 274 | STRUCT_KW => &SyntaxInfo { name: "STRUCT_KW" }, |
@@ -502,6 +510,10 @@ impl SyntaxKind { | |||
502 | NEQ => "!=", | 510 | NEQ => "!=", |
503 | MINUS => "-", | 511 | MINUS => "-", |
504 | THIN_ARROW => "->", | 512 | THIN_ARROW => "->", |
513 | LTEQ => "<=", | ||
514 | GTEQ => ">=", | ||
515 | PLUSEQ => "+=", | ||
516 | MINUSEQ => "-=", | ||
505 | 517 | ||
506 | USE_KW => "use", | 518 | USE_KW => "use", |
507 | FN_KW => "fn", | 519 | FN_KW => "fn", |
diff --git a/tests/data/parser/inline/0079_compound_ops.rs b/tests/data/parser/inline/0079_compound_ops.rs new file mode 100644 index 000000000..48be5aebe --- /dev/null +++ b/tests/data/parser/inline/0079_compound_ops.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | fn foo() { | ||
2 | x += 1; | ||
3 | 1 + 1 <= 2 * 3; | ||
4 | z -= 3 >= 0; | ||
5 | } | ||
diff --git a/tests/data/parser/inline/0079_compound_ops.txt b/tests/data/parser/inline/0079_compound_ops.txt new file mode 100644 index 000000000..6eaed8c75 --- /dev/null +++ b/tests/data/parser/inline/0079_compound_ops.txt | |||
@@ -0,0 +1,72 @@ | |||
1 | FILE@[0; 62) | ||
2 | FN_ITEM@[0; 62) | ||
3 | FN_KW@[0; 2) | ||
4 | NAME@[2; 6) | ||
5 | WHITESPACE@[2; 3) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 9) | ||
8 | L_PAREN@[6; 7) | ||
9 | R_PAREN@[7; 8) | ||
10 | WHITESPACE@[8; 9) | ||
11 | BLOCK_EXPR@[9; 62) | ||
12 | L_CURLY@[9; 10) | ||
13 | EXPR_STMT@[10; 27) | ||
14 | BIN_EXPR@[10; 21) | ||
15 | PATH_EXPR@[10; 17) | ||
16 | PATH@[10; 17) | ||
17 | PATH_SEGMENT@[10; 17) | ||
18 | NAME_REF@[10; 17) | ||
19 | WHITESPACE@[10; 15) | ||
20 | IDENT@[15; 16) "x" | ||
21 | WHITESPACE@[16; 17) | ||
22 | PLUSEQ@[17; 19) | ||
23 | LITERAL@[19; 21) | ||
24 | WHITESPACE@[19; 20) | ||
25 | INT_NUMBER@[20; 21) "1" | ||
26 | SEMI@[21; 22) | ||
27 | WHITESPACE@[22; 27) | ||
28 | EXPR_STMT@[27; 47) | ||
29 | BIN_EXPR@[27; 41) | ||
30 | BIN_EXPR@[27; 33) | ||
31 | LITERAL@[27; 29) | ||
32 | INT_NUMBER@[27; 28) "1" | ||
33 | WHITESPACE@[28; 29) | ||
34 | PLUS@[29; 30) | ||
35 | LITERAL@[30; 33) | ||
36 | WHITESPACE@[30; 31) | ||
37 | INT_NUMBER@[31; 32) "1" | ||
38 | WHITESPACE@[32; 33) | ||
39 | LTEQ@[33; 35) | ||
40 | BIN_EXPR@[35; 41) | ||
41 | LITERAL@[35; 38) | ||
42 | WHITESPACE@[35; 36) | ||
43 | INT_NUMBER@[36; 37) "2" | ||
44 | WHITESPACE@[37; 38) | ||
45 | STAR@[38; 39) | ||
46 | LITERAL@[39; 41) | ||
47 | WHITESPACE@[39; 40) | ||
48 | INT_NUMBER@[40; 41) "3" | ||
49 | SEMI@[41; 42) | ||
50 | WHITESPACE@[42; 47) | ||
51 | EXPR_STMT@[47; 60) | ||
52 | BIN_EXPR@[47; 58) | ||
53 | PATH_EXPR@[47; 49) | ||
54 | PATH@[47; 49) | ||
55 | PATH_SEGMENT@[47; 49) | ||
56 | NAME_REF@[47; 49) | ||
57 | IDENT@[47; 48) "z" | ||
58 | WHITESPACE@[48; 49) | ||
59 | MINUSEQ@[49; 51) | ||
60 | BIN_EXPR@[51; 58) | ||
61 | LITERAL@[51; 54) | ||
62 | WHITESPACE@[51; 52) | ||
63 | INT_NUMBER@[52; 53) "3" | ||
64 | WHITESPACE@[53; 54) | ||
65 | GTEQ@[54; 56) | ||
66 | LITERAL@[56; 58) | ||
67 | WHITESPACE@[56; 57) | ||
68 | INT_NUMBER@[57; 58) "0" | ||
69 | SEMI@[58; 59) | ||
70 | WHITESPACE@[59; 60) | ||
71 | R_CURLY@[60; 61) | ||
72 | WHITESPACE@[61; 62) | ||