Skip to content

Commit

Permalink
GH #23: Add preliminary support for extending the grammar:
Browse files Browse the repository at this point in the history
To add new lexemes:

    Guacamole->add_lexemes(
        [ 'name'         => 'value' ],
        [ 'another_name' => 'another_value' ],
    );

This creates entries of:

    name         ~ 'value'
    another_name ~ 'another_value'

This doesn't even handle escaping "'" yet, so figure it out yourself. :)

To add new keywords:

    Guacamole->add_keyword(
        'MyNewKeyword',
        'unary',          # or: nullary, assign, list
        'my_new_keyword', # whatever name it has
        [ 'OpKeywordMyNewKeyword BlockNonEmpty' ],
    );

This will create the appropriate lexemes (prefixing your keyword with
'OpKeyword' which you can use in the rules) and the rules you provide.

Here is a small example of writing a try/catch implementation:

Example of adding support for Try::Tiny's try/catch:

Guacamole->add_keyword(
    'Catch',
    'unary',
    'catch',
    [ 'OpKeywordCatch BlockNonEmpty' ]
);

Guacamole->add_keyword(
    'Try',
    'list',
    'try',
    [
        'OpKeywordTry BlockNonEmpty OpKeywordCatchExpr',
        'OpKeywordTry BlockNonEmpty',
    ],
);

This, of course, does not check whether `Try::Tiny` is in effect.

Support "finally {}" is about the same with a few adjustments to
the different combinations ("try {} finally {}",
"try {} catch {} finally {}", etc.).
  • Loading branch information
xsawyerx committed May 30, 2022
1 parent 2426e8f commit 801bcb6
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
39 changes: 39 additions & 0 deletions lib/Guacamole.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2102,6 +2102,45 @@ whitespace ~ [\s]+
};
sub add_lexemes {
my ( $class, @items ) = @_;
foreach my $item (@items) {
ref $item eq 'ARRAY'
or die 'add_lexemes( [NAME, VALUE], [NAME, VALUE] )';
$grammar_source .= "$item->[0] ~ '$item->[1]'\n";
}
}
sub add_keyword {
my ( $class, $name, $type, $value, $rules_arrayref ) = @_;
$name && $type && $value && $rules_arrayref
or die 'add_keyword( NAME_STR, TYPE_STR, VALUE_STR, RULES_ARRAYREF )';
ref $rules_arrayref eq 'ARRAY'
or die 'rules must be an arrayref';
$type =~ /^( nullary | unary | assign | list )$/xms
or die 'Type must be "nullary", "unary", "assign", or "list"';
grep !length, $name, $type, $value
and die 'name, type, value must have length';
$name = ucfirst $name; # Just in case
$type = ucfirst $type;
my $rules_string = join "\n | ", $rules_arrayref->@*;
$grammar_source .= qq{
OpKeyword$name ~ '$value'
OpKeyword${name}Expr ::= $rules_string
:lexeme ~ OpKeyword${name} priority => 1
};
my $type_rule = "Op${type}KeywordExpr";
$grammar_source =~ s{($type_rule\s+::=)}{$1 OpKeyword${name}Expr | }xms;
}
sub build_struct {
my ( $rec, $initial_valueref ) = @_;
Expand Down
24 changes: 24 additions & 0 deletions tools/expl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ use lib "$Bin/../lib";
use Guacamole;
use Guacamole::Dumper qw/dump_tree/;

# add_keyword will do the lexeme adding anyway
#Guacamole->add_lexemes(
# [ 'OpKeywordTry' => 'try' ],
# [ 'OpKeywordCatch' => 'catch' ],
#);

# Example of adding support for Try::Tiny's try/catch
#Guacamole->add_keyword(
# 'Catch',
# 'unary',
# 'catch',
# [ 'OpKeywordCatch BlockNonEmpty' ]
#);
#
#Guacamole->add_keyword(
# 'Try',
# 'list',
# 'try',
# [
# 'OpKeywordTry BlockNonEmpty OpKeywordCatchExpr',
# 'OpKeywordTry BlockNonEmpty',
# ],
#);

my $src = shift @ARGV;
foreach my $ast (Guacamole->parse($src)) {
print dump_tree($ast);
Expand Down

0 comments on commit 801bcb6

Please sign in to comment.