Grammar
This page presents the complete EBNF grammar for JAPL. The grammar uses the following conventions: { X } means zero or more X; [ X ] means optional X; ( X | Y ) means alternative; literal tokens are in double quotes.
Top-Level Program
program ::= { top_decl }
top_decl ::= module_decl
| import_decl
| type_decl
| fn_decl
| trait_decl
| impl_decl
| signature_decl
| supervisor_decl
| test_decl
| property_decl
| bench_decl
| foreign_decl
Module Declarations
module_decl ::= "module" module_path [ ":" signature_ref ] "=" module_body
| "module" module_path
module_path ::= TYPE_ID { "." TYPE_ID }
module_body ::= INDENT { module_item } DEDENT
module_item ::= type_decl | fn_decl | trait_decl | impl_decl
| module_decl | signature_decl
Import Declarations
import_decl ::= "import" module_path [ import_spec ]
import_spec ::= "." "{" import_item { "," import_item } "}"
import_item ::= IDENT | TYPE_ID
Type Declarations
type_decl ::= "type" TYPE_ID [ type_params ] [ deriving_clause ] "=" type_body
| "type" "alias" TYPE_ID [ type_params ] "=" type_expr
| "opaque" "type" TYPE_ID [ type_params ]
type_params ::= "[" type_var { "," type_var } "]"
type_var ::= IDENT
type_body ::= sum_type | record_type
sum_type ::= "|" constructor { "|" constructor }
constructor ::= TYPE_ID [ "(" type_expr { "," type_expr } ")" ]
record_type ::= "{" field_decl { "," field_decl } "}"
field_decl ::= IDENT ":" type_expr
deriving_clause ::= "deriving" "(" TYPE_ID { "," TYPE_ID } ")"
Function Declarations
fn_decl ::= "fn" IDENT [ type_params ] "(" [ param_list ] ")"
"->" type_expr [ effect_clause ] [ where_clause ]
"=" expr
param_list ::= param { "," param }
param ::= [ ownership_qual ] IDENT [ ":" type_expr ]
ownership_qual ::= "own" | "ref"
effect_clause ::= "with" effect { "," effect }
effect ::= "Pure" | "Io" | "Async" | "Net"
| "State" "[" type_expr "]"
| "Process" [ "[" type_expr "]" ]
| "Fail" "[" type_expr "]"
where_clause ::= "where" constraint { "," constraint }
constraint ::= TYPE_ID "[" type_expr { "," type_expr } "]"
Expressions
expr ::= let_expr
| use_expr
| match_expr
| if_expr
| fn_expr
| loop_expr
| pipe_expr
let_expr ::= "let" pattern "=" expr NEWLINE expr
use_expr ::= "use" IDENT "=" expr NEWLINE expr
match_expr ::= "match" expr "with" NEWLINE { match_arm }
match_arm ::= "|" pattern [ guard ] "->" expr NEWLINE
guard ::= "if" expr
if_expr ::= "if" expr "then" expr "else" expr
fn_expr ::= "fn" [ IDENT ] [ "(" [ param_list ] ")" ] "->" expr
| "fn" IDENT "->" expr
loop_expr ::= "loop" loop_bindings "while" expr "do" expr
loop_bindings ::= loop_binding { "," loop_binding }
loop_binding ::= IDENT "=" expr
Operator Precedence (Expressions)
pipe_expr ::= unary_expr { "|>" unary_expr }
unary_expr ::= compose_expr { ">>" compose_expr }
compose_expr ::= or_expr
or_expr ::= and_expr { "||" and_expr }
and_expr ::= cmp_expr { "&&" cmp_expr }
cmp_expr ::= add_expr [ cmp_op add_expr ]
cmp_op ::= "==" | "!=" | "<" | ">" | "<=" | ">="
add_expr ::= mul_expr { ("+" | "-" | "++" | "<>") mul_expr }
mul_expr ::= postfix_expr { ("*" | "/" | "%") postfix_expr }
postfix_expr ::= primary_expr { "?" | "." IDENT | "(" [ arg_list ] ")" }
arg_list ::= expr { "," expr }
Primary Expressions
primary_expr ::= IDENT
| TYPE_ID [ "(" [ arg_list ] ")" ]
| int_literal | float_literal | string_literal
| "True" | "False"
| "()"
| "(" expr ")"
| list_expr
| record_expr
| record_update
list_expr ::= "[" [ expr { "," expr } [ "," ".." expr ] ] "]"
record_expr ::= "{" field_assign { "," field_assign } "}"
field_assign ::= IDENT "=" expr
record_update ::= "{" expr "|" field_assign { "," field_assign } "}"
Patterns
pattern ::= constructor_pat
| record_pat
| literal_pat
| wildcard_pat
| var_pat
| list_pat
| pinned_pat
constructor_pat ::= TYPE_ID [ "(" pattern { "," pattern } ")" ]
record_pat ::= "{" field_pat { "," field_pat } "}"
field_pat ::= IDENT [ "=" pattern ]
literal_pat ::= int_literal | float_literal | string_literal
| "True" | "False" | "()"
wildcard_pat ::= "_"
var_pat ::= IDENT
list_pat ::= "[" [ pattern { "," pattern } [ "," ".." pattern ] ] "]"
pinned_pat ::= "^" IDENT
Type Expressions
type_expr ::= fn_type
| simple_type
fn_type ::= "fn" "(" [ type_expr { "," type_expr } ] ")"
"->" type_expr [ effect_clause ]
simple_type ::= named_type
| record_type_expr
| type_var
| "(" type_expr ")"
named_type ::= TYPE_ID [ "[" type_expr { "," type_expr } "]" ]
record_type_expr ::= "{" field_type { "," field_type } [ "|" type_var ] "}"
field_type ::= IDENT ":" type_expr
Trait Declarations
trait_decl ::= "trait" TYPE_ID "[" type_var { "," type_var } "]"
[ "where" constraint { "," constraint } ]
"=" INDENT { trait_member } DEDENT
trait_member ::= fn_signature
fn_signature ::= "fn" IDENT "(" [ param_list ] ")" "->" type_expr
[ effect_clause ]
Impl Declarations
impl_decl ::= "impl" TYPE_ID "[" type_expr { "," type_expr } "]"
"=" INDENT { fn_decl } DEDENT
Signature Declarations
signature_decl ::= "signature" TYPE_ID [ type_params ]
"=" INDENT { sig_member } DEDENT
sig_member ::= "type" TYPE_ID
| fn_signature
Supervisor Declarations
supervisor_decl ::= "supervisor" IDENT "=" INDENT supervisor_body DEDENT
supervisor_body ::= "strategy" "=" strategy_expr NEWLINE
"max_restarts" "=" int_literal NEWLINE
"max_seconds" "=" int_literal NEWLINE
"children" "=" "[" { child_spec "," } "]"
strategy_expr ::= "OneForOne" | "AllForOne" | "RestForOne"
child_spec ::= "{" "id" "=" string_literal ","
"start" "=" expr ","
"restart" "=" restart_type ","
"shutdown" "=" shutdown_expr "}"
restart_type ::= "Permanent" | "Transient" | "Temporary"
shutdown_expr ::= "Timeout" "(" int_literal ")" | "Brutal"
Test, Property, and Bench Declarations
test_decl ::= "test" string_literal "=" expr
property_decl ::= "property" string_literal "="
"forall" "(" param_list ")" "->" expr
bench_decl ::= "bench" string_literal "=" expr
Foreign Declarations
foreign_decl ::= "foreign" string_literal "fn" IDENT
"(" [ param_list ] ")" "->" type_expr
| "foreign" string_literal "module" string_literal
"=" INDENT { foreign_fn } DEDENT
foreign_fn ::= "fn" IDENT "(" [ param_list ] ")" "->" type_expr
Lexical Grammar
Identifiers
identifier ::= lower_start (alpha | digit | '_')*
type_identifier ::= upper_start (alpha | digit | '_')*
lower_start ::= 'a' .. 'z' | '_'
upper_start ::= 'A' .. 'Z'
Integer Literals
int_literal ::= decimal | hexadecimal | octal | binary
decimal ::= digit (digit | '_')*
hexadecimal ::= '0x' hex_digit (hex_digit | '_')*
octal ::= '0o' oct_digit (oct_digit | '_')*
binary ::= '0b' bin_digit (bin_digit | '_')*
Float Literals
float_literal ::= digit+ '.' digit+ exponent?
exponent ::= ('e' | 'E') ('+' | '-')? digit+
String Literals
string_literal ::= '"' string_char* '"'
string_char ::= <any UTF-8 char except '"' and '\'>
| escape_sequence
escape_sequence ::= '\\' | '\"' | '\n' | '\t' | '\r' | '\0'
| '\u{' hex_digit+ '}'
Comments
line_comment ::= '--' <any char>* NEWLINE
doc_comment ::= '---' <any char>* NEWLINE