How can I write an alias of Raku regexes?
Asked Answered
H

1

10

I wrote a grammar like this:

grammar StatementFormat {
    token TOP { (<plain> | '%' <placeholder>)* }

    token plain { <-[%]> }

    token placeholder {
        | <verb>
        | <noun>
        | <adverb>
    }

    token verb {
        'v'
        {
            # some actions
        }
    }

    token noun {
        'n'
        {
            # some actions
        }
    }

    token adverb {
        'a'
        {
            # some actions
        }
    }
}

So I could use it to parse strings like "someone %v %n %a".

However, I found there were so many usages like "%v %n %a", I'd like to give it an alias, say, "%b" such that parsing "someone %b" is equivalent to parsing "someone %v %n %a".

So is there a way to do that?

Of course, token alias { 'b' { ... } } can do that. But in that way I need to repeat that action code. I am wondering if there exists a simpler way.

Haemophiliac answered 15/7, 2020 at 11:56 Comment(0)
M
11

So, there is one obvious way, which is to simply put the code for the actions into subroutines and then in the b alias, call them:

sub verb-action($/) { }
sub noun-action($/) { }
sub adverb-action($/) { }

grammar StatementFormat {
    # rest goes here

    token verb {
        'v'
        { verb-action($/) }
    }

    token noun {
        'n'
        { noun-action($/) }
    }

    token adverb {
        'a'
        { adverb-action($/) }
    }

    token alias {
        'b'
        {
            verb-action($/);
            noun-action($/);
            adverb-action($/);
        }
    }
}

But where'd be the fun of that?

Instead, I'd recommend using the built-in action object feature of grammars.

It goes like this: you have a separate class with the actions as methods, with the same name as the grammar actions:

class StatementFormatActions {
    method verb($/) { ... }
    method noun($/) { ... }
    method adverb($/) { ... }

}

And when you call parse, you pass an instance of that action class along:

StatementFormat.parse($string, :actions(StatementFormatActions.new));

Then when you introduce the alias token, you can also introduce an alias method:

method alias($/) {
    self.verb($/);
    self.noun($/);
    self.adverb($/);
}

Inside the actions you can also call make or $/.make(...) to attach the result of your actions to the match object (then available in$/.made) to populate an AST from your parse tree.

(You might also like my book on grammars which has several examples and more in-depth explanations. Sorry for the plug, could not resist).

Mossman answered 15/7, 2020 at 14:23 Comment(2)
Thank you, it works. Besides, I am wondering if it's possible to modify the string during parsing. If I can replace the %b with %v %n %a, then it's quite easy to implement the alias. But it seems raku does not support this feature. Do you think it useful?Haemophiliac
@Haemophiliac strings are immutable in Raku, so you cannot modify it while parsing.Mossman

© 2022 - 2024 — McMap. All rights reserved.