Revision history for Spp

0.01    2015-11-1
        First version, released on an unsuspecting world.

0.02    2015-11-2
        to-rule use JSON function encode_json.

0.03    2015-12-2
        repl spp is interface of spp

0.04    2017-08-14
        Spp as Parser of grammar, not entire language like lisp

1.01    2017-08-18
        Spp could use as app to test

1.02    2017-8-21
        fix bug could not install. readme add some content.

1.03    2017-8-29
        fix some bug, add string and str to Str

1.04    2017-8-29
        rewrite repl and Spp.pm

1.05    2017-8-29
        delete two no use function, is_str_atom() rename is_str()

1.06    2017-8-31
        name match atom add pos info [line,from,len]

1.07    2017-8-31
        add mode to control debug and get pos
        mode = 0 (default) not debug and pos
        mode = 1 debug matching
        mode = 2 get pos information of Token

1.08    2017-9-1
        match if return false, then set max match report str return.
        ['false', max_report]

1.09    2017-9-2
        to_end() set to Spp::Tools, could share with Mylisp.pm
        add spp_to_spp to test Spp could transfer itself to itself.
        add three test case.

1.10    2017-9-3
        Spp::Tools rename => Spp::Builtin
        would define function register Stable could have type sign
        Do not need re-write with Mylisp. Must implement by other
        language.

1.11    2017-9-4
        add get_matcher() match_matcher()
        could use 'Int Int+' match 'Int Int'
        type validation use type signature to check argument type gather.
        'Str Any' could match 'Str Str'

1.12    2017-9-4
        Spp.pm export grammar_to_ast() ast_to_parser() then other language
        Could backup ast to Json, then load it when use. also could load
        from grammar_text. but more quickly.

1.13    2017-9-4
        write_file would send a message to output when write ok!
        perl-tidy all source code.

1.14    2017-9-4
        spp.pl add not argument help.

1.15    2017-9-5
        match() from Match.pm to Spp.pm, could export to everyone.
        delete :file specification get-file-text test.
        delete _match_rule debug func().
        Spp.pm is transfer with Spp.spp
        Match.pm fix some bug. match-not() do not save cache correctly.
        rename: is_str() => is_atom_str(), is_perl_str => is_str
        
1.16    2017-9-7
        Spp/Match.pm match_sym() add:
        ----------------------
        if (is_false($match)) { return $match }
        my $token_name = rest($name);
        my $char = first($token_name);
        if (is_char_upper($char)) { return [$token_name, $match] }
        if ($char eq '_') { return ['true'] }
        return $match;
        ----------------------
        could named capture string, or reject it!
        LintParser.pm => LintAst.pm
        Lint should do Ast.

1.17    Spp.pm export func add: lint_spp_ast() spp_ast_to_table()
        delete get_matcher() match_matcher().

1.18    Use Perlcritic check all code, fix some small bug.

1.19    puts IsChar.pm to Builtin.pm
        split some function could implement with Builtin
        to Core.pm

1.20    combin all Builtin.pm function of Mylisp to Spp
        add core to it, is_atoms

1.21    die() => error, Match all error could report pos.

1.22    all branch is longest match branch, if two branch
        match same length, then first is return.