Formal Grammar
This page presents the formal grammar of Almide in Extended Backus-Naur Form (EBNF).
Program Structure
Section titled “Program Structure”program = import* decl*import = "import" path ("as" IDENT)? (* import json, import self as app *)decl = type_decl | fn_decl | protocol_decl | top_let | strict_decl | test_declDeclarations
Section titled “Declarations”protocol_decl = "protocol" IDENT "{" protocol_method* "}"protocol_method = "effect"? "fn" IDENT "(" params ")" "->" type
type_decl = "type" IDENT type_params? "=" type_body ("deriving" "From")?type_body = record_body | variant_body | typerecord_body = "{" field ("," field)* "}"variant_body= "|"? variant ("|" variant)*variant = IDENT | IDENT "(" type ("," type)* ")" | IDENT "{" field ("," field)* "}"
fn_decl = visibility? "effect"? "fn" IDENT type_params? "(" params ")" "->" type "=" exprvisibility = "local" | "mod" (* default is public *)
top_let = "let" IDENT (":" type)? "=" expr (* module-scope constant *)strict_decl = "strict" IDENT (* strict mode directive *)test_decl = "test" STRING blocktype = "Int" | "Float" | "String" | "Bool" | "Unit" | "Path" | IDENT | IDENT "[" type ("," type)* "]" (* generics use [] not <> *) | "(" type ("," type)+ ")" (* tuple type *) | "Fn" "(" type* ")" "->" type (* function type *)Expressions
Section titled “Expressions”expr = block | if_expr | match_expr | for_in | while_expr | fan_expr | guard | let | var | assign | binary | pipe | call | lambda | literal | range
block = "{" stmt* expr? "}"
if_expr = "if" expr "then" expr ("else" expr)? (* else is optional; omitting returns Unit *)
match_expr = "match" expr "{" arm ("," arm)* "}"arm = pattern ("if" expr)? "=>" expr (* optional guard *)
for_in = "for" (IDENT | "(" IDENT "," IDENT ")") "in" expr blockwhile_expr = "while" expr block (* condition-based loop *)fan_expr = "fan" "{" expr+ "}" (* concurrent execution *)
guard = "guard" expr "else" expr (* early exit / loop break *)
let = "let" IDENT (":" type)? "=" exprvar = "var" IDENT (":" type)? "=" exprassign = IDENT "=" expr
binary = expr OP expr (* OP: + - * / % ^ == != < > <= >= and or not >> *) (* + for string/list concat, ^ for power (right-assoc) *) (* not for boolean neg, >> for function composition *) (* comparison operators are non-associative: a < b < c is an error *) (* ** is accepted as an alias for ^ *)
pipe = expr "|>" expr (* pipe operator *)range = expr ".." expr | expr "..=" expr (* exclusive / inclusive range *)
call = expr "(" args ")" | expr "." IDENT "(" args ")" | expr "[" expr "]" (* index access *)
args = (expr | IDENT ":" expr) ("," (expr | IDENT ":" expr))* (* named args supported *)
lambda = "(" params ")" "=>" expr (* shorthand *) | "fn" "(" params ")" "=>" expr (* explicit *)Patterns
Section titled “Patterns”pattern = "_" | IDENT | LITERAL | "-" LITERAL (* negative numeric literals *) | "true" | "false" | "some" "(" pattern ")" | "none" | "ok" "(" pattern ")" | "err" "(" pattern ")" | TYPENAME "(" pattern ("," pattern)* ")" (* constructor *) | TYPENAME "{" field_pat ("," field_pat)* ("..")? "}" (* record *) | "(" pattern "," pattern ("," pattern)* ")" (* tuple *)Literals
Section titled “Literals”list_lit = "[" (expr ("," expr)*)? "]" (* [1, 2, 3] or [] *)
map_lit = "[" expr ":" expr ("," expr ":" expr)* "]" (* ["a": 1, "b": 2] *) | "[" ":" "]" (* empty map: [:] *)
literal = INT | FLOAT | STRING | SINGLE_STRING | "true" | "false" | "ok" "(" expr ")" | "err" "(" expr ")" | list_lit | map_lit | record_litString Literals
Section titled “String Literals”- Double-quote strings:
"hello ${name}"— interpolation via${expr}+ escape sequences - Single-quote strings:
'hello'— escape sequences only, no interpolation - Heredoc:
"""..."""— multiline, indent-stripped, interpolation supported - Raw heredoc:
r"""..."""— no escapes, no interpolation - Raw string:
r"..."— no escapes, no interpolation - Numeric literals support
_as a visual separator:1_000_000,0xFF
Lexical Elements
Section titled “Lexical Elements”Identifiers
Section titled “Identifiers”Identifier ::= [a-z_][a-zA-Z0-9_]*Name ::= Identifier | Identifier "?" (* ? suffix = Bool predicate *)TypeName ::= [A-Z][a-zA-Z0-9]*Keywords (42)
Section titled “Keywords (42)”module import type trait impl for in fnlet var if then else match ok errsome none todo unsafe true falsenot and or strict pub effect deriving testguard break continue while local modfanOperators and Delimiters
Section titled “Operators and Delimiters”Operators: + - * / % ^ == != < <= > >= |> .. ..=Unary: - notLogical: and orAssignment: =Arrows: -> =>Delimiters: ( ) { } [ ] , . : ; | _ @ ...Comments
Section titled “Comments”// line comment (to end of line)/* block comment (nestable) */Statement Separators
Section titled “Statement Separators”Newlines separate statements. Semicolons are used only to place multiple statements on a single line.
A newline is ignored (the statement continues) when:
The line ends with:
- Binary operators:
+,-,*,/,%,==,!=,<=,>=,<,>,and,or,|> - Delimiters:
,,.,: - Opening brackets:
(,{,[ - Arrows:
->,=> - Assignment:
= - Keywords:
if,then,else,match,not,|
The next line starts with:
.(method chaining)|>(pipe)
string,list,map,int,float,option,result,set,value,mathare auto-imported- No
return,class,null,!— use Almide alternatives (notfor negation) - Case-insensitive aliases:
Ok/ok,Err/err,Some/some,None/none - All errors via
Result[T, E], all optionals viaOption[T]