program_expression
    : program_header declaration_sequence '\0'
    ;

module_header
    : 'module' module_identifier
    |
    ;

module_identifier
    : IDENTIFIER module_identifier_tail
    ;

module_identifier_tail
    : '.' IDENTIFIER module_identifier_tail
    |
    ;

import_headers
    : import_header
    |
    ;

import_header
    : import_statement import_header_suffix
    | from_statement import_header_suffix
    |
    ;

import_statement
    : 'import' import_identifier
    ;

import_header_suffix
    : TERMINATOR import_header_tail
    ;

import_header_tail
    : import_header import_header_suffix
    |
    ;

import_identifier
    : IDENTIFIER import_identifier_tail import_identifier_alias
    ;

import_identifier_tail
    | '.' IDENTIFIER import_identifier_tail
    |
    ;

import_identifier_alias
    : 'as' IDENTIFIER
    |
    ;

from_statement
    : 'from' from_identifier 'import' from_identifiers
    ;

from_identifier
    : IDENTIFIER from_identifier_tail
    ;

from_identifier_tail
    : '.' IDENTIFIER from_identifier_tail
    |
    ;

from_identifiers
    : '(' from_identifier_list ')'
    | from_identifier_list
    ;

from_identifier_list
    : IDENTIFIER import_identifier_alias from_identifier_list_tail
    |
    ;

from_identifier_list_tail
    : ',' from_identifier_list
    |
    ;

declaration_sequence
    : declaration declaration_sequence_tail
    |
    ;

declaration_sequence_tail
    : TERMINATOR declaration_sequence
    |
    ;

declaration
    : IDENTIFIER '=' declaration_literal
    ;

declaration_literal
    : function_literal
    | object_literal
    | lambda_literal
    | constant_expression
    ;

function_literal
    : '(' function_arguments ')' '->' expression
    ;

lambda_literal
    : lambda_argument '->' expression
    ;

constant_expression
    : expression
    ;

function_arguments
    : lambda_argument function_arguments_tail
    ;

function_arguments_tail
    : lambda_argument function_arguments_tail
    |
    ;

lambda_argument
    : IDENTIFIER
    ;

object_literal
    : 'object' object_header object_body
    ;

object_header
    : object_arguments
    | single_object_argument
    |
    ;

object_arguments
    : '(' object_arguments_list ')'
    ;

object_arguments_list
    : object_argument object_arguments_list
    |
    ;

single_object_argument
    : object_argument
    ;

object_argument
    : IDENTIFIER
    ;

object_body
    : '{' object_members '}'
    ;

object_members
    : object_member object_members_suffix
    |
    ;

object_members_suffix
    : TERMINATOR object_members_tail
    |
    ;

object_members_tail
    : object_member object_members_suffix
    |
    ;

object_member
    : object_member_name '=' declaration_literal
    ;

object_member_name
    : 'positive'
    | 'negative
    | IDENTIFIER
    | '+'
    | '-'
    | '*'
    | '/'
    | '%'
    | '<<'
    | '>>'
    | '>>>'
    | '?'
    | '[]'
    | '&'
    | '^'
    | '|'
    | '~'
    ;

expression
    : ternary_expression
    | logical_or_expression
    ;

ternary_expression
    : 'if' logical_or_expression 'then' expression 'else' ternary_expression_tail
    ;

ternary_expression_tail
    : ternary_expression
    | logical_or_expression
    ;

logical_or_expression
    : logical_and_expression logical_or_expression_tail
    ;

logical_or_expression_tail
    : OR_OPERATOR logical_and_expression logical_or_expression_tail
    |
    ;

OR_OPERATOR
    : '||'
    | 'or'
    ;

logical_and_expression
    : logical_not_expession logical_and_expression_tail
    ;

logical_and_expression_tail
    : AND_OPERATOR logical_not_expession logical_and_expression_tail
    |
    ;

AND_OPERATOR
    : '&&'
    | 'and'
    ;

logical_not_expession
    : 'not' equality_expression
    | equality_expression
    ;

equality_expression
    : shift_expression equality_expression_tail
    ;

equality_expression_tail
    : NOT_EQUALS_OPERATOR shift_expression equality_expression_tail
    | EQUALS_OPERATOR shift_expression equality_expression_tail
    | COMPARATIVE_OPERATOR shift_expression equality_expression_tail
    |
    ;

EQUALS_OPERATOR
    : '='
    | 'is'
    ;

NOT_EQUALS_OPERATOR
    : '<>'
    | 'is not'
    ;

COMPARATIVE_OPERATOR
    : '<'
    | '>'
    | '<='
    | '>='
    ;

shift_expression
    : coalesce_expression shift_expression_tail
    ;

shift_expression_tail
    : SHIFT_OPERATOR coalesce_expression shift_expression_tail
    |
    ;

SHIFT_OPERATOR
    : '<<'
    | '>>'
    | '>>>'
    ;

coalesce_expression
    : bitwise_xor_expression coalesce_expression_tail
    ;

coalesce_expression_tail
    : '?' bitwise_xor_expression coalesce_expression_tail
    |
    ;

bitwise_xor_expression
    : bitwise_or_expression bitwise_xor_expression_tail
    ;

bitwise_xor_expression_tail
    : '^' bitwise_or_expression bitwise_xor_expression_tail
    |
    ;

bitwise_or_expression
    : bitwise_and_expression bitwise_or_expression_tail
    ;

bitwise_or_expression_tail
    : '|' bitwise_and_expression bitwise_or_expression_tail
    |
    ;

bitwise_and_expression
    : additive_expression bitwise_and_expression_tail
    ;

bitwise_and_expression_tail
    : '&' additive_expression bitwise_expression_tail
    |
    ;

additive_expression
    : multiplicative_expression additive_expression_tail
    ;

additive_expression_tail
    : ADDITIVE_OPERATOR multiplicative_expression additive_expression_tail
    |
    ;

ADDITIVE_OPERATOR
    : '+'
    | '-'
    ;

multiplicative_expression
    : unary_expression multiplicative_expression_tail
    ;

multiplicative_expression_tail
    : MULTIPLICATIVE_OPERATOR unary_expression multiplicative_expression_tail
    | MODULUS_OPERATOR unary_expression multiplicative_expression_tail
    |
    ;

MULTIPLICATIVE_OPERATOR
    : '*'
    | '/'
    ;

MODULUS_OPERATOR
    : '%'
    | 'mod'
    ;

unary_expression
    : PREFIX_OPERATOR unary_expression
    | selector_expression
    ;

PREFIX_OPERATOR
    : '+'
    | '-'
    | '~'
    ;

selector_expression
    : primary_expression selector_expression_tail
    ;

selector_expression_tail
    : indexer_expression selector_expression_tail
    | accessor_expression selector_expression_tail
    | arguments_expression
    |
    ;

indexer_expression
    : '[' indexer_arguments ']'
    ;

indexer_arguments
    : indexer_argument indexer_arguments_suffix
    ;

indexer_arguments_suffix
    : ',' indexer_arguments_tail
    |
    ;

indexer_arguments_tail
    : indexer_argument indexer_arguments_suffix
    |
    ;

indexer_argument
    : expression
    ;

arguments_expression
    : argument arguments_expression_tail
    ;

arguments_expression_tail
    : argument arguments_expression_tail
    |
    ;

argument
    : primary_expression
    | apply_expression
    ;

apply_expression
    : '$' expression
    ;

accessor_expression
    : '.' IDENTIFIER
    ;

primary_expression
    : declaration_literal
    | parenthetical_expression
    | tuple_expression
    | list_expression
    | map_expression
    | java_expression
    | qualified_identifier
    | literal_expression
    ;

parenthetical_expression
    : '(' expression ')'
    ;

tuple_expression
    : '(' tuple_elements ')'
    ;

tuple_elements
    : tuple_element tuple_elements_suffix
    |
    ;

tuple_elements_suffix
    : ',' tuple_elements_tail
    |
    ;

tuple_elements_tail
    : tuple_element tuple_elements_suffix
    |
    ;

tuple_element
    : expression
    ;

list_expression
    : '[' list_elements ']'
    ;

list_elements
    : list_element list_elements_suffix
    |
    ;

list_elements_suffix
    : ',' list_elements_tail
    |
    ;

list_elements_tail
    : list_element list_elements_suffix
    |
    ;

list_element
    : expression
    ;

map_expression
    : '{' map_elements '}'
    ;

map_elements
    : map_element map_elements_suffix
    |
    ;

map_elements_suffix
    : ',' map_elements_tail
    |
    ;

map_elements_tail
    : map_element map_elements_suffix
    |
    ;

map_element
    : expression ':' expression
    ;

literal_expression
    : INTEGER
    | DOUBLE
    | BOOLEAN
    | CHARACTER
    | STRING
    | NOTHING
    ;

BOOLEAN: 'True' | 'False';
NOTHING: 'Nothing';

java_expression
    : 'java'
    ;

qualified_identifier
    : IDENTIFIER qualified_identifier_tail
    ;

qualified_identifier_tail
    : '.' IDENTIFIER qualified_identifier_tail
    |
    ;

IDENTIFIER
    : /[a-zA-Z_][0-9a-zA-Z_]*/
    ;

TERMINATOR
    : ';'
    | '\n'
    ;
