#!/usr/bin/env perl6

use v6.d;

use FunctionalParsers::EBNF;

my %*SUB-MAIN-OPTS = :named-anywhere;


#| Generates parser code for a given EBNF grammar.
multi MAIN(
        $ebnf,                                                        #= EBNF text.
        Str :t(:$actions) is copy = 'Raku::Class',                    #= Actions ('t' for 'target'.)
        Str :n(:$parser-name) is copy = 'MyParser',                   #= Parser name.
        Str :p(:$rule-name-prefix) is copy = 'p',                     #= Rule names prefix.
        Str :m(:$rule-name-modifier) is copy = 'WhateverCode',        #= Rule names modifier.
        Str :s(:$style) is copy = 'Whatever',                         #= EBNF style, one of 'G4', 'Inverted', 'Standard', 'Relaxed', or 'Whatever'.
           ) {

    my @knownModifiers = <{$_.tc} {$_.uc} {$_.lc} {$_}>;
    my &rule-name-modifier;
    if $rule-name-modifier eq 'WhateverCode' {
        &rule-name-modifier = {$_.uc}
    } elsif $rule-name-modifier.subts(/\s/,'') ∈ @knownModifiers {
        use MONKEY-SEE-NO-EVAL;
        &rule-name-modifier = EVAL $rule-name-modifier;
    } else {
        die "Only rule name modifier code is allowed to be WhateverCode or one of {@knownModifiers.map({ "'$_'"}).join(', ')}.";
    }

    $actions = do given $actions.lc {
        when $_ ∈ <raku perl6 code> { 'Raku::Code' }
        when 'class' { 'Raku::Class' }
        when 'grammar' { 'Raku::Grammar' }
        when 'wl' { 'WL::Code' }
        when 'java' { 'Java::FuncJ' }
        when 'mermaid' { 'MermaidJS::Graph' }
        default { $actions }
    }

    my $res = fp-ebnf-parse($ebnf, <CODE>, :$actions, :$parser-name, :$rule-name-prefix, :&rule-name-modifier, :$style);

    if $res.head.head {
        say $res;
    } else {
        say $res.head.tail;
    }
}

#| Generates parser code for a given EBNF grammar file.
multi MAIN(
        $file where *.IO.e,                                           #= EBNF file name.
        Str :t(:$actions) is copy = 'Raku::Class',                    #= Actions ('t' for 'target'.)
        Str :n(:$parser-name) is copy = 'MyParser',                   #= Parser name.
        Str :p(:$rule-name-prefix) is copy = 'p',                     #= Rule names prefix.
        Str :m(:$rule-name-modifier) is copy = 'WhateverCode',        #= Rule names modifier.
        Str :s(:$style) is copy = 'Whatever',                         #= EBNF style, one of 'G4', 'Inverted', 'Standard', 'Relaxed', or 'Whatever'.
           ) {
    return MAIN(slurp($file), :$actions, :$parser-name, :$rule-name-prefix, :$rule-name-modifier, :$style);
}