anchor.diff:      return new TrimmingParser(this, trimmer == null ? whitespace() : trimmer);
     }
   
  +  /**
  +   * Returns a parser that succeeds only if the receiver consumes the complete
  +   * input, otherwise return a failure with the optional [message].
  +   *
  +   * For example, the parser [:letter().end():] succeeds on the input [:'a':]
  +   * and fails on [:'ab':]. In contrast the parser [:letter():] alone would
  +   * succeed on both inputs, but not consume everything for the second input.
  +   */
     Parser end([String message]) {
       return new EndOfInputParser(this, message == null
           ? 'end of input expected' : message);
  
positive.code:     return this.map((List list) => indexes.map((index) => list[index]));
    }
  
    Parser separatedBy(Parser separator) {
      return new SequenceParser([this, new SequenceParser([separator, this]).star()]).map((List list) {
        var result = new List();
        result.add(list[0]);
        list[1].forEach((each) => result.addAll(each));
        return result;
      });
    }
    Parser withoutSeparators() {
      return map((List list) {
        var result = new List();
        for (var i = 0; i < list.length; i += 2) {
          result.add(list[i]);
        }
        return result;
      });
  
negative.code:    */
    Parser neg([String message]) => not(message).seq(any()).pick(1);
  
    /**
     * Returns a parser that discards the result of the receiver, and returns
     * a sub-string of the consumed elements in the string/list being parsed.
  