%start stored_definition
%title "Modelica grammar"
%comment "Modelica grammar 3.7-dev for `parol`"
%line_comment "//"
%block_comment "/\*" "\*/"
%t_type crate::ir::ast::Token
%nt_type algorithm_section = crate::modelica_grammar::AlgorithmSection
%nt_type argument = crate::ir::ast::Expression
%nt_type argument_list = crate::modelica_grammar::ExpressionList
%nt_type arithmetic_expression = crate::ir::ast::Expression
%nt_type array_subscripts = crate::modelica_grammar::ArraySubscripts
%nt_type class_definition = crate::ir::ast::ClassDefinition
%nt_type component_list = crate::modelica_grammar::ComponentList
%nt_type component_reference = crate::ir::ast::ComponentReference
%nt_type component_ref_part = crate::ir::ast::ComponentRefPart
%nt_type composition = crate::modelica_grammar::Composition
%nt_type description_string = crate::modelica_grammar::TokenList
%nt_type element_list = crate::modelica_grammar::ElementList
%nt_type equation_block = crate::ir::ast::EquationBlock
%nt_type equation_section = crate::modelica_grammar::EquationSection
%nt_type expression = crate::ir::ast::Expression
%nt_type factor = crate::ir::ast::Expression
%nt_type function_call_args = crate::modelica_grammar::ExpressionList
%nt_type function_argument = crate::ir::ast::Expression
%nt_type function_arguments = crate::modelica_grammar::ExpressionList
%nt_type function_arguments_non_first = crate::modelica_grammar::ExpressionList
%nt_type ident = crate::ir::ast::Token
%nt_type logical_expression = crate::ir::ast::Expression
%nt_type logical_factor = crate::ir::ast::Expression
%nt_type logical_term = crate::ir::ast::Expression
%nt_type name = crate::ir::ast::Name
%nt_type output_expression_list = crate::modelica_grammar::ExpressionList
%nt_type primary = crate::ir::ast::Expression
%nt_type relation = crate::ir::ast::Expression
%nt_type simple_expression = crate::ir::ast::Expression
%nt_type some_equation = crate::ir::ast::Equation
%nt_type statement = crate::ir::ast::Statement
%nt_type statement_block = crate::ir::ast::StatementBlock
%nt_type stored_definition = crate::ir::ast::StoredDefinition
%nt_type string = crate::ir::ast::Token
%nt_type subscript = crate::ir::ast::Subscript
%nt_type term = crate::ir::ast::Expression
%nt_type unsigned_integer = crate::ir::ast::Token
%nt_type unsigned_real = crate::ir::ast::Token
%%
// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial
//=============================================================================
// 2.3.3 Modelica Keywords
algorithm
: 'algorithm'
;
and : 'and'
;
annotation
: 'annotation'
;
block
: 'block'
;
break
: 'break'
;
class
: 'class'
;
connect
: 'connect'
;
connector
: 'connector'
;
constant
: 'constant'
;
constrainedby
: 'constrainedby'
;
der : 'der'
;
discrete
: 'discrete'
;
each: 'each'
;
else: 'else'
;
elseif
: 'elseif'
;
elsewhen
: 'elsewhen'
;
encapsulated
: 'encapsulated'
;
end : 'end'
;
enumeration
: 'enumeration'
;
equation
: 'equation'
;
expandable
: 'expandable'
;
extends
: 'extends'
;
external
: 'external'
;
false
: 'false'
;
final
: 'final'
;
flow: 'flow'
;
for : 'for'
;
function
: 'function'
;
if : 'if'
;
import
: 'import'
;
impure
: 'impure'
;
in : 'in'
;
initial
: 'initial'
;
inner
: 'inner'
;
input
: 'input'
;
loop: 'loop'
;
model
: 'model'
;
not : 'not'
;
operator
: 'operator'
;
or : 'or'
;
outer
: 'outer'
;
output
: 'output'
;
package
: 'package'
;
parameter
: 'parameter'
;
partial
: 'partial'
;
protected
: 'protected'
;
public
: 'public'
;
pure: 'pure'
;
record
: 'record'
;
redeclare
: 'redeclare'
;
replaceable
: 'replaceable'
;
return
: 'return'
;
stream
: 'stream'
;
then: 'then'
;
true: 'true'
;
type: 'type'
;
when: 'when'
;
while
: 'while'
;
within
: 'within'
;
//=============================================================================
// A.1 Lexical conventions
// IDENT = NON-DIGIT { DIGIT | NON-DIGIT } | Q-IDENT
ident
: /[_a-zA-Z][_a-zA-Z0-9]*/@basic_ident
| /\'[_a-zA-Z0-9!#\$%&\(\)\*\+,-\.\/:;<>=\?@\[\]\^\{\}\|~ \"]*\'/@q_ident
;
// 🟨 IDENT = NON-DIGIT { DIGIT | NON-DIGIT } | Q-IDENT
// 🟨 Q-IDENT = "'" { Q-CHAR | S-ESCAPE } "'"
// ✅ NON-DIGIT = "_" | letters "a"..."z" | letters "A"..."Z"
// ✅ DIGIT = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
// ✅ Q-CHAR = NON-DIGIT | DIGIT | "!" | "#" | "$" | "%" | "&" | "(" | ")"
// | "*" | "+" s| "," | "-" | "." | "/" | ":" | ";" | "<" | ">" | "="
// | "?" | "@" | "[" | "]" | "^" | "{" | "}" | "|" | "~" | " " | """
// 🟥 S-ESCAPE = "\'" | "\"" | "\?" | "\\"
// | "\a" | "\b" | "\f" | "\n" | "\r" | "\t" | "\v"
// 🟨 STRING = """ { S-CHAR | S-ESCAPE } """ ;
string
: /"[' \w]*"/
;
// S-CHAR is any member of the Unicode character set
// (https://unicode.org; see section 13.4 for storing as UTF-8 on files)
// except double-quote ‘”’, and backslash ‘\’.
// UNSIGNED-INTEGER = DIGIT { DIGIT }
unsigned_integer
: /[0-9]+/
;
// UNSIGNED-REAL =
// UNSIGNED-INTEGER "." [ UNSIGNED-INTEGER ]
// | UNSIGNED_INTEGER [ "." [ UNSIGNED_INTEGER ] ]
// ( "e" | "E" ) [ "+" | "-" ] UNSIGNED-INTEGER
// | "." UNSIGNED-INTEGER [ ( "e" | "E" ) [ "+" | "-" ] UNSIGNED-INTEGER ]
unsigned_real
: /[0-9]+\.[0-9]+/@decimal
| /[0-9]+\.([0-9]+)?([eE][+-]?[0-9]+)?/@scientific
| /\.[0-9]+([eE][+-]?[0-9]+)?/@scientific2
;
//=============================================================================
// A.2.1 Stored Definition – Within
//✅ stored-definition :
//✅ [ within [ name ] ";" ]
//✅ { [ final ] class-definition ";" }
stored_definition
: [ within^ [ name ] ';'^ ] { [ final ] class_definition ';'^ }
;
//=============================================================================
// A.2.2 Class Definition
//✅ class-definition :
//✅ [ encapsulated ] class-prefixes class-specifier
class_definition
: [ encapsulated ] class_prefixes class_specifier
;
//✅ class-prefixes :
//✅ [ partial ]
//✅ ( class
//✅ | model
//✅ | [ operator ] record
//✅ | block
//✅ | [ expandable ] connector
//✅ | type
//✅ | package
//✅ | [ pure | impure ] [ operator ] function
//✅ | operator
//✅ )
class_type
: class
| model
| [ operator ] record
| block
| [ expandable ] connector
| type
| package
| [ pure | impure ] [ operator ] function
| operator
;
class_prefixes
: [ partial ] class_type
;
//✅ class-specifier :
//✅ long-class-specifier
//✅ | short-class-specifier
//✅ | der-class-specifier
class_specifier
: long_class_specifier
| short_class_specifier
| der_class_specifier
;
//✅ long-class-specifier :
//✅ IDENT description-string composition end IDENT
//✅ | extends IDENT [ class-modification ] description-string composition end IDENT
long_class_specifier
: standard_class_specifier
| extends_class_specifier
;
standard_class_specifier
: ident@name description_string composition end^ ident
;
extends_class_specifier
: extends^ ident [ class_modification ] description_string composition end^ ident
;
//✅ short-class-specifier :
//✅ IDENT "=" base-prefix type-specifier [ array-subscripts ]
//✅ [ class-modification ] description
//✅ | IDENT "=" enumeration "(" ( [ enum-list ] | ":" ) ")" description
short_class_specifier
: type_class_specifier
| enum_class_specifier
;
type_class_specifier
: ident '='^ base_prefix type_specifier [ array_subscripts ] [ class_modification ] description
;
enum_class_specifier
: ident '='^ enumeration '('^ ( [ enum_list ] | ':'^ ) ')'^ description
;
//✅ der-class-specifier :
//✅ IDENT "=" der "(" type-specifier "," IDENT { "," IDENT } ")" description
der_class_specifier
: ident '='^ der '('^ type_specifier ','^ ident { ','^ ident } ')'^ description
;
//✅ base-prefix :
//✅ [ input | output ]
base_prefix
: [ input | output ]
;
//✅ enum-list :
//✅ enumeration-literal { "," enumeration-literal }
enum_list
: enumeration_literal { ','^ enumeration_literal }
;
//✅ enumeration-literal :
//✅ IDENT description
enumeration_literal
: ident description
;
//✅ composition :
//✅ element-list
//✅ { public element-list
//✅ | protected element-list
//✅ | equation-section
//✅ | algorithm-section
//✅ }
//✅ [ external [ language-specification ]
//✅ [ external-function-call ] [ annotation-clause ] ";"
//✅ ]
//✅ [ annotation-clause ";" ]
composition
: element_list
{ public element_list | protected element_list | equation_section | algorithm_section }
[ external^ [ language_specification ] [ external_function_call ] [ annotation_clause ] ';'^ ]
[ annotation_clause ';'^ ]
;
//✅ language-specification :
//✅ STRING
language_specification
: string
;
//✅ external-function-call :
//✅ [ component-reference "=" ]
//✅ IDENT "(" [ expression-list ] ")"
external_function_call
: [ component_reference '='^ ] ident '('^ [ expression_list ] ')'^
;
//✅ element-list :
//✅ { element ";" }
element_list
: { element ';'^ }
;
//✅ element :
//✅ import-clause
//✅ | extends-clause
//✅ | [ redeclare ]
//✅ [ final ]
//✅ [ inner ] [ outer ]
//✅ ( class-definition
//✅ | component-clause
//✅ | replaceable ( class-definition | component-clause )
//✅ [ constraining-clause description ]
//✅ )
element
: import_clause
| extends_clause
| element_definition
| element_replaceable_definition
;
element_definition
: [ redeclare ] [ final ] [ inner ] [ outer ] ( class_definition | component_clause )
;
element_replaceable_definition
: replaceable ( class_definition | component_clause ) [ constraining_clause description ]
;
//✅ import-clause :
//✅ import
//✅ ( IDENT "=" name
//✅ | name [ ".*" | "." ( "*" | "{" import-list "}" ) ]
//✅ )
//✅ description
import_clause
: import ( ident '='^ name | name [ '.*' | '.' ( '*' | '{'^ import_list '}'^ ) ] ) description
;
//✅ import-list :
//✅ IDENT { "," IDENT }
import_list
: ident { ','^ ident }
;
//=============================================================================
// A.2.3 Extends
//✅ extends-clause :
//✅ extends type-specifier [ class-or-inheritance-modification ] [ annotation-clause ]
extends_clause
: extends^ type_specifier [ class_or_inheritance_modification ] [ annotation_clause ]
;
//✅ constraining-clause :
//✅ constrainedby type-specifier [ class-modification ]
constraining_clause
: constrainedby^ type_specifier [ class_modification ]
;
//✅ class-or-inheritance-modification :
//✅ "(" [ argument-or-inheritance-modification-list ] ")"
class_or_inheritance_modification
: '('^ [ argument_or_inheritance_modification_list ] ')'^
;
//✅ argument-or-inheritance-modification-list :
//✅ ( argument | inheritance-modification ) { "," ( argument | inheritance-modification ) }
argument_or_inheritance_modification_list
: ( argument | inheritance_modification ) { ','^ ( argument | inheritance_modification ) }
;
//✅ inheritance-modification :
//✅ break ( connect-equation | IDENT )
inheritance_modification
: break^ ( connect_equation | ident )
;
//-----------------------------------------------------------------------------
// A.2.4 Component Clause
//✅ component-clause :
//✅ type-prefix type-specifier [ array-subscripts ] component-list
component_clause
: type_prefix type_specifier [ array_subscripts ] component_list
;
//✅ type-prefix :
//✅ [ flow | stream ]
//✅ [ discrete | parameter | constant ]
//✅ [ input | output ]
type_prefix
: [ flow | stream ] [ discrete | parameter | constant ] [ input | output ]
;
//✅ component-list :
//✅ component-declaration { "," component-declaration }
component_list
: component_declaration { ','^ component_declaration }
;
//✅ component-declaration :
//✅ declaration [ condition-attribute ] description
component_declaration
: declaration [ condition_attribute ] description
;
//✅ condition-attribute :
//✅ if expression
condition_attribute
: if^ expression
;
//✅ declaration :
//✅ IDENT [ array-subscripts ] [ modification ]
declaration
: ident [ array_subscripts ] [ modification ]
;
//=============================================================================
// A.2.5 Modification
//✅ modification :
//✅ class-modification [ "=" modification-expression ]
//✅ | "=" modification-expression
modification
: class_modification [ '='^ modification_expression ]
| '='^ modification_expression
;
//✅ modification-expression :
//✅ expression
//✅ | break
modification_expression
: expression
| break
;
//✅ class-modification :
//✅ "(" [ argument-list ] ")"
class_modification
: '('^ [ argument_list ] ')'^
;
//✅ argument-list :
//✅ argument { "," argument }
argument_list
: argument { ','^ argument }
;
//✅ argument :
//✅ element-modification-or-replaceable
//✅ | element-redeclaration
argument
: element_modification_or_replaceable
| element_redeclaration
;
//✅ element-modification-or-replaceable :
//✅ [ each ] [ final ] ( element-modification | element-replaceable )
element_modification_or_replaceable
: [ each ] [ final ] ( element_modification | element_replaceable )
;
//✅ element-modification :
//✅ name [ modification ] description-string
element_modification
: name [ modification ] description_string
;
//✅ element-redeclaration :
//✅ redeclare [ each ] [ final ]
//✅ ( short-class-definition | component-clause1 | element-replaceable )
element_redeclaration
: redeclare [ each ] [ final ]
( short_class_definition | component_clause1 | element_replaceable )
;
//✅ element-replaceable :
//✅ replaceable ( short-class-definition | component-clause1 )
//✅ [ constraining-clause ]
element_replaceable
: replaceable ( short_class_definition | component_clause1 ) [ constraining_clause ]
;
//✅ component-clause1 :
//✅ type-prefix type-specifier component-declaration1
component_clause1
: type_prefix type_specifier component_declaration1
;
//✅ component-declaration1 :
//✅ declaration description
component_declaration1
: declaration description
;
//✅ short-class-definition :
//✅ class-prefixes short-class-specifier
short_class_definition
: class_prefixes short_class_specifier
;
//=============================================================================
// A.2.6 Equations
//✅ equation-section :
//✅ [ initial ] equation { some-equation ";" }
equation_section
: [ initial^ ] equation^ { some_equation ';'^ }
;
//✅ algorithm-section :
//✅ [ initial ] algorithm { statement ";" }
algorithm_section
: [ initial^ ] algorithm^ { statement ';'^ }
;
//✅ some-equation :
//✅ ( simple-expression "=" expression
//✅ | if-equation
//✅ | for-equation
//✅ | connect-equation
//✅ | when-equation
//🟥 | component-reference function-call-args
//✅ )
//✅ description
some_equation_option
: simple_equation
| if_equation
| for_equation
| connect_equation
| when_equation
;
// This also handles componet-reference function-call-args
// this is necessary otherwise, look-ahead is very large
// if rhs is not present, only a function call is allowed,
// this is checked in the parser, if rhs is present, then
// it is a standrd simple_equation
simple_equation
: simple_expression [ '='^ expression ]
;
some_equation
: some_equation_option description
;
//✅ statement :
//✅ ( component-reference ( ":=" expression | function-call-args )
//✅ | "(" output-expression-list ")" ":=" component-reference function-call-args
//✅ | break
//✅ | return
//✅ | if-statement
//✅ | for-statement
//✅ | while-statement
//✅ | when-statement
//✅ )
//✅ description
statement_option
: component_statement
| function_call_output_statement
| break
| return
| if_statement
| for_statement
| while_statement
| when_statement
;
component_statement
: component_reference ( ':='^ expression | function_call_args )
;
function_call_output_statement
: '('^ output_expression_list ')'^ ':='^ component_reference function_call_args
;
statement
: statement_option description
;
//✅ if-equation :
//✅ if expression then
//✅ { some-equation ";" }
//✅ { elseif expression then
//✅ { some-equation ";" }
//✅ }
//✅ [ else
//✅ { some-equation ";" }
//✅ ]
//✅ end if
equation_block
: expression then^ { some_equation ';'^ }
;
if_equation
: if^ equation_block@if { elseif^ equation_block@elseif } [ else^ { some_equation ';'^ } ] end^
if^
;
//✅ if-statement :
//✅ if expression then
//✅ { statement ";" }
//✅ { elseif expression then
//✅ { statement ";" }
//✅ }
//✅ [ else
//✅ { statement ";" }
//✅ ]
//✅ end if
statement_block
: expression then^ { statement ';'^ }
;
if_statement
: if^ statement_block@if { elseif^ statement_block@elseif } [ else^ { statement@else ';'^ } ]
end^ if^
;
//✅ for-equation :
//✅ for for-indices loop
//✅ { some-equation ";" }
//✅ end for
for_equation
: for^ for_indices loop^ { some_equation ';'^ } end^ for^
;
//✅ for-statement :
//✅ for for-indices loop
//✅ { statement ";" }
//✅ end for
for_statement
: for^ for_indices loop^ { statement ';'^ } end^ for^
;
//✅ for-indices :
//✅ for-index { "," for-index }
for_indices
: for_index { ','^ for_index }
;
//✅ for-index :
//✅ IDENT [ in expression ]
for_index
: ident [ in^ expression ]
;
//✅ while-statement :
//✅ while expression loop
//✅ { statement ";" }
//✅ end while
while_statement
: while^ expression loop^ { statement ';'^ } end^ while^
;
//✅ when-equation :
//✅ when expression then
//✅ { some-equation ";" }
//✅ { elsewhen expression then
//✅ { some-equation ";" }
//✅ }
//✅ end when
when_equation
: when^ equation_block@when { elsewhen^ equation_block@elsewhen } end^ when^
;
//✅ when-statement :
//✅ when expression then
//✅ { statement ";" }
//✅ { elsewhen expression then
//✅ { statement ";" }
//✅ }
//✅ end when
when_statement
: when^ statement_block@when { elsewhen^ statement_block@elsewhen } end^ when^
;
//✅ connect-equation :
//✅ connect "(" component-reference "," component-reference ")"
connect_equation
: connect^ '('^ component_reference ','^ component_reference ')'^
;
//=============================================================================
// A.2.7 Expressions
//✅ expression :
//✅ simple-expression
//✅ | if expression then expression
//✅ { elseif expression then expression }
//✅ else expression
expression
: simple_expression
| if_expression
;
if_expression
: if^ expression then^ expression { elseif^ expression then^ expression } else^ expression
;
//✅ simple-expression :
//✅ logical-expression [ ":" logical-expression [ ":" logical-expression ] ]
simple_expression
: logical_expression [ ':'^ logical_expression [ ':'^ logical_expression ] ]
;
//✅ logical-expression :
//✅ logical-term { or logical-term }
logical_expression
: logical_term { or^ logical_term }
;
//✅ logical-term :
//✅ logical-factor { and logical-factor }
logical_term
: logical_factor { and^ logical_factor }
;
//✅ logical-factor :
//✅ [ not ] relation
logical_factor
: [ not ] relation
;
//✅ relation :
//✅ arithmetic-expression [ relational-operator arithmetic-expression ]
relation
: arithmetic_expression [ relational_operator arithmetic_expression ]
;
//✅ relational-operator :
//✅ "<" | "<=" | ">" | ">=" | "==" | "<>"
relational_operator
: '<'
| '<='
| '>'
| '>='
| '=='
| '<>'
;
//✅ arithmetic-expression :
//✅ [ add-operator ] term { add-operator term }
arithmetic_expression
: [ add_operator ] term { add_operator term }
;
//✅ add-operator :
//✅ "+" | "-" | ".+" | ".-"
add_operator
: '+'
| '-'
| '.+'
| '.-'
;
//✅ term :
//✅ factor { mul-operator factor }
term: factor { mul_operator factor }
;
//✅ mul-operator :
//✅ "*" | "/" | ".*" | "./"
mul_operator
: '*'
| '/'
| '.*'
| './'
;
//✅ factor :
//✅ primary [ ( "^" | ".^" ) primary ]
factor
: primary { ( '^' | '.^' ) primary }
;
//✅ primary :
//✅ UNSIGNED-NUMBER
//✅ | STRING
//✅ | false
//✅ | true
//✅ | ( component-reference | der | initial | pure ) function-call-args
//✅ | component-reference
//✅ | "(" output-expression-list ")" [ ( array-subscripts | "." IDENT ) ]
//✅ | "[" expression-list { ";" expression-list } "]"
//✅ | "{" array-arguments "}"
//✅ | end
primary
: unsigned_number
| string
| false
| true
| global_function_call
| component_primary
| output_primary
| range_primary
| array_primary
| end
;
component_primary
: component_reference [ function_call_args ]
;
output_primary
: '('^ output_expression_list ')'^ [ ( array_subscripts | '.'^ ident ) ]
;
range_primary
: '['^ expression_list { ';'^ expression_list } ']'^
;
array_primary
: '{'^ array_arguments '}'^
;
global_function_call
: ( der | initial | pure ) function_call_args
;
//✅ UNSIGNED-NUMBER :
//✅ UNSIGNED-INTEGER | UNSIGNED-REAL
unsigned_number
: unsigned_integer
| unsigned_real
;
//✅ type-specifier :
//✅ ["."] name
type_specifier
: [ '.'^ ] name
;
//✅ name :
//✅ IDENT { "." IDENT }
name: ident { '.'^ ident }
;
//✅ component-reference :
//✅ [ "." ] IDENT [ array-subscripts ] { "." IDENT [ array-subscripts ] }
component_reference
: [ '.'^ ] ident [ array_subscripts ] { component_ref_part }
;
component_ref_part
: '.'^ ident [ array_subscripts ]
;
//✅ function-call-args :
//✅ "(" [ function-arguments ] ")"
function_call_args
: '('^ [ function_arguments ] ')'^
;
//✅ function-arguments :
//✅ expression [ "," function-arguments-non-first | for for-indices ]
//✅ | function-partial-application [ "," function-arguments-non-first ]
//✅ | named-arguments
function_arguments
: expression [ ','^ function_arguments_non_first | for for_indices ]
| function_partial_application [ ','^ function_arguments_non_first ]
| named_arguments
;
//✅ function-arguments-non-first :
//✅ function-argument [ "," function-arguments-non-first ]
//✅ | named-arguments
function_arguments_non_first
: function_argument [ ','^ function_arguments_non_first ]
| named_arguments
;
//✅ array-arguments :
//✅ expression [ "," array-arguments-non-first | for for-indices ]
array_arguments
: expression [ ','^ array_arguments_non_first | for for_indices ]
;
//✅ array-arguments-non-first :
//✅ expression [ "," array-arguments-non-first ]
array_arguments_non_first
: expression [ ','^ array_arguments_non_first ]
;
//✅ named-arguments: named-argument [ "," named-arguments ]
named_arguments
: named_argument [ ','^ named_arguments ]
;
//✅ named-argument: IDENT "=" function-argument
named_argument
: ident '='^ function_argument
;
//✅ function-argument :
//✅ function-partial-application | expression
function_argument
: function_partial_application
| expression
;
//✅ function-partial-application :
//✅ function type-specifier "(" [ named-arguments ] ")"
function_partial_application
: function type_specifier '('^ [ named_arguments ] ')'^
;
//✅ output-expression-list :
//✅ [ expression ] { "," [ expression ] }
output_expression_list
: [ expression ] { ','^ [ expression ] }
;
//✅ expression-list :
//✅ expression { "," expression }
expression_list
: expression { ','^ expression }
;
//✅ array-subscripts :
//✅ "[" subscript { "," subscript } "]"
array_subscripts
: '['^ subscript { ','^ subscript } ']'^
;
//✅ subscript :
//✅ ":" | expression
subscript
: ':'
| expression
;
//✅ description :
//✅ description-string [ annotation-clause ]
description
: description_string [ annotation_clause ]
;
//✅ description-string :
//✅ [ STRING { "+" STRING } ]
description_string
: [ string { '+'^ string } ]
;
//✅ annotation-clause :
//✅ annotation class-modification
annotation_clause
: annotation class_modification
;