Skip to content

Modelable Grammar

Generated from cli/src/modelable/grammar/modelable.lark by cli/scripts/render_language_grammar.py — do not edit by hand. Whenever the grammar changes, regenerate this page and commit it alongside the parser.

This page is the published form of the canonical grammar. The Lark EBNF in cli/src/modelable/grammar/modelable.lark is loaded by cli/src/modelable/parser/parse.py via Lark(parser="earley", ambiguity="resolve") and remains the single source of truth. If any example in language-reference.md conflicts with this grammar, the documentation identifies a defect; it does not redefine the language.

Grammar

// Modelable IDL Grammar
// Parser: Earley

start: statement+

statement: domain_decl
         | binding_decl
         | workspace_decl
         | import_domain_stmt
         | projection_decl
         | subscription_decl
         | consumer_decl


// -- Domain ------------------------------------------------------------------

domain_decl: "domain" domain_name "{" domain_item* "}"
domain_name: IDENT | ESCAPED_STRING

domain_item: owner_attr
           | contact_attr
           | desc_attr
           | model_decl
           | model_evolution_decl
           | projection_decl
           | enum_projection_decl
           | auto_projections_decl
           | api_decl
           | generate_block
           | semantic_decl
           | index_decl

owner_attr: "owner" ":" ESCAPED_STRING
contact_attr: "contact" ":" ESCAPED_STRING
desc_attr: "description" ":" ESCAPED_STRING


// -- Model -------------------------------------------------------------------

model_decl: wire_annotation* model_kind IDENT model_header? "{" model_body_item* "}"
model_header: "@" INT model_change?
            | model_change
model_change: "(" change_kind ")"

model_body_item: field_decl
               | access_block
               | reservation_block

// -- Model version deltas (evolution plan D1/D2/D3) ---------------------------
// A model version authored as a delta against an exact prior version rather
// than a complete field list. The base version resolves within the same
// domain/model/kind at workspace-normalization time, not at parse time.
// Model-level metadata (wire annotations, access block, Protobuf
// reservations) follows the same complete-replacement-or-inherit rule as
// field operations: present on the evolves form, it replaces; omitted, it
// inherits from the base (reservations are the one exception -- they are
// version-local exactly like the full-form declaration, see
// docs/language-reference.md §2.6/2.7).
model_evolution_decl: wire_annotation* model_kind IDENT "@" INT model_change? "evolves" "@" INT "{" evolution_item* "}"
evolution_item: add_operation
              | remove_operation
              | rename_operation
              | replace_operation
              | access_block
              | reservation_block
add_operation: "add" field_decl
remove_operation: "remove" IDENT
rename_operation: "rename" IDENT "->" IDENT
replace_operation: "replace" field_decl

model_kind: "entity"    -> mk_entity
          | "aggregate" -> mk_aggregate
          | "event"     -> mk_event
          | "value"     -> mk_value

change_kind: "additive" -> ck_additive
           | "breaking" -> ck_breaking

field_decl: annotation* IDENT optional_marker? ":" type_expr nullable_marker? constraint_clause* field_default?
optional_marker: "?"
nullable_marker: "?"
constraint_clause: "constraint" "{" constraint_item ("," constraint_item)* "}" -> constraint_clause
constraint_item: IDENT ":" constraint_value
constraint_value: ESCAPED_STRING -> constraint_string
                | CONSTRAINT_NUMBER -> constraint_number
                | "true"             -> constraint_true
                | "false"            -> constraint_false
field_default: "=" EXPRESSION

annotation: "@key"                                                -> ann_key
          | "@pii"                                                -> ann_pii
          | "@classification" "(" ESCAPED_STRING ")"             -> ann_classification
          | "@deprecated" "(" "replacedBy" ":" ESCAPED_STRING ")" -> ann_deprecated
          | "@owner" "(" ESCAPED_STRING ")"                      -> ann_owner
          | "@server"                                             -> ann_server
          | wire_annotation
          | "@pitCutoff" "(" ANNOTATION_EXPR ")"                  -> ann_pit_cutoff
          | "@latestBefore" "(" ANNOTATION_EXPR ")"               -> ann_latest_before
          | "@latestOnly"                                         -> ann_latest_only
          | "@custom" "(" (IDENT | ESCAPED_STRING) ["," ANNOTATION_EXPR] ")" -> ann_custom

wire_annotation: "@wire" "(" wire_option ("," wire_option)* ")" -> ann_wire
wire_option: wire_key ":" wire_value
wire_key: IDENT ("." IDENT)?
wire_value: ESCAPED_STRING        -> wire_string
          | wire_map
wire_map: "{" wire_map_item ("," wire_map_item)* "}"
wire_map_item: IDENT ":" ESCAPED_STRING


// -- Types -------------------------------------------------------------------

type_expr: primitive_type
         | decimal_type
         | fixed_binary_type
         | enum_type
         | array_type
         | map_type
         | ref_type
         | object_type
         | union_type
         | enum_ref_type
         | dotted_ref

primitive_type: "string"    -> pt_string
              | "int"       -> pt_int
              | "float"     -> pt_float
              | "bool"      -> pt_bool
              | "date"      -> pt_date
              | "time"      -> pt_time
              | "timestamp" -> pt_timestamp
              | "uuid" ("(" INT ")")?  -> pt_uuid
              | "duration"  -> pt_duration
              | "binary"    -> pt_binary
              | "json"      -> pt_json
              | "u8"        -> pt_u8
              | "u16"       -> pt_u16
              | "u32"       -> pt_u32
              | "u64"       -> pt_u64
              | "u128"      -> pt_u128
              | "i8"        -> pt_i8
              | "i16"       -> pt_i16
              | "i32"       -> pt_i32
              | "i64"       -> pt_i64
              | "i128"      -> pt_i128

decimal_type: "decimal" "(" INT "," INT ")"
fixed_binary_type: "binary" "(" INT ")"
enum_type: "enum" "(" enum_member ("," enum_member)* ")"
enum_member: IDENT
           | NUMERIC_IDENT

NUMERIC_IDENT: /[0-9][A-Za-z0-9_-]*/
array_type: "array" "<" type_expr ">"
map_type: "map" "<" type_expr "," type_expr ">"
ref_type: "ref" "<" dotted_ref ("@" version_spec)? ">"
enum_ref_type: dotted_ref "@" INT
object_type: "object" "{" field_decl* "}"
union_type: "union" "<" IDENT ">" "{" union_variant ("," union_variant)* "}"
union_variant: IDENT ":" type_expr


// -- Projections --------------------------------------------------------------

projection_decl: wire_annotation* "projection" IDENT "@" INT projection_source_block? source_clause? selection_clause? "{" projection_body_item* "}"

selection_clause: pick_clause | omit_clause
pick_clause: "pick" "(" selector ("," selector)* ")"
omit_clause: "omit" "(" selector ("," selector)* ")"
selector: qualified_field | auto_projection_exclusion
projection_source_block: "{" source_clause "}"

projection_body_item: proj_field
                    | access_block
                    | subscription_block
                    | generate_block
                    | materialisation_block
                    | reservation_block

source_clause: "from" dotted_ref "@" version_spec "as" IDENT join_clause* where_clause? group_clause?

where_clause: "where" FIELD_EXPRESSION

join_modifier: "left"

join_clause: join_prefix annotation*
          | join_prefix join_option*
join_option: annotation
           | cardinality_attr
cardinality_attr: "cardinality" ":" IDENT
join_prefix: "join" dotted_ref "@" version_spec "as" IDENT "on" EXPRESSION
           | join_modifier "join" dotted_ref "@" version_spec "as" IDENT "on" EXPRESSION

group_clause: "group" "by" group_item ("," group_item)*

group_item: /(?:[^,\n\r{}()]|\([^()\n\r{}]*\))+/

version_spec: INT                  -> version_exact
            | INT "#" HASH        -> version_pinned
            | ">=" INT "<" INT     -> version_range
            | ">=" INT             -> version_min

proj_field: annotation* IDENT "<-" qualified_field -> direct_field
          | annotation* IDENT "=" FIELD_EXPRESSION  -> computed_field

subscription_block: "subscription" "{" subscription_item* "}"
subscription_item: IDENT ":" EXPRESSION
materialisation_block: "materialisation" "{" materialisation_item* "}"
materialisation_item: IDENT ":" EXPRESSION

qualified_field: IDENT "." IDENT

reservation_block: "reserved" "protobuf" "{" reservation_item* "}"
reservation_item: reserved_numbers | reserved_names
reserved_numbers: "numbers" ":" "[" INT ("," INT)* "]"
reserved_names: "names" ":" "[" ESCAPED_STRING ("," ESCAPED_STRING)* "]"


// -- Generate ----------------------------------------------------------------

api_decl: "api" IDENT "@" INT "{" api_operation* "}"
api_operation: "operation" ESCAPED_STRING "{" api_operation_item* "}"
api_operation_item: method_clause
                   | path_clause
                   | request_clause
                   | responses_block
method_clause: "method" ":" http_method
path_clause: "path" ":" ESCAPED_STRING
request_clause: "request" ":" dotted_ref "@" INT
responses_block: "responses" "{" response_decl* "}"
response_decl: INT ":" dotted_ref "@" INT
http_method: "GET"    -> http_get
           | "POST"   -> http_post
           | "PUT"    -> http_put
           | "PATCH"  -> http_patch
           | "DELETE" -> http_delete

generate_block: "generate" "{" generate_target* "}"

generate_target: target_name ("->" ESCAPED_STRING)?

target_name: "openapi"                 -> tn_openapi
           | "typescript"              -> tn_typescript
           | "avro"                    -> tn_avro
           | "protobuf"                -> tn_protobuf
           | "sql" "(" db_dialect ")"  -> tn_sql
           | "jsonschema"              -> tn_jsonschema
           | "asyncapi"                -> tn_asyncapi
           | "docs"                    -> tn_docs

db_dialect: "postgres" -> dd_postgres
          | "mysql"    -> dd_mysql
          | "clickhouse" -> dd_clickhouse
          | "sqlite"   -> dd_sqlite


// -- Deferred top-level forms ------------------------------------------------
// These are parsed more fully in later parser-plan tasks.

binding_decl: "binding" IDENT "{" binding_item* "}"
binding_item: binding_adapter_attr
            | binding_model_attr
            | binding_table_attr
            | ignored_block_item
binding_adapter_attr: "adapter" ":" IDENT
binding_model_attr: "model" ":" dotted_ref "@" INT
binding_table_attr: "table" ":" ESCAPED_STRING
subscription_decl: "subscription" IDENT "{" subscription_decl_item* "}"
subscription_decl_item: IDENT ":" EXPRESSION
workspace_decl: "workspace" workspace_label? "{" workspace_item* "}"
workspace_label: IDENT | ESCAPED_STRING
workspace_item: workspace_name_attr
              | workspace_description_attr
              | registry_block
              | peers_block
              | generate_block
              | ai_block
              | package_block
workspace_name_attr: "name" ":" ESCAPED_STRING
workspace_description_attr: "description" ":" ESCAPED_STRING
registry_block: "registry" "{" ignored_block_item* "}"
package_block: "package" ESCAPED_STRING "{" package_item* "}"
package_item: package_include_attr
            | package_description_attr
package_include_attr: "include" ":" "[" [ESCAPED_STRING ("," ESCAPED_STRING)*] "]"
package_description_attr: "description" ":" ESCAPED_STRING
peers_block: "peers" ":" "[" PEERS_CONTENT "]"
ai_block: "ai" "{" ai_item* "}"
ai_item: ai_provider | ai_model | ai_repair_attempts
ai_provider: "provider" ":" ESCAPED_STRING
ai_model: "model" ":" ESCAPED_STRING
ai_repair_attempts: "repair_attempts" ":" INT
import_domain_stmt: "import" "domain" dotted_ref import_source? pinned_import? version_selector?
import_source: "from" "registry" ESCAPED_STRING
pinned_import: "at" dotted_ref "@" INT "#" IDENT
consumer_decl: "consumer" IDENT? "{" ignored_block_item* "}"
auto_projections_decl: "auto" "projections" IDENT "@" INT "{" auto_projection_item* "}"

semantic_decl: "semantic" IDENT semantic_header? ":" type_expr semantic_body?
semantic_header: "@" INT semantic_change?

// -- Enum projections ---------------------------------------------------------
// Chosen spelling (E3 spike): the concise `enum projection` form. At domain
// top level no other rule starts with the "enum" keyword, so this creates no
// ambiguous second declaration namespace.
enum_projection_decl: "enum" "projection" IDENT semantic_header? "from" dotted_ref "@" INT pick_or_omit_clause
pick_or_omit_clause: "pick" "(" enum_member ("," enum_member)* ")"  -> pick_selection
                   | "omit" "(" enum_member ("," enum_member)* ")"  -> omit_selection
semantic_change: "(" change_kind ")"
semantic_body: "{" semantic_item* "}"
semantic_item: "registry" ":" bool_literal
bool_literal: "true"  -> bl_true
            | "false" -> bl_false

index_decl: "index" IDENT "@" INT "{" index_item* "}"
index_item: primary_index | secondary_index
primary_index: "primary" IDENT ("," IDENT)*
secondary_index: "secondary" IDENT "{" secondary_index_item* "}"
secondary_index_item: key_item | sort_item | unique_item
key_item: "key" ":" "[" IDENT ("," IDENT)* "]"
sort_item: "sort" ":" "[" sort_field ("," sort_field)* "]"
unique_item: "unique" ":" bool_literal
sort_field: IDENT sort_dir?
sort_dir: "asc"  -> sd_asc
        | "desc" -> sd_desc

auto_projection_item: auto_projection_kind auto_projection_option*
auto_projection_kind: "db"      -> apk_db
                    | "request" -> apk_request
                    | "reply"   -> apk_reply
                    | "event"   -> apk_event

auto_projection_option: exclude_option | on_option
exclude_option: "exclude" "[" auto_projection_exclusion ("," auto_projection_exclusion)* "]"
on_option: "on" "[" IDENT ("," IDENT)* "]"
auto_projection_exclusion: annotation | IDENT

access_block: "access" "{" access_item* "}"
access_item: entity_grant
           | property_grant
entity_grant: "entity" principal permission_list
property_grant: "property" IDENT principal permission_list
principal: PRINCIPAL
permission_list: "[" permission ("," permission)* "]"
permission: "read" -> p_read
          | "project" -> p_project
          | "subscribe" -> p_subscribe
          | "write" -> p_write
          | "transfer" -> p_transfer
          | "manage_access" -> p_manage_access
          | "derive" -> p_derive
          | "redact" -> p_redact

version_selector: "@" version_spec
dotted_ref: IDENT ("." IDENT)*

ignored_block_item: /[^{}]+/ | "{" ignored_block_item* "}"


// -- Lexing ------------------------------------------------------------------

VERSION_RANGE: /[<>~=^0-9.,\s]+/
EXPRESSION: /[^\n\r{}]+/
FIELD_EXPRESSION: /[^\n\r]+(?:\n(?!\s*(?:@|[A-Za-z_][A-Za-z0-9_-]*\s*(?:<-|=)|generate\s*\{|materialisation\s*\{|subscription\s*\{|access\s*\{|from\s|group\s+by|pick\s*\(|omit\s*\(|\{|\}))[^\n\r]+)*/
ANNOTATION_EXPR: /[^)\n\r{}]+/
CONSTRAINT_NUMBER: /-?[0-9]+(\.[0-9]+)?/
IDENT: /[A-Za-z_][A-Za-z0-9_-]*/
HASH: /[0-9A-Fa-f][0-9A-Fa-f_-]*/
PEERS_CONTENT: /[^\]]+/
PRINCIPAL: /\*|[A-Za-z_][A-Za-z0-9_.-]*/

COMMENT: /\/\/[^\n]*/
%import common.ESCAPED_STRING
%import common.INT
%import common.WS
%ignore WS
%ignore COMMENT

Rule index

Alphabetical listing of every named rule and its production.

Rule Production
access_block "access" "{" access_item* "}"
access_item entity_grant \| property_grant
add_operation "add" field_decl
ai_block "ai" "{" ai_item* "}"
ai_item ai_provider \| ai_model \| ai_repair_attempts
ai_model "model" ":" ESCAPED_STRING
ai_provider "provider" ":" ESCAPED_STRING
ai_repair_attempts "repair_attempts" ":" INT
annotation "@key" -> ann_key \| "@pii" -> ann_pii \| "@classification" "(" ESCAPED_STRING ")" -> ann_classification \| "@deprecated" "(" "replacedBy" ":" ESCAPED_STRING ")" -> ann_deprecated \| "@owner" "(" ESCAPED_STRING ")" -> ann_owner \| "@server" -> ann_server \| wire_annotation \| "@pitCutoff" "(" ANNOTATION_EXPR ")" -> ann_pit_cutoff \| "@latestBefore" "(" ANNOTATION_EXPR ")" -> ann_latest_before \| "@latestOnly" -> ann_latest_only \| "@custom" "(" (IDENT \| ESCAPED_STRING) ["," ANNOTATION_EXPR] ")" -> ann_custom
api_decl "api" IDENT "@" INT "{" api_operation* "}"
api_operation "operation" ESCAPED_STRING "{" api_operation_item* "}"
api_operation_item method_clause \| path_clause \| request_clause \| responses_block
array_type "array" "<" type_expr ">"
auto_projection_exclusion annotation \| IDENT
auto_projection_item auto_projection_kind auto_projection_option*
auto_projection_kind "db" -> apk_db \| "request" -> apk_request \| "reply" -> apk_reply \| "event" -> apk_event
auto_projection_option exclude_option \| on_option
auto_projections_decl "auto" "projections" IDENT "@" INT "{" auto_projection_item* "}"
binding_adapter_attr "adapter" ":" IDENT
binding_decl "binding" IDENT "{" binding_item* "}"
binding_item binding_adapter_attr \| binding_model_attr \| binding_table_attr \| ignored_block_item
binding_model_attr "model" ":" dotted_ref "@" INT
binding_table_attr "table" ":" ESCAPED_STRING
bool_literal "true" -> bl_true \| "false" -> bl_false
cardinality_attr "cardinality" ":" IDENT
change_kind "additive" -> ck_additive \| "breaking" -> ck_breaking
constraint_clause "constraint" "{" constraint_item ("," constraint_item)* "}" -> constraint_clause
constraint_item IDENT ":" constraint_value
constraint_value ESCAPED_STRING -> constraint_string \| CONSTRAINT_NUMBER -> constraint_number \| "true" -> constraint_true \| "false" -> constraint_false
consumer_decl "consumer" IDENT? "{" ignored_block_item* "}"
contact_attr "contact" ":" ESCAPED_STRING
db_dialect "postgres" -> dd_postgres \| "mysql" -> dd_mysql \| "clickhouse" -> dd_clickhouse \| "sqlite" -> dd_sqlite
decimal_type "decimal" "(" INT "," INT ")"
desc_attr "description" ":" ESCAPED_STRING
domain_decl "domain" domain_name "{" domain_item* "}"
domain_item owner_attr \| contact_attr \| desc_attr \| model_decl \| model_evolution_decl \| projection_decl \| enum_projection_decl \| auto_projections_decl \| api_decl \| generate_block \| semantic_decl \| index_decl
domain_name IDENT \| ESCAPED_STRING
dotted_ref IDENT ("." IDENT)*
entity_grant "entity" principal permission_list
enum_member IDENT \| NUMERIC_IDENT
enum_projection_decl "enum" "projection" IDENT semantic_header? "from" dotted_ref "@" INT pick_or_omit_clause
enum_ref_type dotted_ref "@" INT
enum_type "enum" "(" enum_member ("," enum_member)* ")"
evolution_item add_operation \| remove_operation \| rename_operation \| replace_operation \| access_block \| reservation_block
exclude_option "exclude" "[" auto_projection_exclusion ("," auto_projection_exclusion)* "]"
field_decl annotation* IDENT optional_marker? ":" type_expr nullable_marker? constraint_clause* field_default?
field_default "=" EXPRESSION
fixed_binary_type "binary" "(" INT ")"
generate_block "generate" "{" generate_target* "}"
generate_target target_name ("->" ESCAPED_STRING)?
group_clause "group" "by" group_item ("," group_item)*
http_method "GET" -> http_get \| "POST" -> http_post \| "PUT" -> http_put \| "PATCH" -> http_patch \| "DELETE" -> http_delete
ignored_block_item /[^{}]+/ \| "{" ignored_block_item* "}"
import_domain_stmt "import" "domain" dotted_ref import_source? pinned_import? version_selector?
import_source "from" "registry" ESCAPED_STRING
index_decl "index" IDENT "@" INT "{" index_item* "}"
index_item primary_index \| secondary_index
join_clause join_prefix annotation* \| join_prefix join_option*
join_modifier "left"
join_option annotation \| cardinality_attr
join_prefix "join" dotted_ref "@" version_spec "as" IDENT "on" EXPRESSION \| join_modifier "join" dotted_ref "@" version_spec "as" IDENT "on" EXPRESSION
key_item "key" ":" "[" IDENT ("," IDENT)* "]"
map_type "map" "<" type_expr "," type_expr ">"
materialisation_block "materialisation" "{" materialisation_item* "}"
materialisation_item IDENT ":" EXPRESSION
method_clause "method" ":" http_method
model_body_item field_decl \| access_block \| reservation_block
model_change "(" change_kind ")"
model_decl wire_annotation* model_kind IDENT model_header? "{" model_body_item* "}"
model_evolution_decl wire_annotation* model_kind IDENT "@" INT model_change? "evolves" "@" INT "{" evolution_item* "}"
model_header "@" INT model_change? \| model_change
model_kind "entity" -> mk_entity \| "aggregate" -> mk_aggregate \| "event" -> mk_event \| "value" -> mk_value
nullable_marker "?"
object_type "object" "{" field_decl* "}"
omit_clause "omit" "(" selector ("," selector)* ")"
on_option "on" "[" IDENT ("," IDENT)* "]"
optional_marker "?"
owner_attr "owner" ":" ESCAPED_STRING
package_block "package" ESCAPED_STRING "{" package_item* "}"
package_description_attr "description" ":" ESCAPED_STRING
package_include_attr "include" ":" "[" [ESCAPED_STRING ("," ESCAPED_STRING)*] "]"
package_item package_include_attr \| package_description_attr
path_clause "path" ":" ESCAPED_STRING
peers_block "peers" ":" "[" PEERS_CONTENT "]"
permission "read" -> p_read \| "project" -> p_project \| "subscribe" -> p_subscribe \| "write" -> p_write \| "transfer" -> p_transfer \| "manage_access" -> p_manage_access \| "derive" -> p_derive \| "redact" -> p_redact
permission_list "[" permission ("," permission)* "]"
pick_clause "pick" "(" selector ("," selector)* ")"
pick_or_omit_clause "pick" "(" enum_member ("," enum_member)* ")" -> pick_selection \| "omit" "(" enum_member ("," enum_member)* ")" -> omit_selection
pinned_import "at" dotted_ref "@" INT "#" IDENT
primary_index "primary" IDENT ("," IDENT)*
primitive_type "string" -> pt_string \| "int" -> pt_int \| "float" -> pt_float \| "bool" -> pt_bool \| "date" -> pt_date \| "time" -> pt_time \| "timestamp" -> pt_timestamp \| "uuid" ("(" INT ")")? -> pt_uuid \| "duration" -> pt_duration \| "binary" -> pt_binary \| "json" -> pt_json \| "u8" -> pt_u8 \| "u16" -> pt_u16 \| "u32" -> pt_u32 \| "u64" -> pt_u64 \| "u128" -> pt_u128 \| "i8" -> pt_i8 \| "i16" -> pt_i16 \| "i32" -> pt_i32 \| "i64" -> pt_i64 \| "i128" -> pt_i128
principal PRINCIPAL
proj_field annotation* IDENT "<-" qualified_field -> direct_field \| annotation* IDENT "=" FIELD_EXPRESSION -> computed_field
projection_body_item proj_field \| access_block \| subscription_block \| generate_block \| materialisation_block \| reservation_block
projection_decl wire_annotation* "projection" IDENT "@" INT projection_source_block? source_clause? selection_clause? "{" projection_body_item* "}"
projection_source_block "{" source_clause "}"
property_grant "property" IDENT principal permission_list
qualified_field IDENT "." IDENT
ref_type "ref" "<" dotted_ref ("@" version_spec)? ">"
registry_block "registry" "{" ignored_block_item* "}"
remove_operation "remove" IDENT
rename_operation "rename" IDENT "->" IDENT
replace_operation "replace" field_decl
request_clause "request" ":" dotted_ref "@" INT
reservation_block "reserved" "protobuf" "{" reservation_item* "}"
reservation_item reserved_numbers \| reserved_names
reserved_names "names" ":" "[" ESCAPED_STRING ("," ESCAPED_STRING)* "]"
reserved_numbers "numbers" ":" "[" INT ("," INT)* "]"
response_decl INT ":" dotted_ref "@" INT
responses_block "responses" "{" response_decl* "}"
secondary_index "secondary" IDENT "{" secondary_index_item* "}"
secondary_index_item key_item \| sort_item \| unique_item
selection_clause pick_clause \| omit_clause
selector qualified_field \| auto_projection_exclusion
semantic_body "{" semantic_item* "}"
semantic_change "(" change_kind ")"
semantic_decl "semantic" IDENT semantic_header? ":" type_expr semantic_body?
semantic_header "@" INT semantic_change?
semantic_item "registry" ":" bool_literal
sort_dir "asc" -> sd_asc \| "desc" -> sd_desc
sort_field IDENT sort_dir?
sort_item "sort" ":" "[" sort_field ("," sort_field)* "]"
source_clause "from" dotted_ref "@" version_spec "as" IDENT join_clause* where_clause? group_clause?
start statement+
statement domain_decl \| binding_decl \| workspace_decl \| import_domain_stmt \| projection_decl \| subscription_decl \| consumer_decl
subscription_block "subscription" "{" subscription_item* "}"
subscription_decl "subscription" IDENT "{" subscription_decl_item* "}"
subscription_decl_item IDENT ":" EXPRESSION
subscription_item IDENT ":" EXPRESSION
target_name "openapi" -> tn_openapi \| "typescript" -> tn_typescript \| "avro" -> tn_avro \| "protobuf" -> tn_protobuf \| "sql" "(" db_dialect ")" -> tn_sql \| "jsonschema" -> tn_jsonschema \| "asyncapi" -> tn_asyncapi \| "docs" -> tn_docs
type_expr primitive_type \| decimal_type \| fixed_binary_type \| enum_type \| array_type \| map_type \| ref_type \| object_type \| union_type \| enum_ref_type \| dotted_ref
union_type "union" "<" IDENT ">" "{" union_variant ("," union_variant)* "}"
union_variant IDENT ":" type_expr
unique_item "unique" ":" bool_literal
version_selector "@" version_spec
version_spec INT -> version_exact \| INT "#" HASH -> version_pinned \| ">=" INT "<" INT -> version_range \| ">=" INT -> version_min
where_clause "where" FIELD_EXPRESSION
wire_annotation "@wire" "(" wire_option ("," wire_option)* ")" -> ann_wire
wire_key IDENT ("." IDENT)?
wire_map "{" wire_map_item ("," wire_map_item)* "}"
wire_map_item IDENT ":" ESCAPED_STRING
wire_option wire_key ":" wire_value
wire_value ESCAPED_STRING -> wire_string \| wire_map
workspace_decl "workspace" workspace_label? "{" workspace_item* "}"
workspace_description_attr "description" ":" ESCAPED_STRING
workspace_item workspace_name_attr \| workspace_description_attr \| registry_block \| peers_block \| generate_block \| ai_block \| package_block
workspace_label IDENT \| ESCAPED_STRING
workspace_name_attr "name" ":" ESCAPED_STRING

Lexical rules

Regular-expression terminals used by the lexer.

Token Pattern
ANNOTATION_EXPR /[^)\n\r{}]+/
COMMENT /\/\/[^\n]*/
CONSTRAINT_NUMBER /-?[0-9]+(\.[0-9]+)?/
EXPRESSION /[^\n\r{}]+/
FIELD_EXPRESSION /[^\n\r]+(?:\n(?!\s*(?:@\|[A-Za-z_][A-Za-z0-9_-]*\s*(?:<-\|=)\|generate\s*\{\|materialisation\s*\{\|subscription\s*\{\|access\s*\{\|from\s\|group\s+by\|pick\s*\(\|omit\s*\(\|\{\|\}))[^\n\r]+)*/
HASH /[0-9A-Fa-f][0-9A-Fa-f_-]*/
IDENT /[A-Za-z_][A-Za-z0-9_-]*/
NUMERIC_IDENT /[0-9][A-Za-z0-9_-]*/
PEERS_CONTENT /[^\]]+/
PRINCIPAL /\*\|[A-Za-z_][A-Za-z0-9_.-]*/
VERSION_RANGE /[<>~=^0-9.,\s]+/
group_item /(?:[^,\n\r{}()]\|\([^()\n\r{}]*\))+/

Directives

Lark import and ignore directives.

  • %import common.ESCAPED_STRING
  • %import common.INT
  • %import common.WS
  • %ignore WS
  • %ignore COMMENT