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.

1.23    parser() = [$door-rule, $table]
        return match, if-false report, othewise return true

1.24    move language related function to Builtin.pm and Spp.pl
        lint() not exported from Spp.pm
        delete all() of builtin.pm

1.25    add Flat() to assign two symbol, Match() would send
        rest to last symbol
        fix a bug of Expr, add Sub as action name.

1.26    2017-9-20
        split some not export function to spp.pl, 
        delete all not nesserary name with -spp, 
        add Push, Unshift, rename Append, could return
        array itself, add Chop(), add Match(), Flat(),
        match() => match_text()"

1.27    2017-9-20
        add Time::Piece module to bakup Ast.pm.2017-09-20
        rename grammar-to-ast() => spp-to-ast()
        rename grammar-to-parser() -> spp-to-parser()

1.28    parser is door + name-table
        put LintAst to Spp.pm so could call ast_to_parser
        directly.

1.29    2017-9-23
        add In Out Qstr Qint Int to match estr
        add Estr.pm for common interface for type language
        
2.0     2017-9-23
        is_false() is_true() use False and True
        is_atom_tillnot -> is_tillnot
        is_atom_look    => is_look