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'