From 9c6d432273964aa86e1387acc0971dc6afe8367d Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sat, 22 Nov 2025 22:49:16 +0100 Subject: [PATCH 1/8] feat: Add Raku grammar --- grammars/raku/README.md | 29 +++ grammars/raku/prql.rakumod | 319 ++++++++++++++++++++++++++ grammars/raku/t/arithmetics.rakutest | 29 +++ grammars/raku/t/arrays.rakutest | 45 ++++ grammars/raku/t/datetime.rakutest | 33 +++ grammars/raku/t/full_queries.rakutest | 30 +++ grammars/raku/t/identifiers.rakutest | 17 ++ grammars/raku/t/misc.rakutest | 129 +++++++++++ grammars/raku/t/numbers.rakutest | 41 ++++ grammars/raku/t/operators.rakutest | 45 ++++ grammars/raku/t/strings.rakutest | 49 ++++ grammars/raku/t/tuples.rakutest | 45 ++++ 12 files changed, 811 insertions(+) create mode 100644 grammars/raku/README.md create mode 100644 grammars/raku/prql.rakumod create mode 100644 grammars/raku/t/arithmetics.rakutest create mode 100644 grammars/raku/t/arrays.rakutest create mode 100644 grammars/raku/t/datetime.rakutest create mode 100644 grammars/raku/t/full_queries.rakutest create mode 100644 grammars/raku/t/identifiers.rakutest create mode 100644 grammars/raku/t/misc.rakutest create mode 100644 grammars/raku/t/numbers.rakutest create mode 100644 grammars/raku/t/operators.rakutest create mode 100644 grammars/raku/t/strings.rakutest create mode 100644 grammars/raku/t/tuples.rakutest diff --git a/grammars/raku/README.md b/grammars/raku/README.md new file mode 100644 index 000000000000..1d190b500e33 --- /dev/null +++ b/grammars/raku/README.md @@ -0,0 +1,29 @@ +# Raku grammar + +PRQL grammar for Raku. + +## Instructions + +```raku +use lib '.'; +use prql; + +say PRQL.parse('from employees'); +say PRQL.parsefile('employees.prql'); +``` + +## Tests + +Tests can be run individually by specifying the test filename on the command line: + + raku t/arithmetics.rakutest + +To run all tests in the directory you have to install `prove6` using `zef`: + + zef install App::Prove6 + prove6 --lib t/ + +## Documentation + +- https://docs.raku.org/language/grammar_tutorial +- https://docs.raku.org/language/grammars diff --git a/grammars/raku/prql.rakumod b/grammars/raku/prql.rakumod new file mode 100644 index 000000000000..6c349691a3f6 --- /dev/null +++ b/grammars/raku/prql.rakumod @@ -0,0 +1,319 @@ +=begin pod + +=head1 NAME + +prql.rakumod - Grammar for PRQL. + +=head1 SYNOPSIS + + use PRQL; + + # Parse a simple PRQL query + say PRQL.parse('from employees'); + + # Parse a PRQL file + say PRQL.parsefile('employees.prql'); + +=head1 DESCRIPTION + +PRQL grammar for Raku. + +PRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement. + +=head1 SEE ALSO + +L and L. + +=end pod + +grammar PRQL { + token TOP { + * + } + + rule statement { + | + | + | + | + | + | + | ? + } + + rule query-definition { + 'prql' + + } + + rule module { + 'module' '{' * '}' + } + + rule pipeline-statement { + + } + + rule pipeline { + | + % '|' + | '|' + } + + rule tuple-expression { + '{' + ( + | + | + | + | + )* %% ',' + '}' + } + + rule annotation { + '@{' + ? % ',' + '}' + } + + rule call-expression { + + ( + | + | + | + )+ + } + + rule named-arg { + ':' + } + + rule declaration { + '=' + } + + rule declaration-tuple { + '=' + } + + rule case-branch { + '=>' + } + + rule case-expression { + 'case' + } + + rule nested-pipeline { + '(' ')' + } + + # The name "test" here means equality testing. It is the name used in the Python grammar. + rule test { + + } + + rule test-inner { + | + | '!' + | + } + + rule binary-test { + | + | + | + } + + token expression { + | 'this' + | 'that' + | 'null' + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + } + + token boolean { + | 'true' + | 'false' + } + + token variable-name { + <.ident> + } + + token identifier { + <.ident> + ['.' [<.ident> | '*']]* + } + + rule array-expression { + '[' + ( | '*' )+ %% ',' + ']' + } + + rule binary-expression { + + } + + rule parenthesized-expression { + '(' ')' + } + + rule unary-expression { + | ('+' | '-') + | '==' + } + + token number { + | + | + } + + rule variable-declaration { + 'let' '=' ( | ) + } + + rule lambda { + * '->' + } + + rule type-definition { + '<' ('|' )* '>' + } + + rule type-name { + ? + } + + rule lambda-param { + ? (':' )? + } + + token integer { + | <.digit> [<.digit> | '_']* ['e' ['+' | '-']? ]? + | '0x' [<.xdigit> | '_']+ + | '0b' <[01_]>+ + | '0o' <[0..7_]>+ + } + + token float { + \d [\d | '_']* '.' \d [\d | '_']* ['e' ]? + } + + token date { + \d+ '-' \d+ '-' \d+ + } + + token time { + \d+ ':' \d+ + [':' \d+ ['.' \d+]?]? + } + + token date-time { + '@' + ( + | 'T'