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
Previous Appendix