Gramática sintática
Esta EBNF transcreve o parser da 0.2.0-alpha. Regras marcadas parcial são
reconhecidas pelo front-end, mas não prometem execução. { X } é repetição,
[ X ] é opcional e | indica alternativa.
Declarações
program = { NL }, { declaration, { NL } }, EOF ;
declaration = [ "pub" ], ( function | variable | struct | enum
| interface | trait | impl | type_alias | module | import
| export ) ;
export = "export", declaration ;
function = [ "extern" ], [ "async" ], "fn", identifier,
[ type_params ], parameters, [ "->", type ], block ;
parameters = "(", [ parameter, { ",", parameter } ], ")" ;
parameter = [ "mut" ], identifier, [ ":", type ] ;
type_params = "<", type_param, { ",", type_param }, ">" ;
type_param = identifier, [ ":", type, { "+", type } ] ;
variable = ("let" | "const" | "var"), [ "mut" ], identifier,
[ ":", type ], [ "=", expression ], terminator ;
struct = "struct", identifier, [ type_params ], "{", { field }, "}" ;
field = identifier, ":", type, [ "=", expression ],
( "," | terminator ) ;
enum = "enum", identifier, [ type_params ], "{",
{ enum_variant, [ "," ], { NL } }, "}" ;
enum_variant = identifier, [ "(", [ type, { ",", type } ], ")"
| "{", { identifier, ":", type, terminator }, "}" ] ;
interface = "interface", identifier, [ type_params ], "{",
{ signature }, "}" ;
trait = "trait", identifier, [ type_params ], "{",
{ signature }, "}" ;
signature = [ "async" ], "fn", identifier, [ type_params ],
parameters, [ "->", type ], terminator ;
impl = "impl", [ type_params ],
( identifier, [ "for", type ] | type ),
"{", { function | type_alias }, "}" ;
type_alias = "type", identifier, [ type_params ], "=", type, terminator ;
module = "mod", identifier, "{", { declaration }, "}" ;
import = "import", import_item, { ",", import_item }, terminator ;
import_item = path, [ "::", "*" ], [ "as", identifier ] ;
path = identifier, { "::", identifier } ;
terminator = [ ";" ], { NL } ;
priv está reservado; privacidade é implícita sem pub. extern fn ainda
exige corpo.
Statements
statement = block | if_stmt | while_stmt | for_stmt | loop_stmt
| match_stmt | switch_stmt | try_stmt | throw_stmt
| defer_stmt | yield_stmt | return_stmt | break_stmt
| continue_stmt | variable | expression, terminator ;
block = "{", { NL }, { statement, { NL } }, "}" ;
if_stmt = "if", expression, block,
{ "elif", expression, block },
[ "else", (if_stmt | block) ] ;
while_stmt = "while", expression, block ;
for_stmt = "for", pattern, "in", expression, block ;
loop_stmt = "loop", block ;
return_stmt = "return", [ expression ], terminator ;
break_stmt = "break", [ identifier ], terminator ;
continue_stmt = "continue", [ identifier ], terminator ;
match_stmt = "match", expression, match_arms ;
match_arms = "{", { pattern, [ "if", expression ], "=>",
(block | expression), [ "," ], { NL } }, "}" ;
switch_stmt = "switch", expression, "{", (* parcial *)
{ "case", expression, ":", block },
[ "default", ":", block ], "}" ;
try_stmt = "try", block, (* parcial *)
{ "catch", "(", [ identifier ], ")", block } ;
throw_stmt = "throw", expression, terminator ; (* parcial *)
defer_stmt = "defer", expression, terminator ; (* parcial *)
yield_stmt = "yield", [ expression ], terminator ; (* parcial *)
Rótulos após break/continue são analisados, mas laços rotulados não têm
sintaxe correspondente.
Expressões
Da menor para a maior precedência:
| Nível | Operadores | Associação |
|---|---|---|
| 1 | atribuições =, +=, -=, *=, /=, %=, **=, &=, ` | =, ^=, <<=, >>=` |
| 2 | ?: | direita |
| 3–4 | ` | |
| 5–7 | ` | , ^, &` |
| 8–9 | ==, !=, <, <=, >, >= | esquerda |
| 10–12 | <<, >>, +, -, *, /, % | esquerda |
| 13 | ** | direita |
| 14 | !, not, ~, -, await, ref, ref mut, * | direita |
| 15 | chamada, membro, índice, range, as, is | esquerda |
expression = assignment ;
assignment = conditional, [ assign_op, assignment ] ;
conditional = logical_or, [ "?", expression, ":", conditional ] ;
logical_or = logical_and, { ("||" | "or"), logical_and } ;
logical_and = bit_or, { ("&&" | "and"), bit_or } ;
bit_or = bit_xor, { "|", bit_xor } ;
bit_xor = bit_and, { "^", bit_and } ;
bit_and = equality, { "&", equality } ;
equality = relational, { ("==" | "!="), relational } ;
relational = shift, { ("<" | "<=" | ">" | ">="), shift } ;
shift = additive, { ("<<" | ">>"), additive } ;
additive = multiplicative, { ("+" | "-"), multiplicative } ;
multiplicative = power, { ("*" | "/" | "%"), power } ;
power = unary, [ "**", power ] ;
unary = ("!" | "not" | "~" | "-" | "await" | "ref" [ "mut" ] | "*"),
unary | postfix ;
postfix = primary, { "(", [ expression, { ",", expression } ], ")"
| ".", identifier | "[", expression, "]"
| "..", [ postfix ] | "as", type | "is", type } ;
primary = literal | identifier | "self" | "super"
| "(", [ expression, { ",", expression } ], ")"
| "[", [ expression | "...", expression,
{ ",", expression | "...", expression } ], "]"
| "{", object_or_block, "}" | lambda | anonymous_fn
| "match", expression, match_arms ;
lambda = [ "async" ], "|", [ parameter, { ",", parameter } ], "|",
(expression | block) ;
anonymous_fn = [ "async" ], "fn", parameters, [ "->", type ], block ;
Ranges e sua grafia inclusiva ainda são experimentais. Objetos usam
{ chave: valor }; a distinção entre objeto e bloco depende dos primeiros
tokens.
Patterns e tipos
pattern = primary_pattern, [ "|", pattern ] ;
primary_pattern = "_" | [ "mut" ], identifier, [ "@", pattern ]
| literal | "-", integer
| "(", [ pattern, { ",", pattern } ], ")"
| "[", [ pattern, { ",", pattern } ],
[ ",", "...", [ identifier ] ], "]"
| identifier, "::", identifier, [ pattern ]
| identifier, "{", { identifier, [ ":", pattern ],
[ "," ] }, "}" | "...", [ identifier ] ;
type = nullable_type, { "|", nullable_type } ;
nullable_type = primary_type, [ "?" ] ;
primary_type = path, [ "<", type, { ",", type }, ">" ],
[ "[", [ expression ], "]" ]
| "self"
| "fn", "(", [ type, { ",", type } ], ")", "->", type
| "(", ")", "->", type
| "(", type, "->", type
| "(", type, ",", type, { ",", type }, ")"
| "(", type, ")" ;