<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: --test
// xfail-fast

// In the current state of affairs, libuv registers a SIGCHLD handler when a
// process is spawned through it. This is not done with a SA_RESTART flag,
// meaning that all of our syscalls run the risk of returning EINTR. This error
// is not correctly handled in the majority of std::io, so these can't run with
// the main body of tests there.
//
// That being said, libuv correctly handles EINTR completely, so these tests
// themselves are safe against that. Currently the test runner may run into this
// problem, but it's less likely than a whole suite of tests...
//
// See #9341

use std::rt::io::process::*;
use std::rt::io::{Reader, Writer};
use std::rt::io::pipe::*;
use std::str;

#[test]
#[cfg(unix, not(android))]
fn smoke() {
    let io = ~[];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"true"],
        env: None,
        cwd: None,
        io: io,
    };
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert_eq!(p.wait(), 0);
}

#[test]
#[cfg(unix, not(android))]
fn smoke_failure() {
    let io = ~[];
    let args = ProcessConfig {
        program: "if-this-is-a-binary-then-the-world-has-ended",
        args: [],
        env: None,
        cwd: None,
        io: io,
    };
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert!(p.wait() != 0);
}

#[test]
#[cfg(unix, not(android))]
fn exit_reported_right() {
    let io = ~[];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"exit 1"],
        env: None,
        cwd: None,
        io: io,
    };
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert_eq!(p.wait(), 1);
}

fn read_all(input: &mut Reader) -> ~str {
    let mut ret = ~"";
    let mut buf = [0, ..1024];
    loop {
        match input.read(buf) {
            None => { break }
            Some(n) => { ret = ret + str::from_utf8(buf.slice_to(n)); }
        }
    }
    return ret;
}

fn run_output(args: ProcessConfig) -> ~str {
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert!(p.io[0].is_none());
    assert!(p.io[1].is_some());
    let ret = read_all(p.io[1].get_mut_ref() as &mut Reader);
    assert_eq!(p.wait(), 0);
    return ret;
}

#[test]
#[cfg(unix, not(android))]
fn stdout_works() {
    let pipe = PipeStream::new().unwrap();
    let io = ~[Ignored, CreatePipe(pipe, false, true)];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"echo foobar"],
        env: None,
        cwd: None,
        io: io,
    };
    assert_eq!(run_output(args), ~"foobar\n");
}

#[test]
#[cfg(unix, not(android))]
fn set_cwd_works() {
    let pipe = PipeStream::new().unwrap();
    let io = ~[Ignored, CreatePipe(pipe, false, true)];
    let cwd = Some("/");
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"pwd"],
        env: None,
        cwd: cwd,
        io: io,
    };
    assert_eq!(run_output(args), ~"/\n");
}

#[test]
#[cfg(unix, not(android))]
fn stdin_works() {
    let input = PipeStream::new().unwrap();
    let output = PipeStream::new().unwrap();
    let io = ~[CreatePipe(input, true, false),
               CreatePipe(output, false, true)];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"read line; echo $line"],
        env: None,
        cwd: None,
        io: io,
    };
    let mut p = Process::new(args).expect("didn't create a proces?!");
    p.io[0].get_mut_ref().write("foobar".as_bytes());
    p.io[0] = None; // close stdin;
    let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
    assert_eq!(p.wait(), 0);
    assert_eq!(out, ~"foobar\n");
}
<commit_msg>auto merge of #9698 : sanxiyn/rust/android, r=huonw<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: --test
// xfail-fast

// In the current state of affairs, libuv registers a SIGCHLD handler when a
// process is spawned through it. This is not done with a SA_RESTART flag,
// meaning that all of our syscalls run the risk of returning EINTR. This error
// is not correctly handled in the majority of std::io, so these can't run with
// the main body of tests there.
//
// That being said, libuv correctly handles EINTR completely, so these tests
// themselves are safe against that. Currently the test runner may run into this
// problem, but it's less likely than a whole suite of tests...
//
// See #9341

use std::rt::io::process::*;
use std::rt::io::{Reader, Writer};
use std::rt::io::pipe::*;
use std::str;

#[test]
#[cfg(unix, not(target_os="android"))]
fn smoke() {
    let io = ~[];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"true"],
        env: None,
        cwd: None,
        io: io,
    };
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert_eq!(p.wait(), 0);
}

#[test]
#[cfg(unix, not(target_os="android"))]
fn smoke_failure() {
    let io = ~[];
    let args = ProcessConfig {
        program: "if-this-is-a-binary-then-the-world-has-ended",
        args: [],
        env: None,
        cwd: None,
        io: io,
    };
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert!(p.wait() != 0);
}

#[test]
#[cfg(unix, not(target_os="android"))]
fn exit_reported_right() {
    let io = ~[];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"exit 1"],
        env: None,
        cwd: None,
        io: io,
    };
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert_eq!(p.wait(), 1);
}

fn read_all(input: &mut Reader) -> ~str {
    let mut ret = ~"";
    let mut buf = [0, ..1024];
    loop {
        match input.read(buf) {
            None => { break }
            Some(n) => { ret = ret + str::from_utf8(buf.slice_to(n)); }
        }
    }
    return ret;
}

fn run_output(args: ProcessConfig) -> ~str {
    let p = Process::new(args);
    assert!(p.is_some());
    let mut p = p.unwrap();
    assert!(p.io[0].is_none());
    assert!(p.io[1].is_some());
    let ret = read_all(p.io[1].get_mut_ref() as &mut Reader);
    assert_eq!(p.wait(), 0);
    return ret;
}

#[test]
#[cfg(unix, not(target_os="android"))]
fn stdout_works() {
    let pipe = PipeStream::new().unwrap();
    let io = ~[Ignored, CreatePipe(pipe, false, true)];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"echo foobar"],
        env: None,
        cwd: None,
        io: io,
    };
    assert_eq!(run_output(args), ~"foobar\n");
}

#[test]
#[cfg(unix, not(target_os="android"))]
fn set_cwd_works() {
    let pipe = PipeStream::new().unwrap();
    let io = ~[Ignored, CreatePipe(pipe, false, true)];
    let cwd = Some("/");
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"pwd"],
        env: None,
        cwd: cwd,
        io: io,
    };
    assert_eq!(run_output(args), ~"/\n");
}

#[test]
#[cfg(unix, not(target_os="android"))]
fn stdin_works() {
    let input = PipeStream::new().unwrap();
    let output = PipeStream::new().unwrap();
    let io = ~[CreatePipe(input, true, false),
               CreatePipe(output, false, true)];
    let args = ProcessConfig {
        program: "/bin/sh",
        args: [~"-c", ~"read line; echo $line"],
        env: None,
        cwd: None,
        io: io,
    };
    let mut p = Process::new(args).expect("didn't create a proces?!");
    p.io[0].get_mut_ref().write("foobar".as_bytes());
    p.io[0] = None; // close stdin;
    let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
    assert_eq!(p.wait(), 0);
    assert_eq!(out, ~"foobar\n");
}
<|endoftext|>


<commit_before>
extern crate nccl;

use nccl::{Pair, Scanner, NcclError, ErrorKind, Parser};

#[test]
fn pair_new() {
    assert_eq!(Pair::new("hello"), Pair {
        key: "hello".into(),
        value: vec![]
    });
}

#[test]
fn pair_add() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p, Pair {
        key: "top_level".into(),
        value: vec![Pair {
            key: "key".into(),
            value: vec![]
        }]
    });
}

#[test]
fn pair_get() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p.get("key").unwrap(), &mut Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_index() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p["key"], Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_keys() {
    let mut p = Pair::new("top");
    p.add("numbers");
    p["numbers"].add("1");
    p["numbers"].add("2");
    p["numbers"].add("3");
    p["numbers"].add("4");
    p["numbers"].add("5");
    assert_eq!(p["numbers"].keys(), vec!["1", "2", "3", "4", "5"]);
}

#[test]
fn pair_value_parse() {
    let mut p = Pair::new("top");
    p.add("bools");
    p["bools"].add("true");
    assert!(p["bools"].value_as::<bool>().unwrap());
}

#[test]
fn scanner_literal() {
    let mut s = Scanner::new("\"this: is neato\": burrito 64\n    yes.".into());
    s.scan_tokens().unwrap();
}

#[test]
#[should_panic]
fn error_key_not_found() {
    let mut p = Pair::new("jjj");
    p.get("jwiofiojwaef jio").unwrap();
}

#[test]
fn scan_file() {
    assert!(nccl::parse_file("config.nccl").is_ok());
}

#[test]
fn dos_unix_lines() {
    assert_eq!(nccl::parse_file("config.nccl"), nccl::parse_file("config_dos.nccl"));
}

#[test]
fn string_escape() {
    let mut s = Scanner::new("\"\\\"hello\\\"\\n\"".into());
    assert_eq!(s.scan_tokens().unwrap()[0].lexeme, "\"hello\"\n");
}

#[test]
fn add_pair() {
    // create a new pair
     let mut p1 = Pair::new("happy birthday");

     p1.add("Bobby");
     p1["Bobby"].add("Today!");

     // we think Ron's birthday is the 3rd...
     p1.add("Ron");
     p1["Ron"].add("March 3rd");

     // whoops, we were wrong
     let mut p2 = Pair::new("Ron");
     p2.add("March 2nd");

     // there you go Ron, happy belated birthday
     p1.add_pair(p2);
}

#[test]
fn add_slice_traverse() {
    let mut p = Pair::new("top");
    p.add_slice(&["a".into(), "b".into(), "c".into()]);
    assert_eq!(p.traverse(3), &mut Pair::new("c"));
}

#[test]
fn traverse_path() {
    let mut p = Pair::new("top");
    p.add_slice(&["a".into(), "b".into(), "c".into()]);
    p.traverse_path(&["a".into(), "b".into()]).add("happy");
    assert_eq!(p.traverse_path(&["a".into(), "b".into(), "happy".into()]), &mut Pair::new("happy"));
}

#[test]
fn add_slice() {
    let mut config = Pair::new("top_level");
    config.add("server");
    config["server"].add("domain");
    config["server"].add("port");
    config["server"].add("root");
    config["server"]["domain"].add("example.com");
    config["server"]["domain"].add("www.example.com");
    config["server"]["port"].add("80");
    config["server"]["port"].add("443");
    config["server"]["root"].add("/var/www/html");

    config.add_slice(&["server".into(), "port".into(), "22".into()]);
    assert_eq!(config["server"]["port"].keys(), vec!["80", "443", "22"]);
}

#[test]
#[should_panic]
fn multiple_errors() {
    let mut s = Scanner::new("hey: momma\n   test\n\tjeii\n    oh no!\n".into());
    s.scan_tokens().unwrap();
}

#[test]
fn parser() {
    let mut p = Parser::new(Scanner::new("hello\n    people\n    of\n    the world\n\nthis\n    is neat".into()).scan_tokens().unwrap());
    assert!(p.parse().is_ok());
}

#[test]
fn add_vec() {
    let mut p = Pair::new("__top_level__");
    p.add("a");
    p.add_slice(&["a".into(), "hello".into(), "world".into()]);
    p.add_slice(&["a".into(), "hello".into(), "world".into()]);
    assert_eq!(p["a"]["hello"].value.len(), 1);
}

#[test]
fn readme() {
    let mut config = Pair::new("top_level");

    // server
    //     domain
    //         example.com
    //         www.example.com
    //     port
    //         80
    //         443
    //     root
    //         /var/www/html

    config.add("server");
    config["server"].add("domain");
    config["server"].add("port");
    config["server"].add("root");
    config["server"]["domain"].add("example.com");
    config["server"]["domain"].add("www.example.com");
    config["server"]["port"].add("80");
    config["server"]["port"].add("443");
    config["server"]["root"].add("/var/www/html");

    let ports = config["server"]["port"].keys_as::<i32>().unwrap();
    assert_eq!(ports, vec![80, 443]);
}

<commit_msg>update tests??<commit_after>
extern crate nccl;

use nccl::{Pair, Scanner, NcclError, ErrorKind, Parser};

#[test]
fn pair_new() {
    assert_eq!(Pair::new("hello"), Pair {
        key: "hello".into(),
        value: vec![]
    });
}

#[test]
fn pair_add() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p, Pair {
        key: "top_level".into(),
        value: vec![Pair {
            key: "key".into(),
            value: vec![]
        }]
    });
}

#[test]
fn pair_get() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p.get("key").unwrap(), &mut Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_index() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p["key"], Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_keys() {
    let mut p = Pair::new("top");
    p.add("numbers");
    p["numbers"].add("1");
    p["numbers"].add("2");
    p["numbers"].add("3");
    p["numbers"].add("4");
    p["numbers"].add("5");
    assert_eq!(p["numbers"].keys(), vec!["1", "2", "3", "4", "5"]);
}

#[test]
fn pair_value_parse() {
    let mut p = Pair::new("top");
    p.add("bools");
    p["bools"].add("true");
    assert!(p["bools"].value_as::<bool>().unwrap());
}

#[test]
fn scanner_literal() {
    let mut s = Scanner::new("\"this: is neato\": burrito 64\n    yes.".into());
    s.scan_tokens().unwrap();
}

#[test]
#[should_panic]
fn error_key_not_found() {
    let mut p = Pair::new("jjj");
    p.get("jwiofiojwaef jio").unwrap();
}

#[test]
fn scan_file() {
    assert!(nccl::parse_file("config.nccl").is_ok());
}

#[test]
fn dos_unix_lines() {
    assert_eq!(nccl::parse_file("config.nccl"), nccl::parse_file("config_dos.nccl"));
}

#[test]
fn string_escape() {
    let mut s = Scanner::new("\"\\\"hello\\\"\\n\"".into());
    assert_eq!(s.scan_tokens().unwrap()[0].lexeme, "\"hello\"\n");
}

#[test]
fn add_pair() {
    // create a new pair
     let mut p1 = Pair::new("happy birthday");

     p1.add("Bobby");
     p1["Bobby"].add("Today!");

     // we think Ron's birthday is the 3rd...
     p1.add("Ron");
     p1["Ron"].add("March 3rd");

     // whoops, we were wrong
     let mut p2 = Pair::new("Ron");
     p2.add("March 2nd");

     // there you go Ron, happy belated birthday
     p1.add_pair(p2);
}

#[test]
fn add_slice_traverse() {
    let mut p = Pair::new("top");
    p.add_slice(&["a".into(), "b".into(), "c".into()]);
    assert_eq!(p.traverse(3), &mut Pair::new("c"));
}

#[test]
fn traverse_path() {
    let mut p = Pair::new("top");
    p.add_slice(&["a".into(), "b".into(), "c".into()]);
    p.traverse_path(&["a".into(), "b".into()]).add("happy");
    assert_eq!(p.traverse_path(&["a".into(), "b".into(), "happy".into()]), &mut Pair::new("happy"));
}

#[test]
fn add_slice() {
    let mut config = Pair::new("top_level");
    config.add("server");
    config["server"].add("domain");
    config["server"].add("port");
    config["server"].add("root");
    config["server"]["domain"].add("example.com");
    config["server"]["domain"].add("www.example.com");
    config["server"]["port"].add("80");
    config["server"]["port"].add("443");
    config["server"]["root"].add("/var/www/html");

    config.add_slice(&["server".into(), "port".into(), "22".into()]);
    assert_eq!(config["server"]["port"].keys(), vec!["80", "443", "22"]);
}

#[test]
#[should_panic]
fn multiple_errors() {
    let mut s = Scanner::new("hey: momma\n   test\n\tjeii\n    oh no!\n".into());
    s.scan_tokens().unwrap();
}

#[test]
fn parser() {
    let mut p = Parser::new(Scanner::new("hello\n    people\n    of\n    the world\n\nthis\n    is neat".into()).scan_tokens().unwrap());
    panic!("{:?}", p.parse());
    //assert!(p.parse().is_ok());
}

#[test]
fn add_vec() {
    let mut p = Pair::new("__top_level__");
    p.add("a");
    p.add_slice(&["a".into(), "hello".into(), "world".into()]);
    p.add_slice(&["a".into(), "hello".into(), "world".into()]);
    assert_eq!(p["a"]["hello"].value.len(), 1);
}

#[test]
fn readme() {
    let mut config = Pair::new("top_level");

    // server
    //     domain
    //         example.com
    //         www.example.com
    //     port
    //         80
    //         443
    //     root
    //         /var/www/html

    config.add("server");
    config["server"].add("domain");
    config["server"].add("port");
    config["server"].add("root");
    config["server"]["domain"].add("example.com");
    config["server"]["domain"].add("www.example.com");
    config["server"]["port"].add("80");
    config["server"]["port"].add("443");
    config["server"]["root"].add("/var/www/html");

    let ports = config["server"]["port"].keys_as::<i32>().unwrap();
    assert_eq!(ports, vec![80, 443]);
}

<|endoftext|>


<commit_before>extern crate lichen;

use lichen::parse::{Parser,Block,SrcBlock,Map};
use lichen::logic::{Logic,Expect};
use lichen::var::Var;
use lichen::source::{Src,Next};
use lichen::eval::Evaluator;

use std::collections::HashMap;

#[test]
fn parse_block() {
    let src = "root\n
    unequipped !some_item\n
    has_weight some_weight < 5.0\n
    some_comp:any [\nunequipped \nhas_weight\n]\n
\n
    if unequipped \"you're looking for something?\"\n
\n
    if some_comp \"welcome, \nlook around\"\n
    next:now end\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    let block_ = [Block::Src(
        SrcBlock {
            idx: 0,
            visited: false,
            or_valid: false,
            name: "root".to_owned(),
            src: vec![Src::Logic("unequipped".to_owned(),
                                 Logic::IsNot("some_item".to_owned())),

                      Src::Logic("has_weight".to_owned(),
                                 Logic::LT(Var::Sym("some_weight".to_owned()), 5.0 .into())),
                      Src::Composite("some_comp".to_owned(),
                                     Expect::Any,
                                     vec!["unequipped".to_owned(),"has_weight".to_owned()]),
                      Src::If("unequipped".to_owned(),
                              vec!["you're looking for something?".into()],
                              None),
                      Src::If("some_comp".to_owned(),
                              vec!["welcome, \nlook around".into()],
                              None),
                      Src::Next(Next::Now("end".to_owned()))],
            logic: HashMap::new(),
        })];

    assert_eq!(block[0],block_[0]);
}

#[test]
fn parse_qsym_block() {
    let src = "root\n
    if !some_item \"you're looking for something?\"\n
;";
    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[0] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[1] {
                Src::If(ref r_,_,_) => {
                    assert_eq!(r,r_);
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_qsym_comp_block() {
    let src =  "root\n
    has_weight some_weight < 5.0\n
    some_comp:any [has_weight !some_item ]\n
    ;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[1] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[2] {
                Src::Composite(_,_,ref x) => {
                    assert_eq!(r,&x[1]);
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn validate_qsym_block() {
    let src =  "root\n
    if other_item next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (_,nn) = ev.next().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn validate_reflection_block() {
    let src =  "root\n
    has other_item\n
    hasnt some_item\n
    hasnt-too !hasnt\n
    comp:all has hasnt-too\n
    if comp next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (_,nn) = ev.last().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn parse_if_vec_block() {
    let src = "root\n
    if !some_item [\n
        \"you're looking for something?\"\n
        \"welcome, \nlook around\"\n
        next:now store]\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            match b.src[1] {
                Src::If(_,_, ref next) => {
                    assert_eq!(next,&Some(Next::Now("store".to_owned())));
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_eval_str_block() {
    let src = "root\n
        has_weight some_weight < 5.0\n
        some_comp:all [has_weight !some_item ]\n
    if some_comp \"looks like you are `some_weight kgs heavy, `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_node) = ev.last().unwrap();

    assert_eq!(vars, ["looks like you are 4 kgs heavy, Io".into()]);
}

#[test]
fn parse_compare_env_block() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight next:now store\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (_vars,node) = ev.last().unwrap();

    assert_eq!(node, Some(Next::Now("store".to_string())));
}

#[test]
fn parse_return_varkind() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight some_weight \"hi `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 4.0 .into());
    assert_eq!(vars[1], "hi Io" .into());
}

#[test]
fn parse_follow_nodes() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight next:now store\n
;\n
\n
store\n
    if !some_item \"welcome, \nlook around\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], "welcome, \nlook around".into());
}

#[test]
fn parse_select_nodes() {
    let src = "root\n
    next:select {\"Head to Store?\" store,\n
                \"Leave the town?\" exit-town}\n
\n
    if !some_item [\"Some choices\"
        next:select {\"Head to Store?\" store,\n
                    \"Leave the town?\" exit-town}]\n
\n
    next:select {\"Head to town?\" store bakery tanner,\n
                5 hike,
                \"Leave the town?\" exit-town}\n
\n
    emit \"A dustball blows by\"\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (_vars,select1) = ev.next().unwrap();
    let (_vars,select2) = ev.next().unwrap();

    assert_eq!(select1,select2);

    let mut map: Map = HashMap::new();
    map.insert("Head to Store?".to_owned(), vec![Var::Sym("store".to_owned())]);
    map.insert("Leave the town?".to_owned(), vec![Var::Sym("exit-town".to_owned())]);

    assert_eq!(select1, Some(Next::Select(map)));

    let (_,select) = ev.next().unwrap();
    match select.expect("Unable to parse map") {
        Next::Select(map) => {
            println!("Map: {:?}",map);
            assert!(map.contains_key("5"));
            assert_eq!(map.get("5"), Some(&vec![Var::Sym("hike".to_owned())]));
        },
        _ => { panic!("Invalid Next type found") }
    }
}

#[test]
fn parse_next_back_restart() {
    let src = "root\n
    next:now step2
    next:restart\n
;\n
step2
    next:back\n
;\n";

    let p = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    let mut env = p.into_env();

    let mut ev = Evaluator::new(&mut env);

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Now("step2".to_owned())));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Back));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Restart(None)));
}

#[test]
fn parse_or_logic() {
    let src = "root\n
    weight some_weight < other_weight\n
    if !weight false\n
    or true\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], true.into());
}

#[test]
fn validate_inv_logic() {
    let src = "root\n
    if !global.name \"missing name\"\n
    or \"name is `global.name\"\n
\n
    if global.is_false \"is_false\"\n
    when {!global.name @global.name \"new-name\"}\n
    emit global.name\n
;\n
def global\n
    is_false false\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "missing name".into());

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "new-name".into());
}
<commit_msg>fix tests<commit_after>extern crate lichen;

use lichen::parse::{Parser,Block,SrcBlock,Map};
use lichen::logic::{Logic,Expect};
use lichen::var::Var;
use lichen::source::{Src,Next};
use lichen::eval::Evaluator;

use std::collections::HashMap;

#[test]
fn parse_block() {
    let src = "root\n
    unequipped !some_item\n
    has_weight some_weight < 5.0\n
    some_comp:any [\nunequipped \nhas_weight\n]\n
\n
    if unequipped \"you're looking for something?\"\n
\n
    if some_comp \"welcome, \nlook around\"\n
    next:now end\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    let block_ = [Block::Src(
        SrcBlock {
            idx: 0,
            visited: false,
            or_valid: false,
            name: "root".to_owned(),
            src: vec![Src::Logic("unequipped".to_owned(),
                                 Logic::IsNot("some_item".to_owned())),

                      Src::Logic("has_weight".to_owned(),
                                 Logic::LT(Var::Sym("some_weight".to_owned()), 5.0 .into())),
                      Src::Composite("some_comp".to_owned(),
                                     Expect::Any,
                                     vec!["unequipped".to_owned(),"has_weight".to_owned()]),
                      Src::If("unequipped".to_owned(),
                              vec!["you're looking for something?".into()],
                              None),
                      Src::If("some_comp".to_owned(),
                              vec!["welcome, \nlook around".into()],
                              None),
                      Src::Next(Next::Now("end".to_owned()))],
            logic: HashMap::new(),
        })];

    assert_eq!(block[0],block_[0]);
}

#[test]
fn parse_qsym_block() {
    let src = "root\n
    if !some_item \"you're looking for something?\"\n
;";
    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[0] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[1] {
                Src::If(ref r_,_,_) => {
                    assert_eq!(r,r_);
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_qsym_comp_block() {
    let src =  "root\n
    has_weight some_weight < 5.0\n
    some_comp:any [has_weight !some_item ]\n
    ;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[1] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[2] {
                Src::Composite(_,_,ref x) => {
                    assert_eq!(r,&x[1]);
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn validate_qsym_block() {
    let src =  "root\n
    if other_item next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (_,nn) = ev.next().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn validate_reflection_block() {
    let src =  "root\n
    has other_item\n
    hasnt some_item\n
    hasnt-too !hasnt\n
    comp:all has hasnt-too\n
    if comp next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (_,nn) = ev.last().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn parse_if_vec_block() {
    let src = "root\n
    if !some_item [\n
        \"you're looking for something?\"\n
        \"welcome, \nlook around\"\n
        next:now store]\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            match b.src[1] {
                Src::If(_,_, ref next) => {
                    assert_eq!(next,&Some(Next::Now("store".to_owned())));
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_eval_str_block() {
    let src = "root\n
        has_weight 4 < 5.0\n
        some_comp:all [has_weight !some_item ]\n
    if some_comp \"looks like you are `some_weight kgs heavy, `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_node) = ev.last().unwrap();

    assert_eq!(vars, ["looks like you are 4 kgs heavy, Io".into()]);
}

#[test]
fn parse_compare_env_block() {
    let src = "root\n
    weight 0 < 1\n
    if weight next:now store\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (_vars,node) = ev.last().unwrap();

    assert_eq!(node, Some(Next::Now("store".to_string())));
}

#[test]
fn parse_return_varkind() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight some_weight \"hi `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 4.0 .into());
    assert_eq!(vars[1], "hi Io" .into());
}

#[test]
fn parse_follow_nodes() {
    let src = "root\n
    weight 0 < 1\n
    if weight next:now store\n
;\n
\n
store\n
    if !some_item \"welcome, \nlook around\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], "welcome, \nlook around".into());
}

#[test]
fn parse_select_nodes() {
    let src = "root\n
    next:select {\"Head to Store?\" store,\n
                \"Leave the town?\" exit-town}\n
\n
    if !some_item [\"Some choices\"
        next:select {\"Head to Store?\" store,\n
                    \"Leave the town?\" exit-town}]\n
\n
    next:select {\"Head to town?\" store bakery tanner,\n
                5 hike,
                \"Leave the town?\" exit-town}\n
\n
    emit \"A dustball blows by\"\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (_vars,select1) = ev.next().unwrap();
    let (_vars,select2) = ev.next().unwrap();

    assert_eq!(select1,select2);

    let mut map: Map = HashMap::new();
    map.insert("Head to Store?".to_owned(), vec![Var::Sym("store".to_owned())]);
    map.insert("Leave the town?".to_owned(), vec![Var::Sym("exit-town".to_owned())]);

    assert_eq!(select1, Some(Next::Select(map)));

    let (_,select) = ev.next().unwrap();
    match select.expect("Unable to parse map") {
        Next::Select(map) => {
            println!("Map: {:?}",map);
            assert!(map.contains_key("5"));
            assert_eq!(map.get("5"), Some(&vec![Var::Sym("hike".to_owned())]));
        },
        _ => { panic!("Invalid Next type found") }
    }
}

#[test]
fn parse_next_back_restart() {
    let src = "root\n
    next:now step2
    next:restart\n
;\n
step2
    next:back\n
;\n";

    let p = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    let mut env = p.into_env();

    let mut ev = Evaluator::new(&mut env);

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Now("step2".to_owned())));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Back));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Restart(None)));
}

#[test]
fn parse_or_logic() {
    let src = "root\n
    has_weight 101 < 100\n
    if !has_weight \"can add stuff\"\n
    or \"too heavy!\"\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], "can add stuff".into());
}

#[test]
fn validate_inv_logic() {
    let src = "root\n
    if !global.name \"missing name\"\n
    or \"name is `global.name\"\n
\n
    if global.is_false \"is_false\"\n
    when {!global.name @global.name \"new-name\"}\n
    emit global.name\n
;\n
def global\n
    is_false false\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "missing name".into());

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "new-name".into());
}
<|endoftext|>


<commit_before>use super::*;
use crate::prelude::*;

use crate::guid::GUID;
use syn::{LitStr, Path};

#[derive(Debug, Clone)]
pub enum LibraryItemType
{
    Module(Path),
    Class(Path),
    Interface(Path),
}

impl syn::parse::Parse for LibraryItemType
{
    fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self>
    {
        let ident: syn::Ident = input.parse()?;
        match ident.to_string().as_str() {
            "module" => Ok(LibraryItemType::Module(input.parse()?)),
            "class" => Ok(LibraryItemType::Class(input.parse()?)),
            "interface" => Ok(LibraryItemType::Interface(input.parse()?)),
            _ => Err(input.error(&format!(
                "Expected 'class', 'interface' or 'module', found {}",
                ident
            ))),
        }
    }
}

intercom_attribute!(
    ComLibraryAttr< ComLibraryAttrParam, LibraryItemType > {
        libid : LitStr,
        on_load : Path,
    }
);

const EMPTY: [Path; 0] = [];

/// COM library details derived from the `com_library` attribute.
#[derive(Debug, PartialEq)]
pub struct ComLibrary
{
    pub name: String,
    pub libid: GUID,
    pub on_load: Option<Path>,
    pub coclasses: Vec<Path>,
    pub interfaces: Vec<Path>,
    pub submodules: Vec<Path>,
}

impl ComLibrary
{
    /// Parses a [com_library] attribute.
    pub fn parse(crate_name: &str, attr_params: TokenStream) -> ParseResult<ComLibrary>
    {
        let attr: ComLibraryAttr = ::syn::parse2(attr_params)
            .map_err(|_| ParseError::ComLibrary("Attribute syntax error".into()))?;

        // The first parameter is the LIBID of the library.
        let libid = match attr.libid().map_err(ParseError::ComLibrary)? {
            Some(libid) => GUID::parse(&libid.value()).map_err(ParseError::ComLibrary)?,
            None => crate::utils::generate_libid(crate_name),
        };

        let on_load = attr.on_load().map_err(ParseError::ComLibrary)?.cloned();

        let mut coclasses = vec![];
        let mut interfaces = vec![];
        let mut submodules = vec![];
        for arg in attr.args().into_iter().cloned() {
            match arg {
                LibraryItemType::Class(cls) => coclasses.push(cls),
                LibraryItemType::Interface(cls) => interfaces.push(cls),
                LibraryItemType::Module(cls) => submodules.push(cls),
            }
        }

        Ok(ComLibrary {
            name: crate_name.to_owned(),
            on_load,
            coclasses,
            interfaces,
            submodules,
            libid,
        })
    }
}

#[cfg(test)]
mod test
{
    use super::*;

    #[test]
    fn parse_com_library()
    {
        let lib = ComLibrary::parse(
            "library_name".into(),
            quote!(
                libid = "12345678-1234-1234-1234-567890ABCDEF",
                class Foo,
                class Bar),
        )
        .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "library_name");
        assert_eq!(
            lib.libid,
            GUID {
                data1: 0x12345678,
                data2: 0x1234,
                data3: 0x1234,
                data4: [0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF]
            }
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(Foo));
        assert_eq!(lib.coclasses[1], parse_quote!(Bar));
    }

    #[test]
    fn parse_com_library_with_auto_guid()
    {
        // This test derives the GUID from the library name.
        //
        // What the final GUID is isn't important, what _is_ important however
        // is that the final GUID will not change ever as long as the library
        // name stays the same.
        let lib = ComLibrary::parse("another_library".into(), quote!(class One, class Two))
            .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "another_library");
        assert_eq!(
            lib.libid,
            GUID::parse("696B2FAE-AC56-3E08-7C2C-ABAA8DB8F6E3").unwrap()
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(One));
        assert_eq!(lib.coclasses[1], parse_quote!(Two));
    }

    #[test]
    fn parse_com_library_with_empty_parameters()
    {
        let lib = ComLibrary::parse("lib".into(), quote!()).unwrap();
        assert_eq!(lib.coclasses.len(), 0);
        assert_eq!(
            lib.libid,
            GUID::parse("22EC0095-CD17-3AFD-6C4F-531464178911").unwrap()
        );
    }
}
<commit_msg>Fix clippy warnings<commit_after>use super::*;
use crate::prelude::*;

use crate::guid::GUID;
use syn::{LitStr, Path};

#[derive(Debug, Clone)]
pub enum LibraryItemType
{
    Module(Path),
    Class(Path),
    Interface(Path),
}

impl syn::parse::Parse for LibraryItemType
{
    fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self>
    {
        let ident: syn::Ident = input.parse()?;
        match ident.to_string().as_str() {
            "module" => Ok(LibraryItemType::Module(input.parse()?)),
            "class" => Ok(LibraryItemType::Class(input.parse()?)),
            "interface" => Ok(LibraryItemType::Interface(input.parse()?)),
            _ => Err(input.error(&format!(
                "Expected 'class', 'interface' or 'module', found {}",
                ident
            ))),
        }
    }
}

intercom_attribute!(
    ComLibraryAttr< ComLibraryAttrParam, LibraryItemType > {
        libid : LitStr,
        on_load : Path,
    }
);

/// COM library details derived from the `com_library` attribute.
#[derive(Debug, PartialEq)]
pub struct ComLibrary
{
    pub name: String,
    pub libid: GUID,
    pub on_load: Option<Path>,
    pub coclasses: Vec<Path>,
    pub interfaces: Vec<Path>,
    pub submodules: Vec<Path>,
}

impl ComLibrary
{
    /// Parses a [com_library] attribute.
    pub fn parse(crate_name: &str, attr_params: TokenStream) -> ParseResult<ComLibrary>
    {
        let attr: ComLibraryAttr = ::syn::parse2(attr_params)
            .map_err(|_| ParseError::ComLibrary("Attribute syntax error".into()))?;

        // The first parameter is the LIBID of the library.
        let libid = match attr.libid().map_err(ParseError::ComLibrary)? {
            Some(libid) => GUID::parse(&libid.value()).map_err(ParseError::ComLibrary)?,
            None => crate::utils::generate_libid(crate_name),
        };

        let on_load = attr.on_load().map_err(ParseError::ComLibrary)?.cloned();

        let mut coclasses = vec![];
        let mut interfaces = vec![];
        let mut submodules = vec![];
        for arg in attr.args().into_iter().cloned() {
            match arg {
                LibraryItemType::Class(cls) => coclasses.push(cls),
                LibraryItemType::Interface(cls) => interfaces.push(cls),
                LibraryItemType::Module(cls) => submodules.push(cls),
            }
        }

        Ok(ComLibrary {
            name: crate_name.to_owned(),
            on_load,
            coclasses,
            interfaces,
            submodules,
            libid,
        })
    }
}

#[cfg(test)]
mod test
{
    use super::*;

    #[test]
    fn parse_com_library()
    {
        let lib = ComLibrary::parse(
            "library_name".into(),
            quote!(
                libid = "12345678-1234-1234-1234-567890ABCDEF",
                class Foo,
                class Bar),
        )
        .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "library_name");
        assert_eq!(
            lib.libid,
            GUID {
                data1: 0x12345678,
                data2: 0x1234,
                data3: 0x1234,
                data4: [0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF]
            }
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(Foo));
        assert_eq!(lib.coclasses[1], parse_quote!(Bar));
    }

    #[test]
    fn parse_com_library_with_auto_guid()
    {
        // This test derives the GUID from the library name.
        //
        // What the final GUID is isn't important, what _is_ important however
        // is that the final GUID will not change ever as long as the library
        // name stays the same.
        let lib = ComLibrary::parse("another_library".into(), quote!(class One, class Two))
            .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "another_library");
        assert_eq!(
            lib.libid,
            GUID::parse("696B2FAE-AC56-3E08-7C2C-ABAA8DB8F6E3").unwrap()
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(One));
        assert_eq!(lib.coclasses[1], parse_quote!(Two));
    }

    #[test]
    fn parse_com_library_with_empty_parameters()
    {
        let lib = ComLibrary::parse("lib".into(), quote!()).unwrap();
        assert_eq!(lib.coclasses.len(), 0);
        assert_eq!(
            lib.libid,
            GUID::parse("22EC0095-CD17-3AFD-6C4F-531464178911").unwrap()
        );
    }
}
<|endoftext|>


<commit_before>use crate::{
    assist_context::{AssistContext, Assists},
    AssistId,
};
use ide_db::helpers::FamousDefs;
use itertools::Itertools;
use stdx::format_to;
use syntax::{
    ast::{self, AttrsOwner, GenericParamsOwner, Impl, NameOwner, TypeBoundsOwner},
    AstNode,
};

// Assist: generate_default_from_new
//
// Generates default implementation from new method.
//
// ```
// struct Example { _inner: () }
//
// impl Example {
//     pub fn n$0ew() -> Self {
//         Self { _inner: () }
//     }
// }
// ```
// ->
// ```
// struct Example { _inner: () }
//
// impl Example {
//     pub fn new() -> Self {
//         Self { _inner: () }
//     }
// }
//
// impl Default for Example {
//     fn default() -> Self {
//         Self::new()
//     }
// }
// ```
pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
    let fn_name = fn_node.name()?;

    if fn_name.text() != "new" {
        cov_mark::hit!(other_function_than_new);
        return None;
    }

    if fn_node.param_list()?.params().next().is_some() {
        cov_mark::hit!(new_function_with_parameters);
        return None;
    }

    let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
    if is_default_implemented(ctx, &impl_) {
        cov_mark::hit!(default_block_is_already_present);
        cov_mark::hit!(struct_in_module_with_default);
        return None;
    }

    let insert_location = impl_.syntax().text_range();

    acc.add(
        AssistId("generate_default_from_new", crate::AssistKind::Generate),
        "Generate a Default impl from a new fn",
        insert_location,
        move |builder| {
            let default_code = "    fn default() -> Self {
        Self::new()
    }";
            let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
            builder.insert(insert_location.end(), code);
        },
    )
}

fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
    let generic_params = impl_.generic_param_list();
    let mut buf = String::with_capacity(code.len());
    buf.push_str("\n\n");
    impl_
        .attrs()
        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
        .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
    buf.push_str("impl");

    if let Some(generic_params) = &generic_params {
        let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
        let type_params = generic_params.type_params().map(|type_param| {
            let mut buf = String::new();
            if let Some(it) = type_param.name() {
                format_to!(buf, "{}", it.syntax());
            }
            if let Some(it) = type_param.colon_token() {
                format_to!(buf, "{} ", it);
            }
            if let Some(it) = type_param.type_bound_list() {
                format_to!(buf, "{}", it.syntax());
            }
            buf
        });
        let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
        let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
        format_to!(buf, "<{}>", generics);
    }

    buf.push(' ');
    buf.push_str(trait_text);
    buf.push_str(" for ");
    buf.push_str(&impl_.self_ty().unwrap().syntax().text().to_string());

    match impl_.where_clause() {
        Some(where_clause) => {
            format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
        }
        None => {
            format_to!(buf, " {{\n{}\n}}", code);
        }
    }

    buf
}

fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
    let db = ctx.sema.db;
    let impl_ = ctx.sema.to_def(impl_);
    let impl_def = match impl_ {
        Some(value) => value,
        None => return false,
    };

    let ty = impl_def.self_ty(db);
    let krate = impl_def.module(db).krate();
    let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default();
    let default_trait = match default {
        Some(value) => value,
        None => return false,
    };

    ty.impls_trait(db, default_trait, &[])
}

#[cfg(test)]
mod tests {
    use ide_db::helpers::FamousDefs;

    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn generate_default() {
        check_pass(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn ne$0w() -> Self {
        Self { _inner: () }
    }
}

fn main() {}
"#,
            r#"
struct Example { _inner: () }

impl Example {
    pub fn new() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}

fn main() {}
"#,
        );
    }

    #[test]
    fn generate_default2() {
        check_pass(
            r#"
struct Test { value: u32 }

impl Test {
    pub fn ne$0w() -> Self {
        Self { value: 0 }
    }
}
"#,
            r#"
struct Test { value: u32 }

impl Test {
    pub fn new() -> Self {
        Self { value: 0 }
    }
}

impl Default for Test {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generic() {
        check_pass(
            r#"
pub struct Foo<T> {
    _bar: *mut T,
}

impl<T> Foo<T> {
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T> {
    _bar: *mut T,
}

impl<T> Foo<T> {
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T> Default for Foo<T> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generics() {
        check_pass(
            r#"
pub struct Foo<T, B> {
    _tars: *mut T,
    _bar: *mut B,
}

impl<T, B> Foo<T, B> {
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T, B> {
    _tars: *mut T,
    _bar: *mut B,
}

impl<T, B> Foo<T, B> {
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T, B> Default for Foo<T, B> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generic_and_bound() {
        check_pass(
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T> {
    pub fn ne$0w() -> Self {
        Foo { t: 0.into() }
    }
}
"#,
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T> {
    pub fn new() -> Self {
        Foo { t: 0.into() }
    }
}

impl<T: From<i32>> Default for Foo<T> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generics_and_bounds() {
        check_pass(
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B> {
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B> {
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generic_and_where() {
        check_pass(
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T>
where
    Option<T>: Debug
{
    pub fn ne$0w() -> Self {
        Foo { t: 0.into() }
    }
}
"#,
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T>
where
    Option<T>: Debug
{
    pub fn new() -> Self {
        Foo { t: 0.into() }
    }
}

impl<T: From<i32>> Default for Foo<T>
where
    Option<T>: Debug
{
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generics_and_wheres() {
        check_pass(
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B>
where
    Option<T>: Debug, Option<B>: Debug,
{
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B>
where
    Option<T>: Debug, Option<B>: Debug,
{
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T: From<i32>, B: From<i64>> Default for Foo<T, B>
where
    Option<T>: Debug, Option<B>: Debug,
{
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_parameters() {
        cov_mark::check!(new_function_with_parameters);
        check_not_applicable(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn $0new(value: ()) -> Self {
        Self { _inner: value }
    }
}
"#,
        );
    }

    #[test]
    fn other_function_than_new() {
        cov_mark::check!(other_function_than_new);
        check_not_applicable(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn a$0dd() -> Self {
        Self { _inner: () }
    }
}

"#,
        );
    }

    #[test]
    fn default_block_is_already_present() {
        cov_mark::check!(default_block_is_already_present);
        check_not_applicable(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn n$0ew() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn standalone_new_function() {
        check_not_applicable(
            r#"
fn n$0ew() -> u32 {
    0
}
"#,
        );
    }

    #[test]
    fn multiple_struct_blocks() {
        check_pass(
            r#"
struct Example { _inner: () }
struct Test { value: u32 }

impl Example {
    pub fn new$0() -> Self {
        Self { _inner: () }
    }
}
"#,
            r#"
struct Example { _inner: () }
struct Test { value: u32 }

impl Example {
    pub fn new() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn when_struct_is_after_impl() {
        check_pass(
            r#"
impl Example {
    pub fn $0new() -> Self {
        Self { _inner: () }
    }
}

struct Example { _inner: () }
"#,
            r#"
impl Example {
    pub fn new() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}

struct Example { _inner: () }
"#,
        );
    }

    #[test]
    fn struct_in_module() {
        check_pass(
            r#"
mod test {
    struct Example { _inner: () }

    impl Example {
        pub fn n$0ew() -> Self {
            Self { _inner: () }
        }
    }
}
"#,
            r#"
mod test {
    struct Example { _inner: () }

    impl Example {
        pub fn new() -> Self {
            Self { _inner: () }
        }
    }

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}
}
"#,
        );
    }

    #[test]
    fn struct_in_module_with_default() {
        cov_mark::check!(struct_in_module_with_default);
        check_not_applicable(
            r#"
mod test {
    struct Example { _inner: () }

    impl Example {
        pub fn n$0ew() -> Self {
            Self { _inner: () }
        }
    }

    impl Default for Example {
        fn default() -> Self {
            Self::new()
        }
    }
}
"#,
        );
    }

    fn check_pass(before: &str, after: &str) {
        let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
        check_assist(generate_default_from_new, before, after);
    }

    fn check_not_applicable(before: &str) {
        let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
        check_assist_not_applicable(generate_default_from_new, before);
    }
}
<commit_msg>Remove attrs<commit_after>use crate::{
    assist_context::{AssistContext, Assists},
    AssistId,
};
use ide_db::helpers::FamousDefs;
use itertools::Itertools;
use stdx::format_to;
use syntax::{
    ast::{self, GenericParamsOwner, Impl, NameOwner, TypeBoundsOwner},
    AstNode,
};

// Assist: generate_default_from_new
//
// Generates default implementation from new method.
//
// ```
// struct Example { _inner: () }
//
// impl Example {
//     pub fn n$0ew() -> Self {
//         Self { _inner: () }
//     }
// }
// ```
// ->
// ```
// struct Example { _inner: () }
//
// impl Example {
//     pub fn new() -> Self {
//         Self { _inner: () }
//     }
// }
//
// impl Default for Example {
//     fn default() -> Self {
//         Self::new()
//     }
// }
// ```
pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
    let fn_name = fn_node.name()?;

    if fn_name.text() != "new" {
        cov_mark::hit!(other_function_than_new);
        return None;
    }

    if fn_node.param_list()?.params().next().is_some() {
        cov_mark::hit!(new_function_with_parameters);
        return None;
    }

    let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
    if is_default_implemented(ctx, &impl_) {
        cov_mark::hit!(default_block_is_already_present);
        cov_mark::hit!(struct_in_module_with_default);
        return None;
    }

    let insert_location = impl_.syntax().text_range();

    acc.add(
        AssistId("generate_default_from_new", crate::AssistKind::Generate),
        "Generate a Default impl from a new fn",
        insert_location,
        move |builder| {
            let default_code = "    fn default() -> Self {
        Self::new()
    }";
            let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
            builder.insert(insert_location.end(), code);
        },
    )
}

fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
    let generic_params = impl_.generic_param_list();
    let mut buf = String::with_capacity(code.len());
    buf.push_str("\n\n");
    buf.push_str("impl");

    if let Some(generic_params) = &generic_params {
        let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
        let type_params = generic_params.type_params().map(|type_param| {
            let mut buf = String::new();
            if let Some(it) = type_param.name() {
                format_to!(buf, "{}", it.syntax());
            }
            if let Some(it) = type_param.colon_token() {
                format_to!(buf, "{} ", it);
            }
            if let Some(it) = type_param.type_bound_list() {
                format_to!(buf, "{}", it.syntax());
            }
            buf
        });
        let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
        let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
        format_to!(buf, "<{}>", generics);
    }

    buf.push(' ');
    buf.push_str(trait_text);
    buf.push_str(" for ");
    buf.push_str(&impl_.self_ty().unwrap().syntax().text().to_string());

    match impl_.where_clause() {
        Some(where_clause) => {
            format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
        }
        None => {
            format_to!(buf, " {{\n{}\n}}", code);
        }
    }

    buf
}

fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
    let db = ctx.sema.db;
    let impl_ = ctx.sema.to_def(impl_);
    let impl_def = match impl_ {
        Some(value) => value,
        None => return false,
    };

    let ty = impl_def.self_ty(db);
    let krate = impl_def.module(db).krate();
    let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default();
    let default_trait = match default {
        Some(value) => value,
        None => return false,
    };

    ty.impls_trait(db, default_trait, &[])
}

#[cfg(test)]
mod tests {
    use ide_db::helpers::FamousDefs;

    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn generate_default() {
        check_pass(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn ne$0w() -> Self {
        Self { _inner: () }
    }
}

fn main() {}
"#,
            r#"
struct Example { _inner: () }

impl Example {
    pub fn new() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}

fn main() {}
"#,
        );
    }

    #[test]
    fn generate_default2() {
        check_pass(
            r#"
struct Test { value: u32 }

impl Test {
    pub fn ne$0w() -> Self {
        Self { value: 0 }
    }
}
"#,
            r#"
struct Test { value: u32 }

impl Test {
    pub fn new() -> Self {
        Self { value: 0 }
    }
}

impl Default for Test {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generic() {
        check_pass(
            r#"
pub struct Foo<T> {
    _bar: *mut T,
}

impl<T> Foo<T> {
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T> {
    _bar: *mut T,
}

impl<T> Foo<T> {
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T> Default for Foo<T> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generics() {
        check_pass(
            r#"
pub struct Foo<T, B> {
    _tars: *mut T,
    _bar: *mut B,
}

impl<T, B> Foo<T, B> {
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T, B> {
    _tars: *mut T,
    _bar: *mut B,
}

impl<T, B> Foo<T, B> {
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T, B> Default for Foo<T, B> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generic_and_bound() {
        check_pass(
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T> {
    pub fn ne$0w() -> Self {
        Foo { t: 0.into() }
    }
}
"#,
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T> {
    pub fn new() -> Self {
        Foo { t: 0.into() }
    }
}

impl<T: From<i32>> Default for Foo<T> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generics_and_bounds() {
        check_pass(
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B> {
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B> {
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generic_and_where() {
        check_pass(
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T>
where
    Option<T>: Debug
{
    pub fn ne$0w() -> Self {
        Foo { t: 0.into() }
    }
}
"#,
            r#"
pub struct Foo<T> {
    t: T,
}

impl<T: From<i32>> Foo<T>
where
    Option<T>: Debug
{
    pub fn new() -> Self {
        Foo { t: 0.into() }
    }
}

impl<T: From<i32>> Default for Foo<T>
where
    Option<T>: Debug
{
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_generics_and_wheres() {
        check_pass(
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B>
where
    Option<T>: Debug, Option<B>: Debug,
{
    pub fn ne$0w() -> Self {
        unimplemented!()
    }
}
"#,
            r#"
pub struct Foo<T, B> {
    _tars: T,
    _bar: B,
}

impl<T: From<i32>, B: From<i64>> Foo<T, B>
where
    Option<T>: Debug, Option<B>: Debug,
{
    pub fn new() -> Self {
        unimplemented!()
    }
}

impl<T: From<i32>, B: From<i64>> Default for Foo<T, B>
where
    Option<T>: Debug, Option<B>: Debug,
{
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn new_function_with_parameters() {
        cov_mark::check!(new_function_with_parameters);
        check_not_applicable(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn $0new(value: ()) -> Self {
        Self { _inner: value }
    }
}
"#,
        );
    }

    #[test]
    fn other_function_than_new() {
        cov_mark::check!(other_function_than_new);
        check_not_applicable(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn a$0dd() -> Self {
        Self { _inner: () }
    }
}

"#,
        );
    }

    #[test]
    fn default_block_is_already_present() {
        cov_mark::check!(default_block_is_already_present);
        check_not_applicable(
            r#"
struct Example { _inner: () }

impl Example {
    pub fn n$0ew() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn standalone_new_function() {
        check_not_applicable(
            r#"
fn n$0ew() -> u32 {
    0
}
"#,
        );
    }

    #[test]
    fn multiple_struct_blocks() {
        check_pass(
            r#"
struct Example { _inner: () }
struct Test { value: u32 }

impl Example {
    pub fn new$0() -> Self {
        Self { _inner: () }
    }
}
"#,
            r#"
struct Example { _inner: () }
struct Test { value: u32 }

impl Example {
    pub fn new() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}
"#,
        );
    }

    #[test]
    fn when_struct_is_after_impl() {
        check_pass(
            r#"
impl Example {
    pub fn $0new() -> Self {
        Self { _inner: () }
    }
}

struct Example { _inner: () }
"#,
            r#"
impl Example {
    pub fn new() -> Self {
        Self { _inner: () }
    }
}

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}

struct Example { _inner: () }
"#,
        );
    }

    #[test]
    fn struct_in_module() {
        check_pass(
            r#"
mod test {
    struct Example { _inner: () }

    impl Example {
        pub fn n$0ew() -> Self {
            Self { _inner: () }
        }
    }
}
"#,
            r#"
mod test {
    struct Example { _inner: () }

    impl Example {
        pub fn new() -> Self {
            Self { _inner: () }
        }
    }

impl Default for Example {
    fn default() -> Self {
        Self::new()
    }
}
}
"#,
        );
    }

    #[test]
    fn struct_in_module_with_default() {
        cov_mark::check!(struct_in_module_with_default);
        check_not_applicable(
            r#"
mod test {
    struct Example { _inner: () }

    impl Example {
        pub fn n$0ew() -> Self {
            Self { _inner: () }
        }
    }

    impl Default for Example {
        fn default() -> Self {
            Self::new()
        }
    }
}
"#,
        );
    }

    fn check_pass(before: &str, after: &str) {
        let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
        check_assist(generate_default_from_new, before, after);
    }

    fn check_not_applicable(before: &str) {
        let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
        check_assist_not_applicable(generate_default_from_new, before);
    }
}
<|endoftext|>


<commit_before>use IResult;
use space::{skip_whitespace, word_break};

/// Parse a piece of punctuation like "+" or "+=".
///
/// See also `keyword!` for parsing keywords, which are subtly different from
/// punctuation.
///
/// - **Syntax:** `punct!("...")`
/// - **Output:** `&str`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// // Parse zero or more bangs.
/// named!(many_bangs -> Vec<&str>,
///     many0!(punct!("!"))
/// );
///
/// fn main() {
///     let input = "!! !";
///     let parsed = many_bangs(input).expect("bangs");
///     assert_eq!(parsed, ["!", "!", "!"]);
/// }
/// ```
#[macro_export]
macro_rules! punct {
    ($i:expr, $punct:expr) => {
        $crate::helper::punct($i, $punct)
    };
}

// Not public API.
#[doc(hidden)]
pub fn punct<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
    let input = skip_whitespace(input);
    if input.starts_with(token) {
        IResult::Done(&input[token.len()..], token)
    } else {
        IResult::Error
    }
}

/// Parse a keyword like "fn" or "struct".
///
/// See also `punct!` for parsing punctuation, which are subtly different from
/// keywords.
///
/// - **Syntax:** `keyword!("...")`
/// - **Output:** `&str`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use synom::IResult;
///
/// // Parse zero or more "bang" keywords.
/// named!(many_bangs -> Vec<&str>,
///     terminated!(
///         many0!(keyword!("bang")),
///         punct!(";")
///     )
/// );
///
/// fn main() {
///     let input = "bang bang bang;";
///     let parsed = many_bangs(input).expect("bangs");
///     assert_eq!(parsed, ["bang", "bang", "bang"]);
///
///     let input = "bangbang;";
///     let err = many_bangs(input);
///     assert_eq!(err, IResult::Error);
/// }
/// ```
#[macro_export]
macro_rules! keyword {
    ($i:expr, $keyword:expr) => {
        $crate::helper::keyword($i, $keyword)
    };
}

// Not public API.
#[doc(hidden)]
pub fn keyword<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
    match punct(input, token) {
        IResult::Done(rest, _) => {
            match word_break(rest) {
                IResult::Done(_, _) => IResult::Done(rest, token),
                IResult::Error => IResult::Error,
            }
        }
        IResult::Error => IResult::Error,
    }
}

/// Turn a failed parse into `None` and a successful parse into `Some`.
///
/// - **Syntax:** `option!(THING)`
/// - **Output:** `Option<THING>`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
///
/// fn main() {
///     let input = "!";
///     let parsed = maybe_bang(input).expect("maybe bang");
///     assert_eq!(parsed, Some("!"));
///
///     let input = "";
///     let parsed = maybe_bang(input).expect("maybe bang");
///     assert_eq!(parsed, None);
/// }
/// ```
#[macro_export]
macro_rules! option {
    ($i:expr, $submac:ident!( $($args:tt)* )) => {
        match $submac!($i, $($args)*) {
            $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)),
            $crate::IResult::Error => $crate::IResult::Done($i, None),
        }
    };

    ($i:expr, $f:expr) => {
        option!($i, call!($f));
    };
}

/// Turn a failed parse into an empty vector. The argument parser must itself
/// return a vector.
///
/// This is often more convenient than `option!(...)` when the argument produces
/// a vector.
///
/// - **Syntax:** `opt_vec!(THING)`
/// - **Output:** `THING`, which must be `Vec<T>`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::{Lifetime, Ty};
/// use syn::parse::{lifetime, ty};
///
/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
///     opt_vec!(do_parse!(
///         keyword!("for") >>
///         punct!("<") >>
///         lifetimes: terminated_list!(punct!(","), lifetime) >>
///         punct!(">") >>
///         (lifetimes)
///     )),
///     ty
/// ));
///
/// fn main() {
///     let input = "for<'a, 'b> fn(&'a A) -> &'b B";
///     let parsed = bound_lifetimes(input).expect("bound lifetimes");
///     assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
///     println!("{:?}", parsed);
///
///     let input = "From<String>";
///     let parsed = bound_lifetimes(input).expect("bound lifetimes");
///     assert!(parsed.0.is_empty());
///     println!("{:?}", parsed);
/// }
/// ```
#[macro_export]
macro_rules! opt_vec {
    ($i:expr, $submac:ident!( $($args:tt)* )) => {
        match $submac!($i, $($args)*) {
            $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
            $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()),
        }
    };
}

/// Parses nothing and always succeeds.
///
/// This can be useful as a fallthrough case in `alt!`.
///
/// - **Syntax:** `epsilon!()`
/// - **Output:** `()`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Mutability;
///
/// named!(mutability -> Mutability, alt!(
///     keyword!("mut") => { |_| Mutability::Mutable }
///     |
///     epsilon!() => { |_| Mutability::Immutable }
/// ));
///
/// fn main() {
///     let input = "mut";
///     let parsed = mutability(input).expect("mutability");
///     assert_eq!(parsed, Mutability::Mutable);
///
///     let input = "";
///     let parsed = mutability(input).expect("mutability");
///     assert_eq!(parsed, Mutability::Immutable);
/// }
/// ```
#[macro_export]
macro_rules! epsilon {
    ($i:expr,) => {
        $crate::IResult::Done($i, ())
    };
}

/// Run a parser, binding the result to a name, and then evaluating an
/// expression.
///
/// Discards the result of the expression and parser.
///
/// - **Syntax:** `tap!(NAME : THING => EXPR)`
/// - **Output:** `()`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::{Expr, ExprKind};
/// use syn::parse::expr;
///
/// named!(expr_with_arrow_call -> Expr, do_parse!(
///     mut e: expr >>
///     many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
///         e = Expr {
///             node: ExprKind::Call(Box::new(e), vec![arg.1]),
///             attrs: Vec::new(),
///         };
///     })) >>
///     (e)
/// ));
///
/// fn main() {
///     let input = "something => argument1 => argument2";
///
///     let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
///
///     println!("{:?}", parsed);
/// }
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! tap {
    ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
        match $submac!($i, $($args)*) {
            $crate::IResult::Done(i, o) => {
                let $name = o;
                $e;
                $crate::IResult::Done(i, ())
            }
            $crate::IResult::Error => $crate::IResult::Error,
        }
    };

    ($i:expr, $name:ident : $f:expr => $e:expr) => {
        tap!($i, $name: call!($f) => $e);
    };
}

/// Zero or more values separated by some separator. Does not allow a trailing
/// seperator.
///
/// The implementation requires that the first parameter is a `punct!` macro,
/// and the second is a named parser.
///
/// - **Syntax:** `separated_list!(punct!("..."), THING)`
/// - **Output:** `Vec<THING>`
///
/// You may also be looking for:
///
/// - `separated_nonempty_list!` - one or more values
/// - `terminated_list!` - zero or more, allows trailing separator
/// - `many0!` - zero or more, no separator
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Expr;
/// use syn::parse::expr;
///
/// named!(expr_list -> Vec<Expr>,
///     separated_list!(punct!(","), expr)
/// );
///
/// fn main() {
///     let input = "1 + 1, things, Construct { this: thing }";
///
///     let parsed = expr_list(input).expect("expr list");
///     assert_eq!(parsed.len(), 3);
/// }
/// ```
#[macro_export]
macro_rules! separated_list {
    ($i:expr, punct!($sep:expr), $f:expr) => {
        $crate::helper::separated_list($i, $sep, $f, false)
    };
}

/// Zero or more values separated by some separator. A trailing separator is
/// allowed.
///
/// The implementation requires that the first parameter is a `punct!` macro,
/// and the second is a named parser.
///
/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
/// - **Output:** `Vec<THING>`
///
/// You may also be looking for:
///
/// - `separated_list!` - zero or more, allows trailing separator
/// - `separated_nonempty_list!` - one or more values
/// - `many0!` - zero or more, no separator
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Expr;
/// use syn::parse::expr;
///
/// named!(expr_list -> Vec<Expr>,
///     terminated_list!(punct!(","), expr)
/// );
///
/// fn main() {
///     let input = "1 + 1, things, Construct { this: thing },";
///
///     let parsed = expr_list(input).expect("expr list");
///     assert_eq!(parsed.len(), 3);
/// }
/// ```
#[macro_export]
macro_rules! terminated_list {
    ($i:expr, punct!($sep:expr), $f:expr) => {
        $crate::helper::separated_list($i, $sep, $f, true)
    };
}

// Not public API.
#[doc(hidden)]
pub fn separated_list<'a, T>(mut input: &'a str,
                             sep: &'static str,
                             f: fn(&'a str) -> IResult<&'a str, T>,
                             terminated: bool)
                             -> IResult<&'a str, Vec<T>> {
    let mut res = Vec::new();

    // get the first element
    match f(input) {
        IResult::Error => IResult::Done(input, Vec::new()),
        IResult::Done(i, o) => {
            if i.len() == input.len() {
                IResult::Error
            } else {
                res.push(o);
                input = i;

                // get the separator first
                while let IResult::Done(i2, _) = punct(input, sep) {
                    if i2.len() == input.len() {
                        break;
                    }

                    // get the element next
                    if let IResult::Done(i3, o3) = f(i2) {
                        if i3.len() == i2.len() {
                            break;
                        }
                        res.push(o3);
                        input = i3;
                    } else {
                        break;
                    }
                }
                if terminated {
                    if let IResult::Done(after, _) = punct(input, sep) {
                        input = after;
                    }
                }
                IResult::Done(input, res)
            }
        }
    }
}
<commit_msg>Separated/terminated_list for more flexible arguments<commit_after>use IResult;
use space::{skip_whitespace, word_break};

/// Parse a piece of punctuation like "+" or "+=".
///
/// See also `keyword!` for parsing keywords, which are subtly different from
/// punctuation.
///
/// - **Syntax:** `punct!("...")`
/// - **Output:** `&str`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// // Parse zero or more bangs.
/// named!(many_bangs -> Vec<&str>,
///     many0!(punct!("!"))
/// );
///
/// fn main() {
///     let input = "!! !";
///     let parsed = many_bangs(input).expect("bangs");
///     assert_eq!(parsed, ["!", "!", "!"]);
/// }
/// ```
#[macro_export]
macro_rules! punct {
    ($i:expr, $punct:expr) => {
        $crate::helper::punct($i, $punct)
    };
}

// Not public API.
#[doc(hidden)]
pub fn punct<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
    let input = skip_whitespace(input);
    if input.starts_with(token) {
        IResult::Done(&input[token.len()..], token)
    } else {
        IResult::Error
    }
}

/// Parse a keyword like "fn" or "struct".
///
/// See also `punct!` for parsing punctuation, which are subtly different from
/// keywords.
///
/// - **Syntax:** `keyword!("...")`
/// - **Output:** `&str`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use synom::IResult;
///
/// // Parse zero or more "bang" keywords.
/// named!(many_bangs -> Vec<&str>,
///     terminated!(
///         many0!(keyword!("bang")),
///         punct!(";")
///     )
/// );
///
/// fn main() {
///     let input = "bang bang bang;";
///     let parsed = many_bangs(input).expect("bangs");
///     assert_eq!(parsed, ["bang", "bang", "bang"]);
///
///     let input = "bangbang;";
///     let err = many_bangs(input);
///     assert_eq!(err, IResult::Error);
/// }
/// ```
#[macro_export]
macro_rules! keyword {
    ($i:expr, $keyword:expr) => {
        $crate::helper::keyword($i, $keyword)
    };
}

// Not public API.
#[doc(hidden)]
pub fn keyword<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
    match punct(input, token) {
        IResult::Done(rest, _) => {
            match word_break(rest) {
                IResult::Done(_, _) => IResult::Done(rest, token),
                IResult::Error => IResult::Error,
            }
        }
        IResult::Error => IResult::Error,
    }
}

/// Turn a failed parse into `None` and a successful parse into `Some`.
///
/// - **Syntax:** `option!(THING)`
/// - **Output:** `Option<THING>`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
///
/// fn main() {
///     let input = "!";
///     let parsed = maybe_bang(input).expect("maybe bang");
///     assert_eq!(parsed, Some("!"));
///
///     let input = "";
///     let parsed = maybe_bang(input).expect("maybe bang");
///     assert_eq!(parsed, None);
/// }
/// ```
#[macro_export]
macro_rules! option {
    ($i:expr, $submac:ident!( $($args:tt)* )) => {
        match $submac!($i, $($args)*) {
            $crate::IResult::Done(i, o) => $crate::IResult::Done(i, Some(o)),
            $crate::IResult::Error => $crate::IResult::Done($i, None),
        }
    };

    ($i:expr, $f:expr) => {
        option!($i, call!($f));
    };
}

/// Turn a failed parse into an empty vector. The argument parser must itself
/// return a vector.
///
/// This is often more convenient than `option!(...)` when the argument produces
/// a vector.
///
/// - **Syntax:** `opt_vec!(THING)`
/// - **Output:** `THING`, which must be `Vec<T>`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::{Lifetime, Ty};
/// use syn::parse::{lifetime, ty};
///
/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
///     opt_vec!(do_parse!(
///         keyword!("for") >>
///         punct!("<") >>
///         lifetimes: terminated_list!(punct!(","), lifetime) >>
///         punct!(">") >>
///         (lifetimes)
///     )),
///     ty
/// ));
///
/// fn main() {
///     let input = "for<'a, 'b> fn(&'a A) -> &'b B";
///     let parsed = bound_lifetimes(input).expect("bound lifetimes");
///     assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
///     println!("{:?}", parsed);
///
///     let input = "From<String>";
///     let parsed = bound_lifetimes(input).expect("bound lifetimes");
///     assert!(parsed.0.is_empty());
///     println!("{:?}", parsed);
/// }
/// ```
#[macro_export]
macro_rules! opt_vec {
    ($i:expr, $submac:ident!( $($args:tt)* )) => {
        match $submac!($i, $($args)*) {
            $crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
            $crate::IResult::Error => $crate::IResult::Done($i, Vec::new()),
        }
    };
}

/// Parses nothing and always succeeds.
///
/// This can be useful as a fallthrough case in `alt!`.
///
/// - **Syntax:** `epsilon!()`
/// - **Output:** `()`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Mutability;
///
/// named!(mutability -> Mutability, alt!(
///     keyword!("mut") => { |_| Mutability::Mutable }
///     |
///     epsilon!() => { |_| Mutability::Immutable }
/// ));
///
/// fn main() {
///     let input = "mut";
///     let parsed = mutability(input).expect("mutability");
///     assert_eq!(parsed, Mutability::Mutable);
///
///     let input = "";
///     let parsed = mutability(input).expect("mutability");
///     assert_eq!(parsed, Mutability::Immutable);
/// }
/// ```
#[macro_export]
macro_rules! epsilon {
    ($i:expr,) => {
        $crate::IResult::Done($i, ())
    };
}

/// Run a parser, binding the result to a name, and then evaluating an
/// expression.
///
/// Discards the result of the expression and parser.
///
/// - **Syntax:** `tap!(NAME : THING => EXPR)`
/// - **Output:** `()`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::{Expr, ExprKind};
/// use syn::parse::expr;
///
/// named!(expr_with_arrow_call -> Expr, do_parse!(
///     mut e: expr >>
///     many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
///         e = Expr {
///             node: ExprKind::Call(Box::new(e), vec![arg.1]),
///             attrs: Vec::new(),
///         };
///     })) >>
///     (e)
/// ));
///
/// fn main() {
///     let input = "something => argument1 => argument2";
///
///     let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
///
///     println!("{:?}", parsed);
/// }
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! tap {
    ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
        match $submac!($i, $($args)*) {
            $crate::IResult::Done(i, o) => {
                let $name = o;
                $e;
                $crate::IResult::Done(i, ())
            }
            $crate::IResult::Error => $crate::IResult::Error,
        }
    };

    ($i:expr, $name:ident : $f:expr => $e:expr) => {
        tap!($i, $name: call!($f) => $e);
    };
}

/// Zero or more values separated by some separator. Does not allow a trailing
/// seperator.
///
/// - **Syntax:** `separated_list!(punct!("..."), THING)`
/// - **Output:** `Vec<THING>`
///
/// You may also be looking for:
///
/// - `separated_nonempty_list!` - one or more values
/// - `terminated_list!` - zero or more, allows trailing separator
/// - `many0!` - zero or more, no separator
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Expr;
/// use syn::parse::expr;
///
/// named!(expr_list -> Vec<Expr>,
///     separated_list!(punct!(","), expr)
/// );
///
/// fn main() {
///     let input = "1 + 1, things, Construct { this: thing }";
///
///     let parsed = expr_list(input).expect("expr list");
///     assert_eq!(parsed.len(), 3);
/// }
/// ```
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Ident;
/// use syn::parse::ident;
///
/// named!(run_on -> Vec<Ident>,
///     terminated!(
///         separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
///         punct!("...")
///     )
/// );
///
/// fn main() {
///     let input = "$expr and $ident and $pat ...";
///
///     let parsed = run_on(input).expect("run-on sentence");
///     assert_eq!(parsed.len(), 3);
///     assert_eq!(parsed[0], "expr");
///     assert_eq!(parsed[1], "ident");
///     assert_eq!(parsed[2], "pat");
/// }
/// ```
#[macro_export]
macro_rules! separated_list {
    // Try to use this branch if possible - makes a difference in compile time.
    ($i:expr, punct!($sep:expr), $f:expr) => {
        $crate::helper::separated_list($i, $sep, $f, false)
    };

    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
        let mut res = ::std::vec::Vec::new();
        let mut input = $i;

        // get the first element
        match $fmac!(input, $($fargs)*) {
            $crate::IResult::Error => $crate::IResult::Done(input, res),
            $crate::IResult::Done(i, o) => {
                if i.len() == input.len() {
                    $crate::IResult::Error
                } else {
                    res.push(o);
                    input = i;

                    // get the separator first
                    while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
                        if i2.len() == input.len() {
                            break;
                        }

                        // get the element next
                        if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
                            if i3.len() == i2.len() {
                                break;
                            }
                            res.push(o3);
                            input = i3;
                        } else {
                            break;
                        }
                    }
                    $crate::IResult::Done(input, res)
                }
            }
        }
    }};

    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
        separated_list!($i, $sepmac!($(separgs)*), call!($f))
    };

    ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
        separated_list!($i, call!($sep), $fmac!($(fargs)*))
    };

    ($i:expr, $sep:expr, $f:expr) => {
        separated_list!($i, call!($sep), call!($f))
    };
}

/// Zero or more values separated by some separator. A trailing separator is
/// allowed.
///
/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
/// - **Output:** `Vec<THING>`
///
/// You may also be looking for:
///
/// - `separated_list!` - zero or more, allows trailing separator
/// - `separated_nonempty_list!` - one or more values
/// - `many0!` - zero or more, no separator
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Expr;
/// use syn::parse::expr;
///
/// named!(expr_list -> Vec<Expr>,
///     terminated_list!(punct!(","), expr)
/// );
///
/// fn main() {
///     let input = "1 + 1, things, Construct { this: thing },";
///
///     let parsed = expr_list(input).expect("expr list");
///     assert_eq!(parsed.len(), 3);
/// }
/// ```
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
/// use syn::Ident;
/// use syn::parse::ident;
///
/// named!(run_on -> Vec<Ident>,
///     terminated!(
///         terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
///         punct!("...")
///     )
/// );
///
/// fn main() {
///     let input = "$expr and $ident and $pat and ...";
///
///     let parsed = run_on(input).expect("run-on sentence");
///     assert_eq!(parsed.len(), 3);
///     assert_eq!(parsed[0], "expr");
///     assert_eq!(parsed[1], "ident");
///     assert_eq!(parsed[2], "pat");
/// }
/// ```
#[macro_export]
macro_rules! terminated_list {
    // Try to use this branch if possible - makes a difference in compile time.
    ($i:expr, punct!($sep:expr), $f:ident) => {
        $crate::helper::separated_list($i, $sep, $f, true)
    };

    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
        let mut res = ::std::vec::Vec::new();
        let mut input = $i;

        // get the first element
        match $fmac!(input, $($fargs)*) {
            $crate::IResult::Error => $crate::IResult::Done(input, res),
            $crate::IResult::Done(i, o) => {
                if i.len() == input.len() {
                    $crate::IResult::Error
                } else {
                    res.push(o);
                    input = i;

                    // get the separator first
                    while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
                        if i2.len() == input.len() {
                            break;
                        }

                        // get the element next
                        if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
                            if i3.len() == i2.len() {
                                break;
                            }
                            res.push(o3);
                            input = i3;
                        } else {
                            break;
                        }
                    }
                    if let $crate::IResult::Done(after, _) = $sepmac!(input, $($separgs)*) {
                        input = after;
                    }
                    $crate::IResult::Done(input, res)
                }
            }
        }
    }};

    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
        terminated_list!($i, $sepmac!($(separgs)*), call!($f))
    };

    ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
        terminated_list!($i, call!($sep), $fmac!($(fargs)*))
    };

    ($i:expr, $sep:expr, $f:expr) => {
        terminated_list!($i, call!($sep), call!($f))
    };
}

// Not public API.
#[doc(hidden)]
pub fn separated_list<'a, T>(mut input: &'a str,
                             sep: &'static str,
                             f: fn(&'a str) -> IResult<&'a str, T>,
                             terminated: bool)
                             -> IResult<&'a str, Vec<T>> {
    let mut res = Vec::new();

    // get the first element
    match f(input) {
        IResult::Error => IResult::Done(input, res),
        IResult::Done(i, o) => {
            if i.len() == input.len() {
                IResult::Error
            } else {
                res.push(o);
                input = i;

                // get the separator first
                while let IResult::Done(i2, _) = punct(input, sep) {
                    if i2.len() == input.len() {
                        break;
                    }

                    // get the element next
                    if let IResult::Done(i3, o3) = f(i2) {
                        if i3.len() == i2.len() {
                            break;
                        }
                        res.push(o3);
                        input = i3;
                    } else {
                        break;
                    }
                }
                if terminated {
                    if let IResult::Done(after, _) = punct(input, sep) {
                        input = after;
                    }
                }
                IResult::Done(input, res)
            }
        }
    }
}
<|endoftext|>