schema = {
SOI
~ (namespace | import_statement | config_block | use_middlewares_block | struct_declaration | enum_declaration | model_declaration | constant_statement | dataset_declaration | interface_declaration | middleware_declaration | config_declaration | decorator_declaration | pipeline_item_declaration | handler_group_declaration | handler_declaration | handler_template_declaration | synthesized_shape_declaration | triple_comment_block | double_comment_block | availability_start | availability_end | decorator | empty_decorator | EMPTY_LINES | CATCH_ALL)*
~ EOI
}
// #############
// constants
// #############
WHITESPACE = _{ SPACE_SEPARATOR | "\t" }
EMPTY_LINES = _{ (WHITESPACE* ~ NEWLINE)+ }
// #############
// keywords
// #############
LET_KEYWORD = { "let" }
ENUM_KEYWORD = { "enum" }
MODEL_KEYWORD = { "model" }
STRUCT_KEYWORD = { "struct" }
STATIC_KEYWORD = { "static" }
FUNCTION_KEYWORD = { "function" }
UNIQUE_KEYWORD = { "unique" }
EXCLUSIVE_KEYWORD = { "exclusive" }
VARIANT_KEYWORD = { "variant" }
FIELD_KEYWORD = { "field" }
RELATION_KEYWORD = { "relation" }
PROPERTY_KEYWORD = { "property" }
MEMBER_KEYWORD = { "member" }
PIPELINE_KEYWORD = { "pipeline" }
ITEM_KEYWORD = { "item" }
SERVER_KEYWORD = { "server" }
CONNECTOR_KEYWORD = { "connector" }
CLIENT_KEYWORD = { "client" }
ENTITY_KEYWORD = { "entity" }
ADMIN_KEYWORD = { "admin" }
DEBUG_KEYWORD = { "debug" }
NAMESPACE_KEYWORD = { "namespace" }
STATIC_FILES_KEYWORD = { "static files" }
IMPORT_KEYWORD = { "import" }
FROM_KEYWORD = { "from" }
DATASET_KEYWORD = { "dataset" }
AUTOSEED_KEYWORD = { "autoseed" }
NOTRACK_KEYWORD = { "notrack" }
GROUP_KEYWORD = { "group" }
RECORD_KEYWORD = { "record" }
DECLARE_KEYWORD = { "declare" }
BUILTIN_KEYWORD = { "builtin" }
SYNTHESIZED_KEYWORD = { "synthesized" }
SHAPE_KEYWORD = { "shape" }
OPTIONAL_KEYWORD = { "optional" }
REQUIRED_KEYWORD = { "required" }
WITH_KEYWORD = { "with" }
NONAPI_KEYWORD = { "nonapi" }
CONFIG_KEYWORD = { "config" }
MIDDLEWARE_KEYWORD = { "middleware" }
MIDDLEWARES_KEYWORD = { "middlewares" }
DECORATOR_KEYWORD = { "decorator" }
REQUEST_KEYWORD = { "request" }
HANDLER_KEYWORD = { "handler" }
TEMPLATE_KEYWORD = { "template" }
INCLUDE_KEYWORD = { "include" }
AS_KEYWORD = { "as" }
JSON_KEYWORD = { "json" }
FORM_KEYWORD = { "form" }
INTERFACE_KEYWORD = { "interface" }
OPTION_KEYWORD = { "option" }
EXTENDS_KEYWORD = { "extends" }
WHERE_KEYWORD = { "where" }
TYPE_KEYWORD = { "type" }
CATCH_ALL = { (!NEWLINE ~ ANY)+ ~ NEWLINE? }
BLOCK_LEVEL_CATCH_ALL = { !BLOCK_CLOSE ~ CATCH_ALL }
// #############
// punctuations
// #############
COLON = @{ ":" }
COMMA = @{ "," }
DOT = @{ "." }
ASSIGN = @{ "=" }
BLOCK_OPEN = { "{" }
BLOCK_CLOSE = { "}" }
PAREN_OPEN = { "(" }
PAREN_CLOSE = { ")" }
CHEVRON_OPEN = { "<" }
CHEVRON_CLOSE = { ">" }
BRACKET_OPEN = { "[" }
BRACKET_CLOSE = { "]" }
OPTIONAL = { "?" }
HASH_TAG = { "#" }
AT = { "@" }
DOLLAR = { "$" }
ARITY_ARRAY = { "[]" }
ARITY_DICTIONARY = { "{}" }
ARROW = { "->" }
BAR = { "|" }
// #############
// identifier
// #############
identifier = @{ ("_" | ASCII_ALPHANUMERIC) ~ ( "_" | ASCII_ALPHANUMERIC)* }
identifier_path = { identifier ~ (DOT ~ identifier)* ~ empty_dot? }
// #############
// type
// #############
type_expression = { (type_subscript | type_item | type_group | type_tuple | typed_shape | typed_enum | type_reference) ~ ((BI_OR) ~ (type_subscript | type_item | type_group | type_tuple | typed_shape | typed_enum | type_reference))* }
type_item = { identifier_path ~ type_generics? ~ OPTIONAL? ~ arity? ~ OPTIONAL? }
type_generics = { CHEVRON_OPEN ~ type_expression ~ (COMMA ~ type_expression)* ~ COMMA? ~ CHEVRON_CLOSE }
arity = { ARITY_ARRAY | ARITY_DICTIONARY }
type_group = { PAREN_OPEN ~ type_expression ~ PAREN_CLOSE ~ OPTIONAL? ~ arity? ~ OPTIONAL? }
type_tuple = { PAREN_OPEN ~ type_expression ~ COMMA ~ type_expression? ~ (COMMA ~ type_expression)* ~ COMMA? ~ PAREN_CLOSE ~ OPTIONAL? ~ arity? ~ OPTIONAL? }
type_subscript = { type_item ~ BRACKET_OPEN ~ type_expression ~ BRACKET_CLOSE ~ OPTIONAL? ~ arity? ~ OPTIONAL? }
type_reference = { enum_variant_literal }
typed_shape_item = { identifier ~ COLON ~ type_expression }
typed_shape = {
BLOCK_OPEN ~
(typed_shape_item ~ (COMMA ~ typed_shape_item)* ~ COMMA?)? ~
BLOCK_CLOSE ~ OPTIONAL? ~ arity? ~ OPTIONAL?
}
typed_enum = { enum_variant_literal ~ BAR ~ enum_variant_literal ~ (BAR ~ enum_variant_literal)* }
// #############
// generics
// #############
generics_declaration = { CHEVRON_OPEN ~ identifier ~ (COMMA ~ identifier)* ~ COMMA? ~ CHEVRON_CLOSE }
generics_constraint = { WHERE_KEYWORD ~ generics_constraint_item ~ (COMMA ~ generics_constraint_item)* ~ COMMA? }
generics_constraint_item = { identifier ~ COLON ~ type_expression }
// #############
// import
// #############
import_statement = { IMPORT_KEYWORD ~ string_literal }
//import_identifier_list = { "{" ~ (identifier ~ (COMMA ~ identifier)*)? ~ COMMA? ~ BLOCK_CLOSE }
// #############
// numeric literals
// #############
numeric_literal = @{ ("-")? ~ ASCII_DIGIT+ ~ (DOT ~ ASCII_DIGIT+)? }
// #############
// string literals
// #############
ASCII_CONTROL_CHARACTER = _{ '\u{0000}'..'\u{001F}' }
string_escape = _{ "\\" ~ ANY }
string_content = @{ (string_escape | !("\"" | ASCII_CONTROL_CHARACTER) ~ ANY)* }
string_literal = ${ "\"" ~ string_content ~ "\"" }
// #############
// regex literals
// #############
regex_content = @{ (string_escape | !("/") ~ ANY)+ }
regex_literal = ${ "/" ~ regex_content ~ "/" }
// #############
// bool literals
// #############
bool_literal = @{ "true" | "false" }
// #############
// null literals
// #############
null_literal = { "null" }
// #############
// enum variant literals
// #############
enum_variant_literal = { DOT ~ identifier ~ argument_list? }
// #############
// tuple literals
// #############
tuple_literal = { PAREN_OPEN ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ (COMMA | (expression ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ COMMA ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ ( expression ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ (COMMA ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ expression)* ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ COMMA?)*)) ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ PAREN_CLOSE }
// #############
// array literals
// #############
array_literal = { BRACKET_OPEN ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block)* ~ (expression ~ (NEWLINE | triple_comment_block | double_comment_block)* ~ ( COMMA ~ (NEWLINE | triple_comment_block | double_comment_block)* ~ expression )* ~ (NEWLINE | triple_comment_block | double_comment_block)* ~ COMMA?)? ~ (NEWLINE | triple_comment_block | double_comment_block)* ~ BRACKET_CLOSE }
// #############
// dictionary literals
// #############
named_expression = { (string_literal | identifier | bracket_expression) ~ COLON ~ expression }
bracket_expression = { BRACKET_OPEN ~ expression ~ BRACKET_CLOSE }
dictionary_literal = { BLOCK_OPEN ~ (WHITE_SPACE | NEWLINE | triple_comment_block | double_comment_block | availability_start | availability_end)* ~ (named_expression ~ ( (NEWLINE | triple_comment_block | double_comment_block | availability_start | availability_end)* ~ COMMA ~ (NEWLINE | triple_comment_block | double_comment_block | availability_start | availability_end)* ~ named_expression )* ~ (NEWLINE | triple_comment_block | double_comment_block | availability_start | availability_end)* ~ COMMA? ~ (NEWLINE | triple_comment_block | double_comment_block | availability_start | availability_end)*)? ~ BLOCK_CLOSE }
// #############
// subscript
// #############
subscript = { BRACKET_OPEN ~ expression ~ BRACKET_CLOSE }
// #############
// comments
// #############
comment_token = { AT ~ (!(NEWLINE | WHITESPACE) ~ ANY)+ }
doc_content = @{ (!NEWLINE ~ ANY)* }
triple_comment = ${ WHITESPACE* ~ "///" ~ WHITESPACE* ~ comment_token? ~ doc_content }
double_comment = ${ WHITESPACE* ~ (!"///") ~ "//" ~ doc_content }
triple_comment_block = { (triple_comment ~ NEWLINE?)+ }
double_comment_block = { (double_comment ~ NEWLINE?)+ }
// #############
// operators
// #############
ADD = { "+" }
SUB = { "-" }
MUL = { "*" }
DIV = { (!"/") ~ "/" }
MOD = { "%" }
NEG = { "-" }
BI_AND = { "&" }
BI_XOR = { "^" }
BI_OR = { "|" }
BI_NEG = { "~" }
BI_LS = { "<<" }
BI_RS = { ">>" }
LT = { "<" }
LTE = { "<=" }
GT = { ">" }
GTE = { ">=" }
OR = { "||" }
AND = { "&&" }
NOT = { "!" }
EQ = { "==" }
NEQ = { "!=" }
NULLISH_COALESCING = { "??" }
RANGE_OPEN = { ".." }
RANGE_CLOSE = { "..." }
FORCE_UNWRAP = { "!" }
BINARY_OPERATOR = _{ MUL | DIV | MOD | ADD | SUB | BI_AND | BI_XOR | BI_OR | BI_LS | BI_RS | OR | AND | NOT | NULLISH_COALESCING | EQ | NEQ | RANGE_CLOSE | RANGE_OPEN }
UNARY_OPERATOR = _{ NEG | BI_NEG | NOT }
UNARY_TRAILING_OPERATOR = _{ FORCE_UNWRAP }
arith_expr = { UNARY_OPERATOR? ~ operand ~ UNARY_TRAILING_OPERATOR? ~ (BINARY_OPERATOR ~ UNARY_OPERATOR? ~ operand ~ UNARY_TRAILING_OPERATOR?)* }
// #############
// group
// #############
group = { PAREN_OPEN ~ expression ~ PAREN_CLOSE }
// #############
// unit & expression
// #############
unit = {
group |
null_literal |
bool_literal |
numeric_literal |
string_literal |
regex_literal |
enum_variant_literal |
empty_dot |
tuple_literal |
array_literal |
dictionary_literal |
identifier
~ (subscript | argument_list | DOT ~ (identifier | int_subscript))*
~ empty_dot?
}
int_subscript = @{ ASCII_DIGIT+ }
identifier_unit = {
identifier
~ (argument_list | (NEWLINE | WHITESPACE)* ~ DOT ~ (NEWLINE | WHITESPACE)* ~ identifier)*
~ empty_dot?
}
empty_dot = { DOT }
operand = { type_as_value_expression | unit | pipeline | empty_pipeline }
expression = {
arith_expr |
type_as_value_expression |
unit |
pipeline |
empty_pipeline
}
// #############
// variable & constant declaration
// #############
constant_statement = { triple_comment_block? ~ LET_KEYWORD ~ identifier ~ (COLON ~ type_expression)? ~ ASSIGN ~ expression }
// #############
// arguments
// #############
argument_list = { PAREN_OPEN ~ (NEWLINE | WHITESPACE)* ~ ((argument | partial_argument) ~ ((NEWLINE | WHITESPACE)* ~ COMMA ~ (NEWLINE | WHITESPACE)* ~ (argument | partial_argument) ~ (NEWLINE | WHITESPACE)*)*)? ~ COMMA? ~ (NEWLINE | WHITESPACE)* ~ PAREN_CLOSE }
partial_argument = { identifier ~ COLON }
argument = { (identifier ~ COLON)? ~ expression }
// #############
// decorator and pipeline
// #############
decorator = { AT ~ identifier_path ~ argument_list? }
empty_decorator = { AT }
pipeline = { DOLLAR ~ identifier_unit }
empty_pipeline = { DOLLAR }
// #############
// arguments declaration
// #############
argument_list_declaration = {
PAREN_OPEN ~
(NEWLINE | WHITESPACE)* ~
((argument_declaration | partial_argument_declaration) ~ ((NEWLINE | WHITESPACE)* ~ COMMA ~ (NEWLINE | WHITESPACE)* ~ (argument_declaration | partial_argument_declaration) ~ (NEWLINE | WHITESPACE)*)*)? ~
COMMA? ~
(NEWLINE | WHITESPACE)* ~
PAREN_CLOSE
}
argument_declaration = { identifier ~ OPTIONAL? ~ COLON ~ type_expression }
partial_argument_declaration = { identifier ~ OPTIONAL? ~ COLON }
// #############
// config blocks
// #############
config_keywords = { SERVER_KEYWORD | CONNECTOR_KEYWORD | CLIENT_KEYWORD | ENTITY_KEYWORD | DEBUG_KEYWORD | ADMIN_KEYWORD }
config_block = {
config_keywords
~ identifier?
~ dictionary_literal
}
// #############
// enum
// #############
enum_declaration = {
triple_comment_block?
~ (decorator ~ (NEWLINE | WHITESPACE)*)*
~ INTERFACE_KEYWORD?
~ OPTION_KEYWORD?
~ ENUM_KEYWORD
~ identifier
~ BLOCK_OPEN
~ (enum_member_declaration | triple_comment_block | double_comment_block | availability_start | availability_end | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)*
~ BLOCK_CLOSE
}
enum_member_declaration = {
triple_comment_block? ~
(decorator ~ double_comment_block? ~ (NEWLINE | WHITESPACE)*)* ~
identifier ~ ((ASSIGN ~ enum_member_expression) | argument_list_declaration)?
}
enum_member_expression = { arith_expr | string_literal | numeric_literal }
// #############
// model
// #############
model_declaration = {
triple_comment_block? ~
(decorator | double_comment_block | empty_decorator | (NEWLINE | WHITESPACE))*
~ MODEL_KEYWORD
~ identifier
~ BLOCK_OPEN
~ (field_declaration | partial_field | handler_declaration | include_handler_from_template | decorator | empty_decorator | triple_comment_block | double_comment_block | availability_start | availability_end | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)*
~ BLOCK_CLOSE
}
// #############
// field
// #############
field_declaration = {
triple_comment_block? ~
(decorator | double_comment_block | empty_decorator | (NEWLINE | WHITESPACE))*
~ identifier
~ COLON
~ type_expression
~ double_comment_block?
}
partial_field = {
identifier ~ COLON ~ WHITESPACE?
}
// #############
// dataset
// #############
dataset_declaration = {
triple_comment_block? ~ (AUTOSEED_KEYWORD | NOTRACK_KEYWORD)? ~ DATASET_KEYWORD ~ identifier ~ BLOCK_OPEN ~ (EMPTY_LINES | triple_comment_block | double_comment_block | availability_start | availability_end | dataset_group_declaration)* ~ BLOCK_CLOSE
}
dataset_group_declaration = {
triple_comment_block? ~ GROUP_KEYWORD ~ identifier_path ~ BLOCK_OPEN ~ (EMPTY_LINES | triple_comment_block | double_comment_block | availability_start | availability_end | dataset_group_record_declaration)* ~ BLOCK_CLOSE
}
dataset_group_record_declaration = {
triple_comment_block? ~ RECORD_KEYWORD ~ identifier ~ dictionary_literal
}
// #############
// declare
// #############
decorator_declaration = {
triple_comment_block? ~
DECLARE_KEYWORD ~
EXCLUSIVE_KEYWORD? ~
UNIQUE_KEYWORD? ~
(MODEL_KEYWORD | ENUM_KEYWORD | INTERFACE_KEYWORD | HANDLER_KEYWORD) ~
(FIELD_KEYWORD | RELATION_KEYWORD | PROPERTY_KEYWORD | MEMBER_KEYWORD)? ~
DECORATOR_KEYWORD ~
identifier ~
(generics_declaration? ~ argument_list_declaration ~ generics_constraint?)? ~
(BLOCK_OPEN ~
(decorator_variant_declaration | triple_comment_block | double_comment_block | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)* ~
BLOCK_CLOSE)?
}
decorator_variant_declaration = {
triple_comment_block? ~
VARIANT_KEYWORD ~
(generics_declaration? ~ argument_list_declaration ~ generics_constraint?)?
}
pipeline_item_declaration = {
triple_comment_block? ~
DECLARE_KEYWORD ~ PIPELINE_KEYWORD ~ ITEM_KEYWORD ~
identifier ~
(
(
generics_declaration? ~
argument_list_declaration? ~
COLON ~
type_expression ~
ARROW ~
type_expression ~ generics_constraint?
) | (
BLOCK_OPEN ~
(pipeline_item_variant_declaration | triple_comment_block | double_comment_block | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)* ~
BLOCK_CLOSE
)
)
}
pipeline_item_variant_declaration = {
triple_comment_block? ~
VARIANT_KEYWORD ~
generics_declaration? ~ argument_list_declaration? ~
COLON ~
type_expression ~
ARROW ~
type_expression ~ generics_constraint?
}
handler_group_declaration = {
triple_comment_block? ~ DECLARE_KEYWORD ~ HANDLER_KEYWORD ~ GROUP_KEYWORD ~ identifier ~ BLOCK_OPEN
~ (handler_declaration | triple_comment_block | double_comment_block | availability_start | availability_end | decorator | empty_decorator | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)*
~ BLOCK_CLOSE
}
req_type = {
JSON_KEYWORD | FORM_KEYWORD
}
handler_declaration = {
triple_comment_block? ~
(decorator | double_comment_block | empty_decorator | (NEWLINE | WHITESPACE))* ~
DECLARE_KEYWORD ~ NONAPI_KEYWORD? ~ req_type? ~ HANDLER_KEYWORD ~
identifier ~ PAREN_OPEN ~ double_comment_block? ~ type_expression? ~ double_comment_block? ~ PAREN_CLOSE ~ COLON ~ type_expression
}
middleware_declaration = {
triple_comment_block? ~
DECLARE_KEYWORD ~ (REQUEST_KEYWORD|HANDLER_KEYWORD) ~ MIDDLEWARE_KEYWORD ~ identifier ~ argument_list_declaration?
}
config_declaration = {
triple_comment_block? ~
DECLARE_KEYWORD ~
CONFIG_KEYWORD ~
identifier ~
BLOCK_OPEN ~
(field_declaration | partial_field | triple_comment_block | double_comment_block | availability_start | availability_end | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)* ~
BLOCK_CLOSE
}
// #############
// interface
// #############
interface_declaration = {
triple_comment_block? ~
(decorator | double_comment_block | empty_decorator | (NEWLINE | WHITESPACE))* ~
INTERFACE_KEYWORD ~ identifier ~ generics_declaration? ~ (EXTENDS_KEYWORD ~ type_expression ~ (COMMA ~ type_expression)* ~ COMMA?)? ~ generics_constraint? ~ BLOCK_OPEN
~ (field_declaration | partial_field | triple_comment_block | double_comment_block | availability_start | availability_end | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)*
~ BLOCK_CLOSE
}
// #############
// namespace
// #############
namespace = {
triple_comment_block? ~
NAMESPACE_KEYWORD ~ identifier
~ BLOCK_OPEN
~ (namespace | config_block | use_middlewares_block | struct_declaration | enum_declaration | model_declaration | constant_statement | dataset_declaration | interface_declaration | middleware_declaration | decorator_declaration | config_declaration | pipeline_item_declaration | handler_group_declaration | handler_declaration | handler_template_declaration | synthesized_shape_declaration | triple_comment_block | double_comment_block | availability_start | availability_end | decorator | empty_decorator | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)*
~ BLOCK_CLOSE
}
// #############
// use_middlewares_block
// #############
use_middlewares_block = {
triple_comment_block? ~ (HANDLER_KEYWORD|REQUEST_KEYWORD) ~ MIDDLEWARES_KEYWORD ~ array_literal
}
// #############
// availability
// #############
availability_start = {
HASH_TAG ~ "if" ~ "available" ~ PAREN_OPEN ~ identifier ~ PAREN_CLOSE
}
availability_end = {
HASH_TAG ~ "end"
}
// #############
// struct
// #############
struct_declaration = {
triple_comment_block? ~
DECLARE_KEYWORD ~
STRUCT_KEYWORD ~
identifier ~
generics_declaration? ~
generics_constraint? ~
BLOCK_OPEN ~
(function_declaration | triple_comment_block | double_comment_block | availability_start | availability_end | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)* ~
BLOCK_CLOSE
}
function_declaration = {
triple_comment_block? ~
DECLARE_KEYWORD ~
STATIC_KEYWORD? ~
FUNCTION_KEYWORD ~
identifier ~
generics_declaration? ~
argument_list_declaration ~
COLON ~
type_expression ~
generics_constraint?
}
// #############
// synthesized shape declaration
// #############
synthesized_shape_declaration = {
triple_comment_block? ~
DECLARE_KEYWORD ~
BUILTIN_KEYWORD? ~
SYNTHESIZED_KEYWORD ~
SHAPE_KEYWORD ~
identifier ~
(
BLOCK_OPEN ~
(field_declaration | partial_field | synthesized_shape_field_declaration | triple_comment_block | double_comment_block | availability_start | availability_end | EMPTY_LINES | BLOCK_LEVEL_CATCH_ALL)* ~
BLOCK_CLOSE
)?
}
synthesized_shape_field_declaration = {
triple_comment_block? ~ DECLARE_KEYWORD ~ (REQUIRED_KEYWORD | OPTIONAL_KEYWORD)? ~ SYNTHESIZED_KEYWORD ~ FIELD_KEYWORD ~ WITH_KEYWORD ~ AT ~ identifier_path
}
// #############
// include template for model handler group
// #############
include_handler_from_template = {
triple_comment_block? ~
(decorator | double_comment_block | empty_decorator | (NEWLINE | WHITESPACE))* ~
INCLUDE_KEYWORD ~ HANDLER_KEYWORD ~ identifier_path ~ (AS_KEYWORD ~ identifier)?
}
// #############
// handler template declaration
// #############
handler_template_declaration = {
triple_comment_block? ~
(decorator | double_comment_block | empty_decorator | (NEWLINE | WHITESPACE))* ~
DECLARE_KEYWORD ~
NONAPI_KEYWORD? ~
req_type? ~
HANDLER_KEYWORD ~
TEMPLATE_KEYWORD ~
identifier ~
PAREN_OPEN ~
type_expression? ~
PAREN_CLOSE ~
COLON ~
type_expression
}
// #############
// type as value expression
// #############
type_as_value_expression = { TYPE_KEYWORD ~ type_expression }