title: Grammar description: Formal grammar reference for the Chasm language. keywords: ["chasm", "grammar", "syntax", "BNF", "EBNF", "reference"]
This page describes the complete syntax of Chasm using an informal BNF-style notation.
item*, zero or moreitem+, one or moreitem?, optional( A | B ), either A or B- Terminals are shown in
"double quotes"or italic - Non-terminals are shown in bold
Top Level
program = top_decl*
top_decl = import_decl
| defstruct_decl
| enum_decl
| extern_decl
| attr_decl
| fn_decl
Declarations
Import
import_decl = "import" IDENT
Struct
defstruct_decl = "defstruct" IDENT "do"
field_decl*
"end"
field_decl = IDENT "::" type ("=" expr)?
Enum
enum_decl = "enum" IDENT "{"
enum_variant ("," enum_variant)* ","?
"}"
enum_variant = IDENT ("(" type ")")?
Extern Function
extern_decl = "extern" "fn" IDENT "(" param_list? ")" "->" type
| "extern" "fn" IDENT "(" param_list? ")" "->" type "as" STRING
Module Attribute
attr_decl = "@" IDENT "::" lifetime ("=" expr)?
lifetime = "frame" | "script" | "persistent"
Function
fn_decl = ("def" | "defp") IDENT "(" param_list? ")" ("::" type)? "do"
stmt*
"end"
param_list = param ("," param)*
param = IDENT "::" type
Statements
stmt = var_decl
| assign
| attr_assign
| if_stmt
| while_stmt
| for_stmt
| return_stmt
| expr_stmt
var_decl = IDENT ("::" type)? "=" expr
| IDENT "::" lifetime "=" expr
assign = IDENT "=" expr
attr_assign = "@" IDENT "=" expr
if_stmt = "if" expr "do" stmt* "end"
| "if" expr "do" stmt* ("else" "do" stmt*)? "end"
while_stmt = "while" expr "do"
stmt*
"end"
for_stmt = "for" IDENT "in" expr "do"
stmt*
"end"
return_stmt = "return" expr?
expr_stmt = expr
Expressions
Expressions are listed from lowest to highest precedence.
expr = pipe_expr
pipe_expr = compare_expr ("|>" call_expr)*
compare_expr = logic_expr (("==" | "!=" | "<" | "<=" | ">" | ">=") logic_expr)?
logic_expr = add_expr (("and" | "or") add_expr)*
add_expr = mul_expr (("+" | "-") mul_expr)*
mul_expr = unary_expr (("*" | "/" | "%") unary_expr)*
unary_expr = ("!" | "-") unary_expr
| postfix_expr
postfix_expr = primary_expr (field_access | index_access | call_suffix)*
field_access = "." IDENT
index_access = "[" expr "]"
call_suffix = "." IDENT "(" arg_list? ")"
primary_expr = INT
| FLOAT
| STRING
| ATOM
| "true" | "false"
| IDENT
| "@" IDENT
| struct_lit
| with_expr
| case_expr
| "(" expr ")"
| call_expr
call_expr = IDENT "(" arg_list? ")"
| IDENT "." IDENT "(" arg_list? ")" # module call
arg_list = expr ("," expr)*
struct_lit = IDENT "{" field_init* "}"
| IDENT "{}"
field_init = IDENT ":" expr ("," field_init)?
with_expr = expr "with" "{" field_init* "}"
case_expr = "case" expr "do"
case_arm*
("_" "->" expr)?
"end"
case_arm = "when" expr "->" expr
Types
type = "int"
| "float"
| "bool"
| "string"
| "atom"
| "void"
| IDENT # struct or enum name
| "[" "]" IDENT # typed array: []Player
| "[" "]" type # typed array: []int
Literals
Integer
INT = [0-9]+
| "0x" [0-9a-fA-F]+
Integers are 64-bit signed values. Hex literals are commonly used for RGBA colors: 0xff0000ff.
Float
FLOAT = [0-9]+ "." [0-9]*
| [0-9]* "." [0-9]+
Floats are 64-bit IEEE 754 doubles.
String
STRING = '"' (char | interpolation)* '"'
interpolation = "#{" expr "}"
Strings are UTF-8. Interpolation embeds any expression: "x = #{@x}".
Atom
ATOM = ":" IDENT
Atoms are compile-time constant identifiers compared by identity: :menu, :playing, :dead.
Comments
comment = "#" .* newline
Comments run from # to the end of the line. There are no block comments.
Identifiers
IDENT = [a-zA-Z_] [a-zA-Z0-9_]*
Identifiers are case-sensitive. By convention:
- Local variables and function names use
snake_case - Struct and enum names use
PascalCase - Module attributes use
@snake_case
Keywords
The following words are reserved and cannot be used as identifiers:
and as atom bool break
case continue def defp defstruct
do else end enum extern
false float fn for if
import in int or persistent
return script string frame true
void when while with