compound ops

This commit is contained in:
Aleksey Kladov 2018-08-05 16:09:25 +03:00
parent 5691da4c84
commit 1e1e2e83c4
8 changed files with 171 additions and 16 deletions

View File

@ -37,6 +37,10 @@ Grammar(
["!=", "NEQ"], ["!=", "NEQ"],
["-", "MINUS"], ["-", "MINUS"],
["->", "THIN_ARROW"], ["->", "THIN_ARROW"],
["<=", "LTEQ"],
[">=", "GTEQ"],
["+=", "PLUSEQ"],
["-=", "MINUSEQ"],
], ],
keywords: [ keywords: [
"use", "use",

View File

@ -33,19 +33,45 @@ struct Restrictions {
forbid_structs: bool forbid_structs: bool
} }
enum Op {
Simple,
Composite(SyntaxKind, u8)
}
// test expr_binding_power // test expr_binding_power
// fn foo() { // fn foo() {
// 1 + 2 * 3 == 1 * 2 + 3; // 1 + 2 * 3 == 1 * 2 + 3;
// *x = 1 + 1; // *x = 1 + 1;
// } // }
fn bp_of(op: SyntaxKind) -> u8 {
match op { // test compound_ops
// fn foo() {
// x += 1;
// 1 + 1 <= 2 * 3;
// z -= 3 >= 0;
// }
fn current_op(p: &Parser) -> (u8, Op) {
if p.at_compound2(L_ANGLE, EQ) {
return (2, Op::Composite(LTEQ, 2))
}
if p.at_compound2(R_ANGLE, EQ) {
return (2, Op::Composite(GTEQ, 2))
}
if p.at_compound2(PLUS, EQ) {
return (1, Op::Composite(PLUSEQ, 2))
}
if p.at_compound2(MINUS, EQ) {
return (1, Op::Composite(MINUSEQ, 2))
}
let bp = match p.current() {
EQ => 1, EQ => 1,
EQEQ | NEQ => 2, EQEQ | NEQ => 2,
MINUS | PLUS => 3, MINUS | PLUS => 3,
STAR | SLASH => 4, STAR | SLASH => 4,
_ => 0 _ => 0,
} };
(bp, Op::Simple)
} }
// Parses expression with binding power of at least bp. // Parses expression with binding power of at least bp.
@ -56,10 +82,16 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) {
}; };
loop { loop {
let op_bp = bp_of(p.current()); let (op_bp, op) = current_op(p);
if op_bp < bp { if op_bp < bp {
break; break;
} }
match op {
Op::Simple => p.bump(),
Op::Composite(kind, n) => {
p.bump_compound(kind, n);
},
}
lhs = bin_expr(p, r, lhs, op_bp); lhs = bin_expr(p, r, lhs, op_bp);
} }
} }
@ -254,12 +286,7 @@ fn struct_lit(p: &mut Parser) {
} }
fn bin_expr(p: &mut Parser, r: Restrictions, lhs: CompletedMarker, bp: u8) -> CompletedMarker { fn bin_expr(p: &mut Parser, r: Restrictions, lhs: CompletedMarker, bp: u8) -> CompletedMarker {
assert!(match p.current() {
MINUS | PLUS | STAR | SLASH | EQEQ | NEQ | EQ => true,
_ => false,
});
let m = lhs.precede(p); let m = lhs.precede(p);
p.bump();
expr_bp(p, r, bp); expr_bp(p, r, bp);
m.complete(p, BIN_EXPR) m.complete(p, BIN_EXPR)
} }

View File

@ -58,6 +58,10 @@ impl<'t> Parser<'t> {
self.current() == kind self.current() == kind
} }
pub(crate) fn at_compound2(&self, c1: SyntaxKind, c2: SyntaxKind) -> bool {
self.0.at_compound2(c1, c2)
}
/// Checks if the current token is contextual keyword with text `t`. /// Checks if the current token is contextual keyword with text `t`.
pub(crate) fn at_contextual_kw(&self, t: &str) -> bool { pub(crate) fn at_contextual_kw(&self, t: &str) -> bool {
self.0.at_kw(t) self.0.at_kw(t)
@ -85,6 +89,13 @@ impl<'t> Parser<'t> {
self.0.bump_remap(kind); self.0.bump_remap(kind);
} }
/// Advances the parser by `n` tokens, remapping its kind.
/// This is useful to create compound tokens from parts. For
/// example, an `<<` token is two consecutive remapped `<` tokens
pub(crate) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) {
self.0.bump_compound(kind, n);
}
/// Emit error with the `message` /// Emit error with the `message`
/// TODO: this should be much more fancy and support /// TODO: this should be much more fancy and support
/// structured errors with spans and notes, like rustc /// structured errors with spans and notes, like rustc

View File

@ -36,7 +36,22 @@ impl<'t> ParserInput<'t> {
self.tokens[idx].kind self.tokens[idx].kind
} }
#[allow(unused)] pub fn len(&self, pos: InputPosition) -> TextUnit {
let idx = pos.0 as usize;
if !(idx < self.tokens.len()) {
return 0.into();
}
self.tokens[idx].len
}
pub fn start(&self, pos: InputPosition) -> TextUnit {
let idx = pos.0 as usize;
if !(idx < self.tokens.len()) {
return 0.into();
}
self.start_offsets[idx]
}
pub fn text(&self, pos: InputPosition) -> &'t str { pub fn text(&self, pos: InputPosition) -> &'t str {
let idx = pos.0 as usize; let idx = pos.0 as usize;
if !(idx < self.tokens.len()) { if !(idx < self.tokens.len()) {

View File

@ -65,6 +65,11 @@ impl<'t> ParserImpl<'t> {
self.events self.events
} }
pub(super) fn at_compound2(&self, c1: SyntaxKind, c2: SyntaxKind) -> bool {
self.inp.kind(self.pos) == c1 && self.inp.kind(self.pos + 1) == c2
&& self.inp.start(self.pos + 1) == self.inp.start(self.pos) + self.inp.len(self.pos)
}
pub(super) fn nth(&self, n: u32) -> SyntaxKind { pub(super) fn nth(&self, n: u32) -> SyntaxKind {
self.inp.kind(self.pos + n) self.inp.kind(self.pos + n)
} }
@ -87,7 +92,7 @@ impl<'t> ParserImpl<'t> {
if kind == EOF { if kind == EOF {
return; return;
} }
self.do_bump(kind); self.do_bump(kind, 1);
} }
pub(super) fn bump_remap(&mut self, kind: SyntaxKind) { pub(super) fn bump_remap(&mut self, kind: SyntaxKind) {
@ -95,14 +100,18 @@ impl<'t> ParserImpl<'t> {
// TODO: panic!? // TODO: panic!?
return; return;
} }
self.do_bump(kind); self.do_bump(kind, 1);
} }
fn do_bump(&mut self, kind: SyntaxKind) { pub(super) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) {
self.pos += 1; self.do_bump(kind, n);
}
fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
self.pos += u32::from(n_raw_tokens);
self.event(Event::Token { self.event(Event::Token {
kind, kind,
n_raw_tokens: 1, n_raw_tokens,
}); });
} }

View File

@ -40,6 +40,10 @@ pub enum SyntaxKind {
NEQ, NEQ,
MINUS, MINUS,
THIN_ARROW, THIN_ARROW,
LTEQ,
GTEQ,
PLUSEQ,
MINUSEQ,
USE_KW, USE_KW,
FN_KW, FN_KW,
STRUCT_KW, STRUCT_KW,
@ -261,6 +265,10 @@ impl SyntaxKind {
NEQ => &SyntaxInfo { name: "NEQ" }, NEQ => &SyntaxInfo { name: "NEQ" },
MINUS => &SyntaxInfo { name: "MINUS" }, MINUS => &SyntaxInfo { name: "MINUS" },
THIN_ARROW => &SyntaxInfo { name: "THIN_ARROW" }, THIN_ARROW => &SyntaxInfo { name: "THIN_ARROW" },
LTEQ => &SyntaxInfo { name: "LTEQ" },
GTEQ => &SyntaxInfo { name: "GTEQ" },
PLUSEQ => &SyntaxInfo { name: "PLUSEQ" },
MINUSEQ => &SyntaxInfo { name: "MINUSEQ" },
USE_KW => &SyntaxInfo { name: "USE_KW" }, USE_KW => &SyntaxInfo { name: "USE_KW" },
FN_KW => &SyntaxInfo { name: "FN_KW" }, FN_KW => &SyntaxInfo { name: "FN_KW" },
STRUCT_KW => &SyntaxInfo { name: "STRUCT_KW" }, STRUCT_KW => &SyntaxInfo { name: "STRUCT_KW" },
@ -502,6 +510,10 @@ impl SyntaxKind {
NEQ => "!=", NEQ => "!=",
MINUS => "-", MINUS => "-",
THIN_ARROW => "->", THIN_ARROW => "->",
LTEQ => "<=",
GTEQ => ">=",
PLUSEQ => "+=",
MINUSEQ => "-=",
USE_KW => "use", USE_KW => "use",
FN_KW => "fn", FN_KW => "fn",

View File

@ -0,0 +1,5 @@
fn foo() {
x += 1;
1 + 1 <= 2 * 3;
z -= 3 >= 0;
}

View File

@ -0,0 +1,72 @@
FILE@[0; 62)
FN_ITEM@[0; 62)
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; 62)
L_CURLY@[9; 10)
EXPR_STMT@[10; 27)
BIN_EXPR@[10; 21)
PATH_EXPR@[10; 17)
PATH@[10; 17)
PATH_SEGMENT@[10; 17)
NAME_REF@[10; 17)
WHITESPACE@[10; 15)
IDENT@[15; 16) "x"
WHITESPACE@[16; 17)
PLUSEQ@[17; 19)
LITERAL@[19; 21)
WHITESPACE@[19; 20)
INT_NUMBER@[20; 21) "1"
SEMI@[21; 22)
WHITESPACE@[22; 27)
EXPR_STMT@[27; 47)
BIN_EXPR@[27; 41)
BIN_EXPR@[27; 33)
LITERAL@[27; 29)
INT_NUMBER@[27; 28) "1"
WHITESPACE@[28; 29)
PLUS@[29; 30)
LITERAL@[30; 33)
WHITESPACE@[30; 31)
INT_NUMBER@[31; 32) "1"
WHITESPACE@[32; 33)
LTEQ@[33; 35)
BIN_EXPR@[35; 41)
LITERAL@[35; 38)
WHITESPACE@[35; 36)
INT_NUMBER@[36; 37) "2"
WHITESPACE@[37; 38)
STAR@[38; 39)
LITERAL@[39; 41)
WHITESPACE@[39; 40)
INT_NUMBER@[40; 41) "3"
SEMI@[41; 42)
WHITESPACE@[42; 47)
EXPR_STMT@[47; 60)
BIN_EXPR@[47; 58)
PATH_EXPR@[47; 49)
PATH@[47; 49)
PATH_SEGMENT@[47; 49)
NAME_REF@[47; 49)
IDENT@[47; 48) "z"
WHITESPACE@[48; 49)
MINUSEQ@[49; 51)
BIN_EXPR@[51; 58)
LITERAL@[51; 54)
WHITESPACE@[51; 52)
INT_NUMBER@[52; 53) "3"
WHITESPACE@[53; 54)
GTEQ@[54; 56)
LITERAL@[56; 58)
WHITESPACE@[56; 57)
INT_NUMBER@[57; 58) "0"
SEMI@[58; 59)
WHITESPACE@[59; 60)
R_CURLY@[60; 61)
WHITESPACE@[61; 62)