bnf! {
	Item {
		Module ::=
			"mod" id:name "\n"
				Item*:items
			"end" "\n";
		
		Proc ::=
			"proc" id:name [ProcParamList:params] "\n"
				Stmt+:code
			"end" "\n";
		
		Fn ::=
			"fn" id:name "(" FnParamList:params ")" ":" Type:ret "\n"
				Expr:expr
			"end" "\n";
		
		Use ::=
			"use" Path:path ["as" id:name] "\n";
	}
	
	Stmt {
		Skip ::= "skip" "\n";
		
		Xor ::= LValue:lval ":=" Expr:expr "\n";
		Add ::= LValue:lval "+=" Expr:expr "\n";
		Sub ::= LValue:lval "-=" Expr:expr "\n";
		
		Swap ::= LValue:left "<>" LValue:right "\n";
		
		Do   ::=   "do" id:name "(" { Expr:args "," } ")" "\n";
		Undo ::= "undo" id:name "(" { Expr:args "," } ")" "\n";
		
		Let ::=
			"let" id:name [":" Type:ty] ":=" Expr:init "\n"
				Stmt+:block
			"drop" id ":=" Expr:deinit "\n";
		
		If ::=
			"if" Expr:test "\n"
				Stmt+:block
			["else" "\n"
				Stmt+:else_block
			]
			"fi" Expr:assert "\n"
		
		From ::=
			"from" Expr:assert "\n"
				Stmt*:block
			"until" Expr:test "\n"
				Stmt*:loop_block
			"end" "\n";
	}
	
	Expr {
		Lit ::= Literal:lit;
		Lval ::= LValue:lval;
		
		Subexp ::= "(" Expr:expr ")";
		
		Neg ::= "-" Expr:expr;
		Not ::= "!" Expr:expr;
		
		Add ::= Expr:left {"+" Expr:rights};
		Mul ::= Expr:left {"*" Expr:rights};
		
		Sub ::= Expr:left "-" Expr:right;
		Div ::= Expr:left "/" Expr:right;
		Mod ::= Expr:left "%" Expr:right;
		Exp ::= Expr:left "^" Expr:right;
		
		Eq ::= Expr:left "=" Expr:right;
		Ne ::= Expr:left "!=" Expr:right;
		Lt ::= Expr:left "<" Expr:right;
		Le ::= Expr:left "<=" Expr:right;
		Gt ::= Expr:left ">" Expr:right;
		Ge ::= Expr:left ">=" Expr:right;
	}
}
