Skip to content

feat: Wrapper macros for grammar definition + folds #22

Description

@impact-basin

Firstly - great package, thank you for all your hard work!

I have been wrapping the PikaParser.jl workflow in a few macros, and wanted to float them for your consideration.

The two macros are in the gist here -- @pika_grammar produces a callable function which parses the input, and @pika_evaluate provides syntactic sugar for fold-function definitions.

I think an example is best - a simple calculator with whitespace (mind I don't write many PEG grammars, so you will probably find a better way of doing this!)

The grammar is defined with this macro like so:

calc_grammar = @pika_grammar :top begin
    :ws     => many(satisfy(isspace)),
    :digit  => satisfy(isdigit),
    :number => some(:digit),
    :plus   => seq(:expr, :ws, token('+'), :ws, :expr, :ws),
    :minus  => seq(:expr, :ws, token('-'), :ws, :expr, :ws),
    :times  => seq(:expr, :ws, token('*'), :ws, :expr, :ws),
    :divby  => seq(:expr, :ws, token('/'), :ws, :expr, :ws),
    :paren  => seq(:ws, token('('), :ws, :expr, :ws, token(')'), :ws),
    :expr   => first(:paren, :times, :divby, :plus, :minus, :number),
    :top    => seq(:expr)
end

(Note that the @pika_grammar macro traverses the syntax tree, and replaces PikaParser.jl library symbols with their qualified names, e.g. seq => PikaParser.seq).

Now we write the evaluator with some additional output:

calc_eval = @pika_evaluate :top m v begin
    :number => parse(Int, m.view)
    :plus   => begin
        println("Parsing plus: $(m.view) => $(v[1]) + $(v[5])")
        v[1] + v[5]
    end
    :minus  => begin
        println("Parsing minus: $(m.view) => $(v[1]) - $(v[5])")
        v[1] - v[5]
    end
    :times => begin
        println("Parsing times: $(m.view) => $(v[1]) * $(v[5])")
        v[1] * v[5]
    end
    :divby => begin
        println("Parsing divby: $(m.view) => $(v[1]) / $(v[5])")
        v[1] / v[5]
    end
    :expr  => v[1]
    :paren => v[4]
    :top   => begin
        println("Parsing top: $(m.view) => $(v[1])")
        v[1]
    end
end

Finally, we parse according to the grammar and evaluate:

julia> calc_grammar("12 + ( 34* 56)") |> calc_eval
Parsing times: 34* 56 => 34 * 56
Parsing plus: 12 + ( 34* 56) => 12 + 1904
Parsing top: 12 + ( 34* 56) => 1916
1916

Please let me know if I can be of any help - whether there are additional aspects to consider, or whether I should open a pull request.

And once again, thanks for the great parsing library!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions