function by_expression($expression)
 {
     // build a queue of expression tokens
     $tokens = self::tokenise($expression);
     $matched_tokens = array();
     foreach ($tokens as $key => $token) {
         // try to match token type (order matters)
         if (IntervalFilter::match($token) === true) {
             $matched_tokens[] = new IntervalFilter();
         } elseif (CommandFilter::match($token) === true) {
             $matched_token[] = new CommandFilter();
         } elseif (DateFilter::match($token) === true) {
             $matched_tokens[] = new DateFilter();
         } elseif (RangeFilter::match($token) === true) {
             $matched_tokens[] = new RangeFilter();
         } elseif (WordFilter::match($token) === true) {
             $matched_tokens[] = new WordFilter();
         }
     }
     $last_token = $matched_tokens[$key];
     if ($last_token instanceof DateTokenFilter) {
         $last_token->group_dates(true);
     }
     $tasks = $this->_data->tasks;
     $token_filter = new TokenFilter();
     foreach ($matched_tokens as $token_filter) {
         $token_filter->filter_by($tasks);
     }
     // TODO: sort and group?
     return $tasks;
 }