diff --git a/.mega-linter.yaml b/.mega-linter.yaml index 8557dfecf79b..e76d9a9a79a5 100644 --- a/.mega-linter.yaml +++ b/.mega-linter.yaml @@ -47,3 +47,4 @@ DISABLE_ERRORS_LINTERS: - PHP_PHPCSFIXER PHP_PHPCS_ARGUMENTS: - --standard=PSR12 +RAKU_RAKU_ARGUMENTS: -I ./grammars/raku/lib/ diff --git a/CHANGELOG.md b/CHANGELOG.md index a039aa61bee7..e1e87600c4f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ **Integrations**: +- Add grammar file for Raku. (@vanillajonathan, #5576) + **Internal changes**: **New Contributors**: diff --git a/grammars/README.md b/grammars/README.md index b3b5c2962ed2..bea84245ef68 100644 --- a/grammars/README.md +++ b/grammars/README.md @@ -70,6 +70,9 @@ an index. ([prql.py](https://github.com/pygments/pygments/blob/master/pygments/lexers/prql.py)). See the [demo](https://pygments.org/demo/). +- [Raku](https://raku.org/) — Grammar can be found at + [`grammars/raku/`](https://github.com/PRQL/prql/tree/main/grammars/raku/). + - [TEA](https://github.com/psemiletov/tea-qt/) — supported. The grammar is [upstream](https://github.com/psemiletov/tea-qt/blob/master/hls/prql.xml). diff --git a/grammars/raku/META6.json b/grammars/raku/META6.json new file mode 100644 index 000000000000..339a651b5866 --- /dev/null +++ b/grammars/raku/META6.json @@ -0,0 +1,20 @@ +{ + "name": "PRQL", + "version": "0.0.1", + "description": "Grammar for PRQL", + "tags": ["data", "grammar", "pipeline", "sql"], + "source-url": "https://github.com/PRQL/prql/", + "support": { + "source": "https://github.com/PRQL/prql/", + "bugtracker": "https://github.com/PRQL/prql/issues" + }, + "api": "1.0", + "production": false, + "auth": "github:PRQL", + "license": "Artistic-2.0", + "provides": { + "prql": "lib/prql.rakumod" + }, + "raku": "6.*", + "meta-version": "1" +} diff --git a/grammars/raku/README.md b/grammars/raku/README.md new file mode 100644 index 000000000000..8a742d58d067 --- /dev/null +++ b/grammars/raku/README.md @@ -0,0 +1,36 @@ +# Raku grammar + +PRQL grammar for Raku. + +## Instructions + +```raku +use lib '.'; +use prql; + +say PRQL.parse('from employees'); +say PRQL.parsefile('employees.prql'); +``` + +## Installation + +To install from source run: + + zef install . + +## 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/lib/prql.rakumod b/grammars/raku/lib/prql.rakumod new file mode 100644 index 000000000000..849342d0b2c4 --- /dev/null +++ b/grammars/raku/lib/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'