package Spp;

use 5.012;
no warnings 'experimental';

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT =
  qw(spp_repl match_text grammar_to_ast lint_grammar parse_text spp_to_spp);

our $VERSION = '2.02';
use Spp::Builtin;
use Spp::Tools;
use Spp::Ast;
use Spp::Grammar;
use Spp::Cursor;
use Spp::MatchRule;
use Spp::OptAst;
use Spp::LintAst;
use Spp::ToSpp;

sub spp_repl {
  my $spp_ast   = get_spp_ast();
  my $estr_ast  = to_ejson($spp_ast);
  my $table     = ast_to_table($estr_ast);
  my $door_rule = $table->{'door'};
  say 'This is Spp REPL, type enter to exit.';
  while (1) {
    print '>> ';
    my $line = <STDIN>;
    exit() if ord($line) == 10;
    my $cursor = new_cursor($line, $table);
    my $match = match_spp_rule($cursor, $door_rule);
    if (is_false($match)) { say fail_report($cursor) }
    else {
      say '.. ', see_ast($match);
      my $ast = opt_spp_ast($match);
      say '.. ', see_ast($ast);
    }
  }
}

sub match_text {
  my ($ast, $text) = @_;
  my $table  = ast_to_table($ast);
  my $rule   = $table->{'door'};
  my $cursor = new_cursor($text, $table);
  my $match  = match_spp_rule($cursor, $rule);
  if (is_false($match)) {
    my $report = fail_report($cursor);
    return $report, 0;
  }
  return $match, 1;
}

sub grammar_to_ast {
  my $grammar  = shift;
  my $spp_ast  = get_spp_ast();
  my $estr_ast = to_ejson($spp_ast);
  my ($match, $ok) = match_text($estr_ast, $grammar);
  if ($ok) {
    my $ast = opt_spp_ast($match);
    lint_spp_ast($ast);
    return $ast;
  }
  else { error($match) }
}

sub lint_grammar {
  my $grammar = shift;
  my $ast     = grammar_to_ast($grammar);
  lint_spp_ast($ast);
  return True;
}

sub parse_text {
  my ($grammar, $text) = @_;
  my $ast = grammar_to_ast($grammar);
  lint_spp_ast($ast);
  my ($match, $ok) = match_text($ast, $text);
  if   ($ok) { return $match }
  else       { error($match) }
}

sub spp_to_spp {
  my $str     = shift;
  my $spp_ast = to_ejson(get_spp_ast());
  my ($match, $ok) = match_text($spp_ast, $str);
  if ($ok) {
    my $ast = opt_spp_ast($match);
    return ast_to_spp($ast);
  }
}
1;
