From d82a21ab202b2f5e8c96847802d806735ec74ad3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 31 Jul 2018 23:13:08 +0300 Subject: lambda expressions --- src/grammar.ron | 3 +- src/parser/grammar/expressions.rs | 77 +++++++++++++++++ src/parser/grammar/items/mod.rs | 63 +------------- src/parser/grammar/mod.rs | 65 ++------------ src/parser/grammar/params.rs | 71 ++++++++++++++++ src/parser/grammar/types.rs | 2 +- src/syntax_kinds/generated.rs | 6 +- .../data/parser/inline/0033_fn_value_parameters.rs | 4 - .../parser/inline/0033_fn_value_parameters.txt | 99 ---------------------- tests/data/parser/inline/0063_lambda_expr.rs | 6 ++ tests/data/parser/inline/0063_lambda_expr.txt | 91 ++++++++++++++++++++ tests/data/parser/inline/0064_param_list.rs | 4 + tests/data/parser/inline/0064_param_list.txt | 99 ++++++++++++++++++++++ 13 files changed, 364 insertions(+), 226 deletions(-) create mode 100644 src/parser/grammar/params.rs delete mode 100644 tests/data/parser/inline/0033_fn_value_parameters.rs delete mode 100644 tests/data/parser/inline/0033_fn_value_parameters.txt create mode 100644 tests/data/parser/inline/0063_lambda_expr.rs create mode 100644 tests/data/parser/inline/0063_lambda_expr.txt create mode 100644 tests/data/parser/inline/0064_param_list.rs create mode 100644 tests/data/parser/inline/0064_param_list.txt diff --git a/src/grammar.ron b/src/grammar.ron index df7b4083b..24f11f63e 100644 --- a/src/grammar.ron +++ b/src/grammar.ron @@ -131,6 +131,7 @@ Grammar( "FIELD_EXPR", "REF_EXPR", "DEREF_EXPR", + "LAMBDA_EXPR", "STRUCT_LIT", "STRUCT_LIT_FIELD", @@ -150,7 +151,6 @@ Grammar( "ABI", "NAME", "NAME_REF", - "VALUE_PARAMETER", "BLOCK", "LET_STMT", @@ -165,6 +165,7 @@ Grammar( "ASSOC_TYPE_ARG", "PARAM_LIST", + "VALUE_PARAMETER", "SELF_PARAM", "ARG_LIST", ] diff --git a/src/parser/grammar/expressions.rs b/src/parser/grammar/expressions.rs index ef3a0f76c..09b351f31 100644 --- a/src/parser/grammar/expressions.rs +++ b/src/parser/grammar/expressions.rs @@ -44,6 +44,63 @@ pub(super) fn expr(p: &mut Parser) { } } +// test block +// fn a() {} +// fn b() { let _ = 1; } +// fn c() { 1; 2; } +// fn d() { 1; 2 } +pub(super) fn block(p: &mut Parser) { + if !p.at(L_CURLY) { + p.error("expected block"); + } + let m = p.start(); + p.bump(); + while !p.at(EOF) && !p.at(R_CURLY) { + match p.current() { + LET_KW => let_stmt(p), + c => { + // test block_items + // fn a() { fn b() {} } + if items::ITEM_FIRST.contains(c) { + items::item(p) + } else { + let expr_stmt = p.start(); + expressions::expr(p); + if p.eat(SEMI) { + expr_stmt.complete(p, EXPR_STMT); + } else { + expr_stmt.abandon(p); + } + } + } + } + } + p.expect(R_CURLY); + m.complete(p, BLOCK); +} + +// test let_stmt; +// fn foo() { +// let a; +// let b: i32; +// let c = 92; +// let d: i32 = 92; +// } +fn let_stmt(p: &mut Parser) { + assert!(p.at(LET_KW)); + let m = p.start(); + p.bump(); + patterns::pattern(p); + if p.at(COLON) { + types::ascription(p); + } + if p.eat(EQ) { + expressions::expr(p); + } + p.expect(SEMI); + m.complete(p, LET_STMT); +} + fn prefix_expr(p: &mut Parser) -> Option { match p.current() { AMPERSAND => Some(ref_expr(p)), @@ -89,6 +146,7 @@ fn atom_expr(p: &mut Parser) -> Option { match p.current() { L_PAREN => Some(tuple_expr(p)), + PIPE => Some(lambda_expr(p)), _ => { p.err_and_bump("expected expression"); None @@ -104,6 +162,25 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker { m.complete(p, TUPLE_EXPR) } +// test lambda_expr +// fn foo() { +// || (); +// || -> i32 { 92 }; +// |x| x; +// |x: i32,| x; +// } +fn lambda_expr(p: &mut Parser) -> CompletedMarker { + assert!(p.at(PIPE)); + let m = p.start(); + params::list_opt_types(p); + if fn_ret_type(p) { + block(p); + } else { + expr(p) + } + m.complete(p, LAMBDA_EXPR) +} + // test call_expr // fn foo() { // let _ = f(); diff --git a/src/parser/grammar/items/mod.rs b/src/parser/grammar/items/mod.rs index d1da1ecb4..8c2704be5 100644 --- a/src/parser/grammar/items/mod.rs +++ b/src/parser/grammar/items/mod.rs @@ -15,7 +15,7 @@ pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { pub(super) const ITEM_FIRST: TokenSet = token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND]; -fn item(p: &mut Parser) { +pub(super) fn item(p: &mut Parser) { let item = p.start(); attributes::outer_attributes(p); visibility(p); @@ -239,7 +239,7 @@ fn fn_item(p: &mut Parser) { type_params::list(p); if p.at(L_PAREN) { - fn_value_parameters(p); + params::list(p); } else { p.error("expected function arguments"); } @@ -252,64 +252,7 @@ fn fn_item(p: &mut Parser) { // fn foo() where T: Copy {} type_params::where_clause(p); - block(p); - - // test block - // fn a() {} - // fn b() { let _ = 1; } - // fn c() { 1; 2; } - // fn d() { 1; 2 } - fn block(p: &mut Parser) { - if !p.at(L_CURLY) { - p.error("expected block"); - } - let m = p.start(); - p.bump(); - while !p.at(EOF) && !p.at(R_CURLY) { - match p.current() { - LET_KW => let_stmt(p), - c => { - // test block_items - // fn a() { fn b() {} } - if ITEM_FIRST.contains(c) { - item(p) - } else { - let expr_stmt = p.start(); - expressions::expr(p); - if p.eat(SEMI) { - expr_stmt.complete(p, EXPR_STMT); - } else { - expr_stmt.abandon(p); - } - } - } - } - } - p.expect(R_CURLY); - m.complete(p, BLOCK); - } - - // test let_stmt; - // fn foo() { - // let a; - // let b: i32; - // let c = 92; - // let d: i32 = 92; - // } - fn let_stmt(p: &mut Parser) { - assert!(p.at(LET_KW)); - let m = p.start(); - p.bump(); - patterns::pattern(p); - if p.at(COLON) { - types::ascription(p); - } - if p.eat(EQ) { - expressions::expr(p); - } - p.expect(SEMI); - m.complete(p, LET_STMT); - } + expressions::block(p); } // test type_item diff --git a/src/parser/grammar/mod.rs b/src/parser/grammar/mod.rs index 69942e7f1..d4f9b80cf 100644 --- a/src/parser/grammar/mod.rs +++ b/src/parser/grammar/mod.rs @@ -26,8 +26,9 @@ mod expressions; mod items; mod paths; mod patterns; -mod type_args; +mod params; mod type_params; +mod type_args; mod types; use { @@ -95,67 +96,13 @@ fn abi(p: &mut Parser) { abi.complete(p, ABI); } -// test fn_value_parameters -// fn a() {} -// fn b(x: i32) {} -// fn c(x: i32, ) {} -// fn d(x: i32, y: ()) {} -fn fn_value_parameters(p: &mut Parser) { - assert!(p.at(L_PAREN)); - let m = p.start(); - p.bump(); - self_param(p); - while !p.at(EOF) && !p.at(R_PAREN) { - value_parameter(p); - if !p.at(R_PAREN) { - p.expect(COMMA); - } - } - p.expect(R_PAREN); - m.complete(p, PARAM_LIST); - - fn value_parameter(p: &mut Parser) { - let m = p.start(); - patterns::pattern(p); - p.expect(COLON); - types::type_(p); - m.complete(p, VALUE_PARAMETER); - } - - // test self_param - // impl S { - // fn a(self) {} - // fn b(&self,) {} - // fn c(&'a self,) {} - // fn d(&'a mut self, x: i32) {} - // } - fn self_param(p: &mut Parser) { - let la1 = p.nth(1); - let la2 = p.nth(2); - let la3 = p.nth(3); - let n_toks = match (p.current(), la1, la2, la3) { - (SELF_KW, _, _, _) => 1, - (AMPERSAND, SELF_KW, _, _) => 2, - (AMPERSAND, MUT_KW, SELF_KW, _) => 3, - (AMPERSAND, LIFETIME, SELF_KW, _) => 3, - (AMPERSAND, LIFETIME, MUT_KW, SELF_KW) => 4, - _ => return, - }; - let m = p.start(); - for _ in 0..n_toks { - p.bump(); - } - m.complete(p, SELF_PARAM); - if !p.at(R_PAREN) { - p.expect(COMMA); - } - } -} - -fn fn_ret_type(p: &mut Parser) { +fn fn_ret_type(p: &mut Parser) -> bool { if p.at(THIN_ARROW) { p.bump(); types::type_(p); + true + } else { + false } } diff --git a/src/parser/grammar/params.rs b/src/parser/grammar/params.rs new file mode 100644 index 000000000..1ef2cea88 --- /dev/null +++ b/src/parser/grammar/params.rs @@ -0,0 +1,71 @@ +use super::*; + +// test param_list +// fn a() {} +// fn b(x: i32) {} +// fn c(x: i32, ) {} +// fn d(x: i32, y: ()) {} +pub(super) fn list(p: &mut Parser) { + list_(p, true) +} + +pub(super) fn list_opt_types(p: &mut Parser) { + list_(p, false) +} + +fn list_(p: &mut Parser, require_types: bool) { + assert!(p.at(if require_types { L_PAREN } else { PIPE })); + let m = p.start(); + p.bump(); + if require_types { + self_param(p); + } + let terminator = if require_types { R_PAREN } else { PIPE }; + while !p.at(EOF) && !p.at(terminator) { + value_parameter(p, require_types); + if !p.at(terminator) { + p.expect(COMMA); + } + } + p.expect(terminator); + m.complete(p, PARAM_LIST); +} + +fn value_parameter(p: &mut Parser, require_type: bool) { + let m = p.start(); + patterns::pattern(p); + if p.at(COLON) || require_type { + types::ascription(p) + } + m.complete(p, VALUE_PARAMETER); +} + +// test self_param +// impl S { +// fn a(self) {} +// fn b(&self,) {} +// fn c(&'a self,) {} +// fn d(&'a mut self, x: i32) {} +// } +fn self_param(p: &mut Parser) { + let la1 = p.nth(1); + let la2 = p.nth(2); + let la3 = p.nth(3); + let n_toks = match (p.current(), la1, la2, la3) { + (SELF_KW, _, _, _) => 1, + (AMPERSAND, SELF_KW, _, _) => 2, + (AMPERSAND, MUT_KW, SELF_KW, _) => 3, + (AMPERSAND, LIFETIME, SELF_KW, _) => 3, + (AMPERSAND, LIFETIME, MUT_KW, SELF_KW) => 4, + _ => return, + }; + let m = p.start(); + for _ in 0..n_toks { + p.bump(); + } + m.complete(p, SELF_PARAM); + if !p.at(R_PAREN) { + p.expect(COMMA); + } +} + diff --git a/src/parser/grammar/types.rs b/src/parser/grammar/types.rs index 31871ceec..6535f6872 100644 --- a/src/parser/grammar/types.rs +++ b/src/parser/grammar/types.rs @@ -166,7 +166,7 @@ fn fn_pointer_type(p: &mut Parser) { return; } - fn_value_parameters(p); + params::list(p); // test fn_pointer_type_with_ret // type F = fn() -> (); fn_ret_type(p); diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs index 156d42db4..93a3250a4 100644 --- a/src/syntax_kinds/generated.rs +++ b/src/syntax_kinds/generated.rs @@ -122,6 +122,7 @@ pub enum SyntaxKind { FIELD_EXPR, REF_EXPR, DEREF_EXPR, + LAMBDA_EXPR, STRUCT_LIT, STRUCT_LIT_FIELD, EXTERN_BLOCK, @@ -140,7 +141,6 @@ pub enum SyntaxKind { ABI, NAME, NAME_REF, - VALUE_PARAMETER, BLOCK, LET_STMT, EXPR_STMT, @@ -152,6 +152,7 @@ pub enum SyntaxKind { TYPE_ARG, ASSOC_TYPE_ARG, PARAM_LIST, + VALUE_PARAMETER, SELF_PARAM, ARG_LIST, // Technical SyntaxKinds: they appear temporally during parsing, @@ -283,6 +284,7 @@ impl SyntaxKind { FIELD_EXPR => &SyntaxInfo { name: "FIELD_EXPR" }, REF_EXPR => &SyntaxInfo { name: "REF_EXPR" }, DEREF_EXPR => &SyntaxInfo { name: "DEREF_EXPR" }, + LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" }, STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" }, STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" }, EXTERN_BLOCK => &SyntaxInfo { name: "EXTERN_BLOCK" }, @@ -301,7 +303,6 @@ impl SyntaxKind { ABI => &SyntaxInfo { name: "ABI" }, NAME => &SyntaxInfo { name: "NAME" }, NAME_REF => &SyntaxInfo { name: "NAME_REF" }, - VALUE_PARAMETER => &SyntaxInfo { name: "VALUE_PARAMETER" }, BLOCK => &SyntaxInfo { name: "BLOCK" }, LET_STMT => &SyntaxInfo { name: "LET_STMT" }, EXPR_STMT => &SyntaxInfo { name: "EXPR_STMT" }, @@ -313,6 +314,7 @@ impl SyntaxKind { TYPE_ARG => &SyntaxInfo { name: "TYPE_ARG" }, ASSOC_TYPE_ARG => &SyntaxInfo { name: "ASSOC_TYPE_ARG" }, PARAM_LIST => &SyntaxInfo { name: "PARAM_LIST" }, + VALUE_PARAMETER => &SyntaxInfo { name: "VALUE_PARAMETER" }, SELF_PARAM => &SyntaxInfo { name: "SELF_PARAM" }, ARG_LIST => &SyntaxInfo { name: "ARG_LIST" }, TOMBSTONE => &SyntaxInfo { name: "TOMBSTONE" }, diff --git a/tests/data/parser/inline/0033_fn_value_parameters.rs b/tests/data/parser/inline/0033_fn_value_parameters.rs deleted file mode 100644 index 9d55bedbb..000000000 --- a/tests/data/parser/inline/0033_fn_value_parameters.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn a() {} -fn b(x: i32) {} -fn c(x: i32, ) {} -fn d(x: i32, y: ()) {} diff --git a/tests/data/parser/inline/0033_fn_value_parameters.txt b/tests/data/parser/inline/0033_fn_value_parameters.txt deleted file mode 100644 index 96e03d71a..000000000 --- a/tests/data/parser/inline/0033_fn_value_parameters.txt +++ /dev/null @@ -1,99 +0,0 @@ -FILE@[0; 67) - FN_ITEM@[0; 10) - FN_KW@[0; 2) - NAME@[2; 4) - WHITESPACE@[2; 3) - IDENT@[3; 4) "a" - PARAM_LIST@[4; 7) - L_PAREN@[4; 5) - R_PAREN@[5; 6) - WHITESPACE@[6; 7) - BLOCK@[7; 10) - L_CURLY@[7; 8) - R_CURLY@[8; 9) - WHITESPACE@[9; 10) - FN_ITEM@[10; 26) - FN_KW@[10; 12) - NAME@[12; 14) - WHITESPACE@[12; 13) - IDENT@[13; 14) "b" - PARAM_LIST@[14; 23) - L_PAREN@[14; 15) - VALUE_PARAMETER@[15; 21) - BIND_PAT@[15; 16) - NAME@[15; 16) - IDENT@[15; 16) "x" - COLON@[16; 17) - PATH_TYPE@[17; 21) - PATH@[17; 21) - PATH_SEGMENT@[17; 21) - NAME_REF@[17; 21) - WHITESPACE@[17; 18) - IDENT@[18; 21) "i32" - R_PAREN@[21; 22) - WHITESPACE@[22; 23) - BLOCK@[23; 26) - L_CURLY@[23; 24) - R_CURLY@[24; 25) - WHITESPACE@[25; 26) - FN_ITEM@[26; 44) - FN_KW@[26; 28) - NAME@[28; 30) - WHITESPACE@[28; 29) - IDENT@[29; 30) "c" - PARAM_LIST@[30; 41) - L_PAREN@[30; 31) - VALUE_PARAMETER@[31; 37) - BIND_PAT@[31; 32) - NAME@[31; 32) - IDENT@[31; 32) "x" - COLON@[32; 33) - PATH_TYPE@[33; 37) - PATH@[33; 37) - PATH_SEGMENT@[33; 37) - NAME_REF@[33; 37) - WHITESPACE@[33; 34) - IDENT@[34; 37) "i32" - COMMA@[37; 38) - WHITESPACE@[38; 39) - R_PAREN@[39; 40) - WHITESPACE@[40; 41) - BLOCK@[41; 44) - L_CURLY@[41; 42) - R_CURLY@[42; 43) - WHITESPACE@[43; 44) - FN_ITEM@[44; 67) - FN_KW@[44; 46) - NAME@[46; 48) - WHITESPACE@[46; 47) - IDENT@[47; 48) "d" - PARAM_LIST@[48; 64) - L_PAREN@[48; 49) - VALUE_PARAMETER@[49; 55) - BIND_PAT@[49; 50) - NAME@[49; 50) - IDENT@[49; 50) "x" - COLON@[50; 51) - PATH_TYPE@[51; 55) - PATH@[51; 55) - PATH_SEGMENT@[51; 55) - NAME_REF@[51; 55) - WHITESPACE@[51; 52) - IDENT@[52; 55) "i32" - COMMA@[55; 56) - VALUE_PARAMETER@[56; 62) - BIND_PAT@[56; 58) - NAME@[56; 58) - WHITESPACE@[56; 57) - IDENT@[57; 58) "y" - COLON@[58; 59) - TUPLE_TYPE@[59; 62) - WHITESPACE@[59; 60) - L_PAREN@[60; 61) - R_PAREN@[61; 62) - R_PAREN@[62; 63) - WHITESPACE@[63; 64) - BLOCK@[64; 67) - L_CURLY@[64; 65) - R_CURLY@[65; 66) - WHITESPACE@[66; 67) diff --git a/tests/data/parser/inline/0063_lambda_expr.rs b/tests/data/parser/inline/0063_lambda_expr.rs new file mode 100644 index 000000000..3c30a9209 --- /dev/null +++ b/tests/data/parser/inline/0063_lambda_expr.rs @@ -0,0 +1,6 @@ +fn foo() { + || (); + || -> i32 { 92 }; + |x| x; + |x: i32,| x; +} diff --git a/tests/data/parser/inline/0063_lambda_expr.txt b/tests/data/parser/inline/0063_lambda_expr.txt new file mode 100644 index 000000000..b1edffc14 --- /dev/null +++ b/tests/data/parser/inline/0063_lambda_expr.txt @@ -0,0 +1,91 @@ +FILE@[0; 74) + FN_ITEM@[0; 74) + 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@[9; 74) + L_CURLY@[9; 10) + EXPR_STMT@[10; 26) + LAMBDA_EXPR@[10; 20) + PARAM_LIST@[10; 18) + WHITESPACE@[10; 15) + PIPE@[15; 16) + PIPE@[16; 17) + WHITESPACE@[17; 18) + TUPLE_EXPR@[18; 20) + L_PAREN@[18; 19) + R_PAREN@[19; 20) + SEMI@[20; 21) + WHITESPACE@[21; 26) + EXPR_STMT@[26; 48) + LAMBDA_EXPR@[26; 42) + PARAM_LIST@[26; 29) + PIPE@[26; 27) + PIPE@[27; 28) + WHITESPACE@[28; 29) + THIN_ARROW@[29; 31) + PATH_TYPE@[31; 36) + PATH@[31; 36) + PATH_SEGMENT@[31; 36) + NAME_REF@[31; 36) + WHITESPACE@[31; 32) + IDENT@[32; 35) "i32" + WHITESPACE@[35; 36) + BLOCK@[36; 42) + L_CURLY@[36; 37) + LITERAL@[37; 41) + WHITESPACE@[37; 38) + INT_NUMBER@[38; 40) + WHITESPACE@[40; 41) + R_CURLY@[41; 42) + SEMI@[42; 43) + WHITESPACE@[43; 48) + EXPR_STMT@[48; 59) + LAMBDA_EXPR@[48; 53) + PARAM_LIST@[48; 52) + PIPE@[48; 49) + VALUE_PARAMETER@[49; 50) + BIND_PAT@[49; 50) + NAME@[49; 50) + IDENT@[49; 50) "x" + PIPE@[50; 51) + WHITESPACE@[51; 52) + PATH_EXPR@[52; 53) + PATH@[52; 53) + PATH_SEGMENT@[52; 53) + NAME_REF@[52; 53) + IDENT@[52; 53) "x" + SEMI@[53; 54) + WHITESPACE@[54; 59) + EXPR_STMT@[59; 72) + LAMBDA_EXPR@[59; 70) + PARAM_LIST@[59; 69) + PIPE@[59; 60) + VALUE_PARAMETER@[60; 66) + BIND_PAT@[60; 61) + NAME@[60; 61) + IDENT@[60; 61) "x" + COLON@[61; 62) + PATH_TYPE@[62; 66) + PATH@[62; 66) + PATH_SEGMENT@[62; 66) + NAME_REF@[62; 66) + WHITESPACE@[62; 63) + IDENT@[63; 66) "i32" + COMMA@[66; 67) + PIPE@[67; 68) + WHITESPACE@[68; 69) + PATH_EXPR@[69; 70) + PATH@[69; 70) + PATH_SEGMENT@[69; 70) + NAME_REF@[69; 70) + IDENT@[69; 70) "x" + SEMI@[70; 71) + WHITESPACE@[71; 72) + R_CURLY@[72; 73) + WHITESPACE@[73; 74) diff --git a/tests/data/parser/inline/0064_param_list.rs b/tests/data/parser/inline/0064_param_list.rs new file mode 100644 index 000000000..9d55bedbb --- /dev/null +++ b/tests/data/parser/inline/0064_param_list.rs @@ -0,0 +1,4 @@ +fn a() {} +fn b(x: i32) {} +fn c(x: i32, ) {} +fn d(x: i32, y: ()) {} diff --git a/tests/data/parser/inline/0064_param_list.txt b/tests/data/parser/inline/0064_param_list.txt new file mode 100644 index 000000000..96e03d71a --- /dev/null +++ b/tests/data/parser/inline/0064_param_list.txt @@ -0,0 +1,99 @@ +FILE@[0; 67) + FN_ITEM@[0; 10) + FN_KW@[0; 2) + NAME@[2; 4) + WHITESPACE@[2; 3) + IDENT@[3; 4) "a" + PARAM_LIST@[4; 7) + L_PAREN@[4; 5) + R_PAREN@[5; 6) + WHITESPACE@[6; 7) + BLOCK@[7; 10) + L_CURLY@[7; 8) + R_CURLY@[8; 9) + WHITESPACE@[9; 10) + FN_ITEM@[10; 26) + FN_KW@[10; 12) + NAME@[12; 14) + WHITESPACE@[12; 13) + IDENT@[13; 14) "b" + PARAM_LIST@[14; 23) + L_PAREN@[14; 15) + VALUE_PARAMETER@[15; 21) + BIND_PAT@[15; 16) + NAME@[15; 16) + IDENT@[15; 16) "x" + COLON@[16; 17) + PATH_TYPE@[17; 21) + PATH@[17; 21) + PATH_SEGMENT@[17; 21) + NAME_REF@[17; 21) + WHITESPACE@[17; 18) + IDENT@[18; 21) "i32" + R_PAREN@[21; 22) + WHITESPACE@[22; 23) + BLOCK@[23; 26) + L_CURLY@[23; 24) + R_CURLY@[24; 25) + WHITESPACE@[25; 26) + FN_ITEM@[26; 44) + FN_KW@[26; 28) + NAME@[28; 30) + WHITESPACE@[28; 29) + IDENT@[29; 30) "c" + PARAM_LIST@[30; 41) + L_PAREN@[30; 31) + VALUE_PARAMETER@[31; 37) + BIND_PAT@[31; 32) + NAME@[31; 32) + IDENT@[31; 32) "x" + COLON@[32; 33) + PATH_TYPE@[33; 37) + PATH@[33; 37) + PATH_SEGMENT@[33; 37) + NAME_REF@[33; 37) + WHITESPACE@[33; 34) + IDENT@[34; 37) "i32" + COMMA@[37; 38) + WHITESPACE@[38; 39) + R_PAREN@[39; 40) + WHITESPACE@[40; 41) + BLOCK@[41; 44) + L_CURLY@[41; 42) + R_CURLY@[42; 43) + WHITESPACE@[43; 44) + FN_ITEM@[44; 67) + FN_KW@[44; 46) + NAME@[46; 48) + WHITESPACE@[46; 47) + IDENT@[47; 48) "d" + PARAM_LIST@[48; 64) + L_PAREN@[48; 49) + VALUE_PARAMETER@[49; 55) + BIND_PAT@[49; 50) + NAME@[49; 50) + IDENT@[49; 50) "x" + COLON@[50; 51) + PATH_TYPE@[51; 55) + PATH@[51; 55) + PATH_SEGMENT@[51; 55) + NAME_REF@[51; 55) + WHITESPACE@[51; 52) + IDENT@[52; 55) "i32" + COMMA@[55; 56) + VALUE_PARAMETER@[56; 62) + BIND_PAT@[56; 58) + NAME@[56; 58) + WHITESPACE@[56; 57) + IDENT@[57; 58) "y" + COLON@[58; 59) + TUPLE_TYPE@[59; 62) + WHITESPACE@[59; 60) + L_PAREN@[60; 61) + R_PAREN@[61; 62) + R_PAREN@[62; 63) + WHITESPACE@[63; 64) + BLOCK@[64; 67) + L_CURLY@[64; 65) + R_CURLY@[65; 66) + WHITESPACE@[66; 67) -- cgit v1.2.3