anchor.diff:  
     var lastMatch = null;
     var lastMatchStr = null;
  -  var reset = false;
   
     for(int i=0; i< str.length; i++){
       matchStr += str[i];
       if(lastMatch == null){
         ds = ds.map((_) => _.derive(str[i])).where((_) => !_.isReject);
  +      if(isExactMatch(ds)){
  +        dispatch(ds, matchStr);
   
  -      if(exactMatchDispatched(ds, matchStr)){
           //reset
           matchStr = '';
           ds = rules;
  
positive.code:     lastMatch.action(lastMatchStr);
  }
  
  bool exactMatchDispatched(List<Rule> rules, String matched){
    var matches = rules.where((_) => _.isMatch);
    if(matches.length > 1) throw "More that one match is not supported yet";
    if (matches.length == 1){
      matches.first.action(matched);
      return true;
    }
    return false;
  }
  
negative.code: 
  
  Rule keywordRule = new Rule(rx([or(['if', 'else'])]),
                         (_) => print(new Keyword(_)));
  Rule spacesRule = new Rule(rx([oneOrMore(' ')]), (_) => print('SPACE'));
  working_main() {
    var rules = [keywordRule, spacesRule];
    var ds = rules;
    var str = 'if    else  ';
  