Language Grammar
This is the complete grammar specification for Adama in BNF-style notation. I won't pretend this is thrilling reading, but when you need to know the precise syntax for something -- "wait, does channel take brackets or parens here?" -- this is where you come.
Notation
| Symbol | Meaning |
|---|---|
::= |
Definition |
| |
Alternative |
[ ] |
Optional (zero or one) |
{ } |
Repetition (zero or more) |
( ) |
Grouping |
'text' |
Literal text |
CAPS |
Token from lexer |
lowercase |
Non-terminal |
Document Structure
document ::= { top_level_definition }
top_level_definition ::=
field_definition
| record_definition
| message_definition
| enum_definition
| table_definition
| channel_definition
| function_definition
| procedure_definition
| policy_definition
| event_handler
| state_definition
| cron_definition
| web_handler
| static_block
| include_directive
| service_definition
| test_definition
Include Directive
include_directive ::= '@include' IDENTIFIER { '/' IDENTIFIER } ';'
Field Definitions
field_definition ::=
[ privacy_modifier ] [ 'readonly' ] type_ref IDENTIFIER [ '=' expression ] ';'
| [ privacy_modifier ] 'formula' IDENTIFIER '=' expression ';'
| 'bubble' IDENTIFIER '=' expression ';'
| 'view' type_ref IDENTIFIER ';'
privacy_modifier ::=
'public'
| 'private'
| 'viewer_is' '<' IDENTIFIER '>'
| 'use_policy' '<' policy_list '>'
policy_list ::= IDENTIFIER { ',' IDENTIFIER }
Type Definitions
Records
record_definition ::=
'record' IDENTIFIER '{' { record_member } '}'
record_member ::=
field_definition
| method_definition
| policy_definition
| require_statement
| dispatch_definition
| index_definition
Messages
message_definition ::=
'message' IDENTIFIER '{' { message_member } '}'
message_member ::=
message_field
| index_definition
| method_definition
message_field ::= type_ref IDENTIFIER [ '=' expression ] ';'
Enums
enum_definition ::=
'enum' IDENTIFIER '{' enum_value_list '}'
enum_value_list ::= enum_value { ',' enum_value }
enum_value ::= IDENTIFIER [ '::' IDENTIFIER ]
Dispatch
dispatch_definition ::=
'dispatch' '<' IDENTIFIER '>' IDENTIFIER ';'
Tables
table_definition ::=
'table' '<' IDENTIFIER '>' IDENTIFIER ';'
Index Definition
The index directive appears inside records and messages to enable efficient table lookups on specific fields.
index_definition ::=
'index' IDENTIFIER ';'
Type References
type_ref ::=
primitive_type
| 'maybe' '<' type_ref '>'
| 'list' '<' type_ref '>'
| 'map' '<' type_ref ',' type_ref '>'
| 'table' '<' IDENTIFIER '>'
| 'channel' '<' IDENTIFIER '>'
| 'future' '<' type_ref '>'
| 'result' '<' type_ref '>'
| type_ref '[' ']'
| IDENTIFIER
primitive_type ::=
'int'
| 'long'
| 'double'
| 'bool'
| 'string'
| 'complex'
| 'date'
| 'time'
| 'datetime'
| 'timespan'
| 'principal'
| 'asset'
| 'label'
| 'dynamic'
| 'json'
| 'vec2'
| 'vec3'
| 'vec4'
| 'mat2'
| 'mat3'
| 'mat4'
| 'math4'
Functions and Procedures
function_definition ::=
'function' IDENTIFIER '(' [ parameter_list ] ')' '->' type_ref block
procedure_definition ::=
'procedure' IDENTIFIER '(' [ parameter_list ] ')' [ '->' type_ref ] [ 'readonly' ] [ 'aborts' ] block
method_definition ::=
'method' IDENTIFIER '(' [ parameter_list ] ')' [ '->' type_ref ] [ 'readonly' ] [ 'aborts' ] block
parameter_list ::= parameter { ',' parameter }
parameter ::= type_ref IDENTIFIER
Channels
channel_definition ::=
'channel' IDENTIFIER '(' [ channel_params ] ')' [ 'open' ] block
| 'channel' '<' IDENTIFIER [ '[' ']' ] '>' IDENTIFIER ';'
channel_params ::=
'principal' IDENTIFIER ',' IDENTIFIER IDENTIFIER
| IDENTIFIER IDENTIFIER
| IDENTIFIER '[' ']' IDENTIFIER
Policies
policy_definition ::=
'policy' IDENTIFIER block
require_statement ::=
'require' IDENTIFIER ';'
Event Handlers
event_handler ::=
'@construct' block
| '@connected' block
| '@disconnected' block
| '@delete' block
| '@load' block
| '@can_attach' block
| '@attached' '(' IDENTIFIER IDENTIFIER ')' block
| '@authorize' '(' IDENTIFIER ',' IDENTIFIER ')' block
| '@password' '(' IDENTIFIER ',' IDENTIFIER ')' block
State Machines
state_definition ::=
'#' IDENTIFIER block
transition_statement ::=
'transition' label_expression [ 'in' expression ] ';'
invoke_statement ::=
'invoke' label_expression ';'
label_expression ::=
'#' IDENTIFIER
| '#'
| IDENTIFIER
| '(' expression '?' label_expression ':' label_expression ')'
Scheduled Tasks
cron_definition ::=
'@cron' IDENTIFIER cron_schedule block
cron_schedule ::=
'daily' ( TIME_LITERAL | IDENTIFIER )
| 'hourly' ( INTEGER_LITERAL | IDENTIFIER )
| 'monthly' ( INTEGER_LITERAL | IDENTIFIER )
Web Handlers
web_handler ::=
'@web' web_method web_path [ '(' web_params ')' ] block
web_method ::= 'get' | 'put' | 'post' | 'delete' | 'options'
web_path ::= { web_path_segment }
web_path_segment ::=
'/' IDENTIFIER
| '/' '$' IDENTIFIER
web_params ::=
parameter_list
| IDENTIFIER IDENTIFIER
Static Block
static_block ::=
'@static' '{' { static_member } '}'
static_member ::=
'create' block
| 'invent' block
| 'maximum_history' '=' INTEGER_LITERAL ';'
| 'delete_on_close' '=' BOOLEAN_LITERAL ';'
Services
service_definition ::=
'service' IDENTIFIER '{' { service_member } '}'
service_member ::=
'internal' '=' STRING_LITERAL ';'
| 'method' '<' IDENTIFIER ',' IDENTIFIER '>' IDENTIFIER ';'
Tests
test_definition ::=
'test' IDENTIFIER block
Statements
block ::= '{' { statement } '}'
statement ::=
variable_declaration
| assignment_statement
| expression_statement
| if_statement
| switch_statement
| for_statement
| foreach_statement
| while_statement
| do_while_statement
| return_statement
| break_statement
| continue_statement
| abort_statement
| transition_statement
| invoke_statement
| block
| table_operation
| assert_statement
| log_statement
| test_directive
Variable Declaration
variable_declaration ::=
[ 'readonly' ] type_ref IDENTIFIER [ '=' expression ] ';'
| ( 'auto' | 'let' ) IDENTIFIER '=' expression ';'
Assignment
assignment_statement ::=
lvalue assignment_op expression ';'
| lvalue ( '++' | '--' ) ';'
| ( '++' | '--' ) lvalue ';'
assignment_op ::= '=' | '+=' | '-=' | '*='
lvalue ::=
IDENTIFIER
| lvalue '.' IDENTIFIER
| lvalue '[' expression ']'
Control Flow
if_statement ::=
'if' '(' condition ')' block [ 'else' ( if_statement | block ) ]
condition ::=
expression
| expression 'as' IDENTIFIER
switch_statement ::=
'switch' '(' expression ')' '{' { case_clause } [ default_clause ] '}'
case_clause ::=
'case' case_pattern ':' { statement }
case_pattern ::=
literal
| IDENTIFIER '::' IDENTIFIER [ '*' ]
default_clause ::=
'default' ':' { statement }
Loops
for_statement ::=
'for' '(' [ for_init ] ';' [ expression ] ';' [ for_update ] ')' block
for_init ::=
variable_declaration
| assignment_statement
for_update ::=
assignment_statement
| expression
foreach_statement ::=
'foreach' '(' IDENTIFIER 'in' expression ')' block
while_statement ::=
'while' '(' expression ')' block
do_while_statement ::=
'do' block 'while' '(' expression ')' ';'
Other Statements
return_statement ::= 'return' [ expression ] ';'
break_statement ::= 'break' ';'
continue_statement ::= 'continue' ';'
abort_statement ::= 'abort' ';'
expression_statement ::= expression ';'
Table Operations
table_operation ::=
table_ref '<-' expression ';'
table_ref ::= IDENTIFIER | '_' IDENTIFIER
Test Directives
test_directive ::=
'@step' ';'
| '@pump' anonymous_message 'into' IDENTIFIER ';'
| '@forward' expression ';'
| '@send' IDENTIFIER '(' expression ',' expression ')' ';'
| '@aborts' block
assert_statement ::= 'assert' expression ';'
log_statement ::= 'log' expression ';'
Expressions
expression ::= ternary_expression
ternary_expression ::=
or_expression [ '?' expression ':' expression ]
or_expression ::= and_expression { '||' and_expression }
and_expression ::= equality_expression { '&&' equality_expression }
equality_expression ::= relational_expression { ( '==' | '!=' ) relational_expression }
relational_expression ::= additive_expression { ( '<' | '<=' | '>' | '>=' | '=?' ) additive_expression }
additive_expression ::= multiplicative_expression { ( '+' | '-' ) multiplicative_expression }
multiplicative_expression ::= unary_expression { ( '*' | '/' | '%' ) unary_expression }
unary_expression ::=
( '!' | '-' | '++' | '--' ) unary_expression
| postfix_expression
postfix_expression ::=
primary_expression { postfix_op }
postfix_op ::=
'.' IDENTIFIER
| '.' IDENTIFIER '(' [ argument_list ] ')'
| '[' expression ']'
| '(' [ argument_list ] ')'
| '++' | '--'
Primary Expressions
primary_expression ::=
literal
| IDENTIFIER
| at_constant
| '(' expression ')'
| anonymous_message
| array_literal
| lambda_expression
| query_expression
| convert_expression
literal ::=
INTEGER_LITERAL
| LONG_LITERAL
| DOUBLE_LITERAL
| STRING_LITERAL
| BOOLEAN_LITERAL
| '#' IDENTIFIER
| '#'
at_constant ::=
'@who'
| '@no_one'
| '@nothing'
| '@blocked'
| '@web'
| '@context'
| '@headers'
| '@parameters'
| '@viewer'
| '@date' '(' expression ',' expression ',' expression ')'
| '@time' '(' expression ',' expression ')'
| '@datetime' '(' expression ')'
| '@timespan' '(' expression ')'
| '@maybe' '(' expression ')'
| '@c' '(' expression ',' expression ')'
| '@vec' '(' expression_list ')'
| '@dynamic' '(' expression ')'
| '@convert' '<' type_ref '>' '(' expression ')'
Collection Expressions
anonymous_message ::= '{' [ field_init_list ] '}'
field_init_list ::= field_init { ',' field_init }
field_init ::= IDENTIFIER ':' expression
array_literal ::= '[' [ expression_list ] ']'
expression_list ::= expression { ',' expression }
argument_list ::= expression_list
lambda_expression ::= IDENTIFIER '->' expression
Query Expressions
query_expression ::=
'iterate' table_ref [ query_clause_list ]
query_clause_list ::= { query_clause }
query_clause ::=
'where' expression
| 'order' 'by' order_by_list [ 'asc' | 'desc' ]
| 'order_dyn' expression
| 'shuffle'
| 'limit' expression
| 'offset' expression
order_by_list ::= order_by_field { ',' order_by_field }
order_by_field ::= IDENTIFIER [ 'asc' | 'desc' ]
Type Conversion
convert_expression ::= '@convert' '<' type_ref '>' '(' expression ')'
Lexical Elements
Identifiers
IDENTIFIER ::= letter { letter | digit | '_' }
letter ::= 'a'..'z' | 'A'..'Z' | '_'
digit ::= '0'..'9'
Literals
INTEGER_LITERAL ::= digit { digit } | '0x' hex_digit { hex_digit }
LONG_LITERAL ::= INTEGER_LITERAL 'L'
DOUBLE_LITERAL ::= digit { digit } '.' digit { digit } [ exponent ]
| digit { digit } exponent
exponent ::= ( 'e' | 'E' ) [ '+' | '-' ] digit { digit }
STRING_LITERAL ::= '"' { string_char } '"'
string_char ::= any_char_except_quote_or_backslash | escape_sequence
escape_sequence ::= '\' ( 'n' | 't' | 'r' | '\' | '"' | '0' )
BOOLEAN_LITERAL ::= 'true' | 'false'
TIME_LITERAL ::= digit digit ':' digit digit
hex_digit ::= digit | 'a'..'f' | 'A'..'F'
Comments
single_line_comment ::= '//' { any_char } newline
multi_line_comment ::= '/*' { any_char } '*/'
Keywords
The following identifiers are reserved:
abort as assert asset auto
bool break bubble case channel
complex continue create cron daily
date datetime default delete dispatch
do double else enum false
fetch for foreach formula function
future get hourly if in
index int invent invoke iterate
json label let limit list
long map mat2 mat3 mat4
math4 maybe message method monthly
offset open options order order_dyn
policy post principal private procedure
public put readonly record require
result return service shuffle string
switch table test time timespan
transition true use_policy vec2 vec3
vec4 view viewer_is where while
Reserved @ Keywords
@attached @authorize @blocked @c
@can_attach @connected @construct @context
@convert @cron @date @datetime
@delete @disconnected @dynamic @forward
@headers @include @load @maybe
@no_one @nothing @parameters @password
@pump @send @static @step
@time @timespan @vec @viewer
@web @who