###
### Lexer.pm
###
### Originally from Higher-Order Perl by Mark Dominus, published by Morgan
### Kaufmann Publishers, Copyright 2005 by Elsevier Inc
###
### Ported to Perl6 by Dan Brook
###

## Chapter 8 section 1.1

sub Lexer::import { }

## XXX - is exported doesn't support args atm

## Chapter 8 section 1.3

sub tokens(Code *$input, Str *$label, Str $pattern, Code $maketoken?)
    is exported(:all) {
  ## XXX - slurpy magic doesn't work too well presently ...
  $maketoken := ({ [ $^tok_label, $^tok ] })
    if !defined $maketoken;
  my @tokens;
  my $buf = "";   # set to undef to when input is exhausted
  my $split := { (split rx:perl5/($pattern)/, $^str).map:{~$_} };
  return sub {
    while +@tokens == 0 && defined $buf {
      my $i = $input.();
      if $i.isa(Array) {
        my($sep, $tok) = $split.($buf);
        $tok = $maketoken.($tok, $label)
          if defined $tok;
        @tokens.push( ($sep, $tok, $i).grep:{ $_ ne "" } );
        $buf = "";
        last;
      }

      $buf ~= $i
        if defined $i;

      my @newtoks = $split.($buf);
      while +@newtoks > 2 
         || +@newtoks && !defined $i {

        @tokens.push( @newtoks.shift );
        @tokens.push( $maketoken.(@newtoks.shift, $label) )
                if +@newtoks;
      }

      $buf = [~] @newtoks;
      undefine $buf
        if !defined $i;

      @tokens .= grep:{ $_ ne "" };
    }
    # say "tokens looks like: {@tokens.perl}";
    return @tokens.shift;
  };
}


## Chapter 8 section 1.3

sub make_lexer (Code $lexer is rw, *@args) {
  ## XXX - Surely there's a more p6ish way of doing this?
  $lexer = tokens($lexer, [,] @$_)
    for @args;
  return $lexer;
}

1;
