#!/usr/bin/env raku grammar FileGrammar { # The top-level file is a list of statements token TOP { ^ * %% \v* $ } # A line is either a list of keyword-payload or scope token line { | } # A statement is a simple keyword-payload mapping token statement { \s } # The set of simple key-value keywords token keyword { < ANCHOR BG COUNT ENV MODE SPACING > } # A simple payload token payload { \S+ %% \h* } # A scope is a scope-word + list of scope-lines token scope { * } # The set of scope-opening keywords token scope-word { < INPUTS OUTPUTS > } # A scope line is either a simple payload or a full statement token scope-line { \v+ \h \h [ | ] } } class Actions { method TOP($/) { make $>>.made } method line($/) { make .made with $ || $; } method statement($/) { make { Keyword => $.made, Payload => $.made } } method scope($/) { make { Keyword => $.made, Payload => $>>.made } } method scope-line($/) { make $ ?? $.made !! { Payload => $.made } } method keyword($/) { make ~$/ } method payload($/) { make ~$/ } method scope-word($/) { make ~$/ } } sub MAIN($file, Bool :$verbose) { my $input = slurp $file; say "Parsing input: $input" if $verbose; my @parse = FileGrammar.parse($input, actions => Actions.new).made; for @parse -> %line { say %line } }