aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/grammar.ron4
-rw-r--r--src/grammar/expressions/mod.rs47
-rw-r--r--src/parser_api.rs11
-rw-r--r--src/parser_impl/input.rs17
-rw-r--r--src/parser_impl/mod.rs19
-rw-r--r--src/syntax_kinds/generated.rs12
-rw-r--r--tests/data/parser/inline/0079_compound_ops.rs5
-rw-r--r--tests/data/parser/inline/0079_compound_ops.txt72
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
36enum 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// }
41fn 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// }
53fn 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
256fn bin_expr(p: &mut Parser, r: Restrictions, lhs: CompletedMarker, bp: u8) -> CompletedMarker { 288fn 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 @@
1fn 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 @@
1FILE@[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)