EBNF Grammar
This is the complete EBNF grammar for WCL.
Notation:
=— rule definition|— alternation{ ... }— zero or more repetitions[ ... ]— zero or one (optional)( ... )— grouping"..."— literal terminalUPPER— named terminal
(* ===== Top-level ===== *)
document = trivia { doc_item } trivia ;
doc_item = import_decl | export_decl | body_item ;
body = { body_item } ;
body_item = attribute
| block
| table
| let_binding
| macro_def
| macro_call
| for_loop
| conditional
| validation
| schema
| decorator_schema
| symbol_set_decl
| declare_stmt
| comment ;
(* ===== Import Directives (top-level only) ===== *)
import_decl = "import" ["?"] (STRING_LIT | library_import) ;
library_import = "<" IDENT { "." IDENT } ".wcl" ">" ;
(* ===== Export Declarations (top-level only) ===== *)
export_decl = "export" "let" IDENT "=" expression
| "export" IDENT ;
(* ===== Attributes ===== *)
attribute = { decorator } IDENT "=" expression ;
(* ===== Blocks ===== *)
block = { decorator } [ "partial" ] IDENT [ IDENTIFIER_LIT ]
{ inline_arg } ( "{" body "}" | text_content ) ;
inline_arg = INT_LIT | FLOAT_LIT | STRING_LIT | BOOL_LIT | NULL_LIT
| symbol_lit | IDENT | list_literal ;
text_content = STRING_LIT | heredoc ;
(* ===== Let Bindings ===== *)
let_binding = { decorator } ["partial"] "let" IDENT "=" expression ;
(* ===== Control Flow ===== *)
for_loop = "for" IDENT [ "," IDENT ] "in" expression "{" body "}" ;
conditional = "if" expression "{" body "}" [ else_branch ] ;
else_branch = "else" ( conditional | "{" body "}" ) ;
(* ===== Tables ===== *)
table = { decorator } [ "partial" ] "table" IDENTIFIER_LIT
[ ":" IDENT ] ( "{" table_body "}" | "=" expression ) ;
table_body = { column_decl } { table_row } ;
column_decl = { decorator } IDENT ":" type_expr ;
table_row = "|" expression { "|" expression } "|" ;
(* ===== Schemas ===== *)
schema = { decorator } "schema" STRING_LIT "{" { schema_field | schema_variant } "}" ;
schema_variant = { decorator } "variant" STRING_LIT "{" { schema_field } "}" ;
schema_field = { decorator } IDENT "=" type_expr { decorator } ;
(* ===== Decorator Schemas ===== *)
decorator_schema = { decorator } "decorator_schema" STRING_LIT
"{" decorator_schema_body "}" ;
decorator_schema_body = "target" "=" "[" target_list "]" { schema_field } ;
target_list = target { "," target } ;
target = "block" | "attribute" | "table" | "schema" ;
(* ===== Symbol Sets ===== *)
symbol_set_decl = "symbol_set" IDENT "{" { symbol_set_member } "}" ;
symbol_set_member = symbol_lit [ "=" STRING_LIT ] ;
symbol_lit = ":" IDENT ;
(* ===== Decorators ===== *)
decorator = "@" IDENT [ "(" decorator_args ")" ] ;
decorator_args = positional_args [ "," named_args ]
| named_args ;
positional_args = expression { "," expression } ;
named_args = named_arg { "," named_arg } ;
named_arg = IDENT "=" expression ;
(* ===== Macros ===== *)
macro_def = { decorator } "macro" ( func_macro_def | attr_macro_def ) ;
func_macro_def = IDENT "(" param_list ")" "{" body "}" ;
attr_macro_def = "@" IDENT "(" param_list ")" "{" transform_body "}" ;
param_list = [ param { "," param } ] ;
param = IDENT [ ":" type_expr ] [ "=" expression ] ;
macro_call = IDENT "(" [ arg_list ] ")" ;
arg_list = expression { "," expression } [ "," named_args ] ;
(* ===== Transform Body (attribute macros) ===== *)
transform_body = { transform_directive } ;
transform_directive = inject_block | set_block | remove_block | when_block ;
inject_block = "inject" "{" body "}" ;
set_block = "set" "{" { attribute } "}" ;
remove_block = "remove" "[" ident_list "]" ;
ident_list = IDENT { "," IDENT } [ "," ] ;
when_block = "when" expression "{" { transform_directive } "}" ;
(* ===== Declare Statements ===== *)
declare_stmt = "declare" IDENT "(" [ declare_params ] ")" [ "->" type_expr ] ;
declare_params = declare_param { "," declare_param } ;
declare_param = IDENT ":" type_expr ;
(* ===== Validation ===== *)
validation = { decorator } "validation" STRING_LIT "{"
{ let_binding } "check" "=" expression
"message" "=" expression "}" ;
(* ===== Types ===== *)
type_expr = "string" | "int" | "float" | "bool" | "null"
| "identifier" | "symbol" | "any"
| "list" "(" type_expr ")"
| "map" "(" type_expr "," type_expr ")"
| "set" "(" type_expr ")"
| "ref" "(" STRING_LIT ")"
| "union" "(" type_expr { "," type_expr } ")" ;
(* ===== Expressions ===== *)
expression = ternary_expr ;
ternary_expr = or_expr [ "?" expression ":" expression ] ;
or_expr = and_expr { "||" and_expr } ;
and_expr = equality_expr { "&&" equality_expr } ;
equality_expr = comparison_expr { ( "==" | "!=" ) comparison_expr } ;
comparison_expr = additive_expr { ( "<" | ">" | "<=" | ">=" | "=~" )
additive_expr } ;
additive_expr = multiplicative_expr { ( "+" | "-" ) multiplicative_expr } ;
multiplicative_expr = unary_expr { ( "*" | "/" | "%" ) unary_expr } ;
unary_expr = ( "!" | "-" ) unary_expr | postfix_expr ;
postfix_expr = primary_expr { ( "." IDENT | "[" expression "]"
| "(" [ arg_list ] ")" ) } ;
primary_expr = INT_LIT | FLOAT_LIT | STRING_LIT | BOOL_LIT | NULL_LIT
| IDENTIFIER_LIT | IDENT | symbol_lit
| list_literal | map_literal
| "(" expression ")"
| query_expr
| import_util_expr
| ref_expr
| lambda_expr ;
(* ===== Special Expressions ===== *)
query_expr = "query" "(" pipeline ")" ;
pipeline = selector { "|" filter } ;
selector = [ ".." ] IDENT [ "#" IDENTIFIER_LIT ]
{ "." ( IDENT | STRING_LIT ) }
| "." | "*" ;
filter = "." IDENT [ ( "==" | "!=" | "<" | ">" | "<=" | ">="
| "=~" ) expression ]
| "has" "(" ( "." IDENT | "@" IDENT ) ")"
| "@" IDENT "." IDENT ( "==" | "!=" | "<" | ">" | "<="
| ">=" ) expression ;
import_util_expr = "import_table" "(" STRING_LIT { "," import_table_arg } ")"
| "import_raw" "(" STRING_LIT ")" ;
import_table_arg = STRING_LIT | IDENT "=" expression ;
ref_expr = "ref" "(" IDENTIFIER_LIT ")" ;
lambda_expr = lambda_params "=>" ( expression | block_expr ) ;
lambda_params = IDENT
| "(" [ IDENT { "," IDENT } ] ")" ;
block_expr = "{" { let_binding } expression "}" ;
(* ===== Collections ===== *)
list_literal = "[" [ expression { "," expression } [ "," ] ] "]" ;
map_literal = "{" [ map_entry { map_entry } ] "}" ;
map_entry = ( IDENT | STRING_LIT ) "=" expression ;
(* ===== Trivia ===== *)
trivia = { whitespace | comment } ;
comment = line_comment | block_comment | doc_comment ;
line_comment = "//" { any_char } newline ;
block_comment = "/*" { any_char | block_comment } "*/" ;
doc_comment = "///" { any_char } newline ;
(* ===== Terminals ===== *)
IDENT = ( letter | "_" ) { letter | digit | "_" } ;
IDENTIFIER_LIT = ( letter | "_" ) { letter | digit | "_" | "-" } ;
STRING_LIT = '"' { string_char | escape_seq | interpolation } '"'
| heredoc ;
INT_LIT = digit { digit | "_" }
| "0x" hex_digit { hex_digit | "_" }
| "0o" oct_digit { oct_digit | "_" }
| "0b" bin_digit { bin_digit | "_" } ;
FLOAT_LIT = digit { digit } "." digit { digit }
[ ( "e" | "E" ) [ "+" | "-" ] digit { digit } ] ;
BOOL_LIT = "true" | "false" ;
NULL_LIT = "null" ;
interpolation = "${" expression "}" ;
escape_seq = "\\" ( '"' | "\\" | "n" | "r" | "t"
| "u" hex4 | "U" hex8 ) ;
heredoc = "<<" [ "-" ] marker newline { any_char } newline marker
| "<<'" marker "'" newline { any_char } newline marker ;