anchor.diff:                  return result;
                 };
   
  -  Parser get str => (noneOf(_strSpecialChars + "\n").many1 ^
  -          (chars) => _transformString(chars.join())) |
  -      (oneOf(_strSpecialChars) ^ (chars) => _transformString(chars)) |
  -      (char("\n").notFollowedBy(spnl) ^ (_) => [new Str("\n")]);
  -
  -  Parser<List<Inline>> get inline => choice([
  +  Parser _strCache;
  +  Parser get str {
  +    if (_strCache == null) {
  +      _strCache = (noneOf(_strSpecialChars.join() + "\n").many1 ^
  +              (chars) => _transformString(chars.join())) |
  +          (oneOf(_strSpecialChars.join()) ^
  +              (chars) => _transformString(chars)) |
  +          (char("\n").notFollowedBy(spnl) ^ (_) => [new Str("\n")]);
  +    }
  +    return _strCache;
  +  }
  +
  +  Parser<List<Inline>> _inlineCache;
  +  Parser<List<Inline>> get inline {
  +    if (_inlineCache == null) {
  +      _inlineCache = choice([
           lineBreak,
           whitespace,
           escapedChar,
  
positive.code: 
          return success(result).run(s, position);
        });
  
    //
    // link and image
    //
  
    Parser linkWhitespace = (blankline > (whitespaceChar < skipSpaces)) |
        (whitespaceChar < skipSpaces);
    Parser get linkInline => (char('(') >
            (((linkWhitespace.maybe > linkInlineDestination) +
                    ((linkWhitespace > linkTitle).maybe < linkWhitespace.maybe)) ^
                (a, Option b) => new Target(a, b.asNullable))) <
  
negative.code:   // Links aux parsers
    //
  
    // Can't be static because of str
    Parser get _linkTextChoice => choice([
          whitespace,
          htmlEntity,
  