Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
tobz1000 committed Feb 4, 2020
1 parent 912776f commit f622831
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 56 deletions.
2 changes: 1 addition & 1 deletion crates/ra_parser/src/grammar/expressions/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
let m = p.start();
p.eat(T![async]);
p.eat(T![move]);
params::param_list_opt_types(p);
params::param_list_closure(p);
if opt_fn_ret_type(p) {
if !p.at(T!['{']) {
p.error("expected `{`");
Expand Down
9 changes: 3 additions & 6 deletions crates/ra_parser/src/grammar/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
// async unsafe fn foo() {}
// unsafe const fn bar() {}
T![fn] => {
fn_def(p, flavor);
fn_def(p);
m.complete(p, FN_DEF);
}

Expand Down Expand Up @@ -301,7 +301,7 @@ pub(crate) fn extern_item_list(p: &mut Parser) {
m.complete(p, EXTERN_ITEM_LIST);
}

fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
fn fn_def(p: &mut Parser) {
assert!(p.at(T![fn]));
p.bump(T![fn]);

Expand All @@ -311,10 +311,7 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
type_params::opt_type_param_list(p);

if p.at(T!['(']) {
match flavor {
ItemFlavor::Mod => params::param_list(p),
ItemFlavor::Trait => params::param_list_opt_patterns(p),
}
params::param_list_fn(p);
} else {
p.error("expected function arguments");
}
Expand Down
91 changes: 45 additions & 46 deletions crates/ra_parser/src/grammar/params.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,67 @@
//! FIXME: write short doc here

// general TODO: `cargo xtask codegen && cargo test`

use super::*;

// test param_list
// fn a() {}
// fn b(x: i32) {}
// fn c(x: i32, ) {}
// fn d(x: i32, y: ()) {}
pub(super) fn param_list(p: &mut Parser) {
list_(p, Flavor::Normal)
pub(super) fn param_list_fn(p: &mut Parser) {
list_(p, Flavor::Function)
}

// test param_list_opt_patterns
// fn foo<F: FnMut(&mut Foo<'a>)>(){}
pub(super) fn param_list_opt_patterns(p: &mut Parser) {
list_(p, Flavor::OptionalPattern)
pub(super) fn param_list_impl_fn(p: &mut Parser) {
list_(p, Flavor::ImplFn)
}

pub(super) fn param_list_opt_types(p: &mut Parser) {
list_(p, Flavor::OptionalType)
pub(super) fn param_list_fn_ptr(p: &mut Parser) {
list_(p, Flavor::FnPointer)
}

#[derive(Clone, Copy, Eq, PartialEq)]
enum Flavor {
OptionalType,
OptionalPattern,
Normal,
pub(super) fn param_list_closure(p: &mut Parser) {
list_(p, Flavor::Closure)
}

impl Flavor {
fn type_required(self) -> bool {
match self {
Flavor::OptionalType => false,
_ => true,
}
}
#[derive(Debug, Clone, Copy)]
enum Flavor {
Function, // Includes trait fn params; omitted param idents are not supported
ImplFn,
FnPointer,
Closure
}

fn list_(p: &mut Parser, flavor: Flavor) {
let (bra, ket) = if flavor.type_required() { (T!['('], T![')']) } else { (T![|], T![|]) };
assert!(p.at(bra));
use Flavor::*;

let (bra, ket) = match flavor {
Closure => (T![|], T![|]),
Function | ImplFn | FnPointer => (T!['('], T![')'])
};

let m = p.start();
p.bump(bra);
if flavor.type_required() {

if let Function = flavor {
// test self_param_outer_attr
// fn f(#[must_use] self) {}
attributes::outer_attributes(p);
opt_self_param(p);
}

while !p.at(EOF) && !p.at(ket) {
// test param_outer_arg
// fn f(#[attr1] pat: Type) {}
attributes::outer_attributes(p);

if flavor.type_required() && p.at(T![...]) {
break;
if let Function | FnPointer = flavor {
if p.at(T![...]) {
break;
}
}

if !p.at_ts(VALUE_PARAMETER_FIRST) {
Expand All @@ -68,7 +75,7 @@ fn list_(p: &mut Parser, flavor: Flavor) {
}
// test param_list_vararg
// extern "C" { fn printf(format: *const i8, ...) -> i32; }
if flavor.type_required() {
if let Function | FnPointer = flavor {
p.eat(T![...]);
}
p.expect(ket);
Expand All @@ -77,39 +84,31 @@ fn list_(p: &mut Parser, flavor: Flavor) {

const VALUE_PARAMETER_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);

// TODO tests
fn value_parameter(p: &mut Parser, flavor: Flavor) {
let m = p.start();
match flavor {
Flavor::OptionalType | Flavor::Normal => {
Flavor::Function => {
patterns::pattern(p);
if p.at(T![:]) && !p.at(T![::]) || flavor.type_required() {
types::ascription(p)
}
types::ascription(p);
}
Flavor::ImplFn => {
types::type_(p);
}
// test value_parameters_no_patterns
// type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>;
Flavor::OptionalPattern => {
let la0 = p.current();
let la1 = p.nth(1);
let la2 = p.nth(2);
let la3 = p.nth(3);

// test trait_fn_placeholder_parameter
// trait Foo {
// fn bar(_: u64, mut x: i32);
// }
if (la0 == IDENT || la0 == T![_]) && la1 == T![:] && !p.nth_at(1, T![::])
|| la0 == T![mut] && la1 == IDENT && la2 == T![:]
|| la0 == T![&]
&& (la1 == IDENT && la2 == T![:] && !p.nth_at(2, T![::])
|| la1 == T![mut] && la2 == IDENT && la3 == T![:] && !p.nth_at(3, T![::]))
{
Flavor::FnPointer => {
if p.at(IDENT) {
patterns::pattern(p);
types::ascription(p);
} else {
types::type_(p);
}
}
Flavor::Closure => {
patterns::pattern(p);
if p.at(T![:]) && !p.at(T![::]) {
types::ascription(p);
}
}
}
m.complete(p, PARAM);
}
Expand Down
5 changes: 3 additions & 2 deletions crates/ra_parser/src/grammar/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ fn opt_path_type_args(p: &mut Parser, mode: Mode) {
Mode::Use => return,
Mode::Type => {
// test path_fn_trait_args
// type F = Box<Fn(x: i32) -> ()>;
// type F = Box<Fn(i32) -> ()>;
if p.at(T!['(']) {
params::param_list_opt_patterns(p);
// No binding allowed (test above shouldn't pass)
params::param_list_impl_fn(p);
opt_fn_ret_type(p);
} else {
type_args::opt_type_arg_list(p, false)
Expand Down
3 changes: 2 additions & 1 deletion crates/ra_parser/src/grammar/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ fn fn_pointer_type(p: &mut Parser) {
return;
}
if p.at(T!['(']) {
params::param_list_opt_patterns(p);
// optional binding, pattern not allowed
params::param_list_fn_ptr(p);
} else {
p.error("expected parameters")
}
Expand Down

0 comments on commit f622831

Please sign in to comment.