Grammar

bedrock-lang grammar

# Program
program        = { item }
item           = import_def | function | proc_def | struct_def | enum_def | extern_def
               | var_def | const_def

import_def      = "import" IDENT { "." IDENT } ";"

# Generics
type_params     = "[" type_param { "," type_param } [ "," ] "]"
type_param      = IDENT

# Functions and Procedures
function        = [ "pub" ] [ "inline" ] "func" IDENT [ type_params ] "(" [ params ] ")" result block "end"
proc_def        = [ "pub" ] [ "inline" ] "proc" IDENT [ type_params ] "(" [ params ] ")" block "end"
result          = "->" type
params          = param { "," param } [ "," ]
param           = IDENT ":" [ "const" ] type
block           = { statement }

# Foreign Function Interface
extern_def      = "extern" ( "func" IDENT "(" [ extern_params ] ")" "->" type
                | "proc" IDENT "(" [ extern_params ] ")" ) ";"
extern_params   = extern_param { "," extern_param } [ "," "..." ]
                | "..."
extern_param    = IDENT ":" type

# Structs and Enums
struct_def      = [ "pub" ] "type" IDENT [ type_params ] "=" "struct" [ struct_members ] "end"

struct_literal  = ( IDENT | "_" ) "where" [ field_inits ] "end"
field_inits     = field_init { "," field_init } [ "," ]
field_init      = IDENT "=" expression

struct_members  = struct_member { struct_member }
struct_member   = struct_field ","
                | method_def
struct_field    = [ "pub" ] IDENT ":" type

method_def      = [ "pub" ] [ "inline" ] "func" IDENT [ type_params ] "(" [ params ] ")" result block "end"
                | [ "pub" ] [ "inline" ] "proc" IDENT [ type_params ] "(" [ params ] ")" block "end"

enum_def       = [ "pub" ] "type" IDENT [ type_params ] "=" "enum" [ enum_variants ] "end"
enum_variants  = enum_variant { "," enum_variant } [ "," ]
enum_variant   = IDENT [ "(" type_list ")" ]

# Statements
statement       = var_stmt | local_static_var_stmt | assign_stmt | defer_stmt
                | unsafe_stmt | control_flow_stmt | return_stmt | expr_stmt

var_stmt        = "var" IDENT [ ":" type ] "=" expression ";"
assign_stmt     = place_expr ( "=" | compound_op ) expression ";"

var_def  = [ "pub" ] "var" IDENT [ ":" type ] "=" expression ";"

# like c, does not change value in simultanous calls.
local_static_var_stmt = "static" "var" IDENT [ ":" type ] "=" expression ";"

const_def       = [ "pub" ] "const" IDENT [ ":" type ] "=" expression ";"

place_expr      = "*" "(" expression ")"
                | "*" IDENT
                | IDENT { ( "." IDENT ) | ( "[" expression "]") }
compound_op     = "+=" | "-=" | "*=" | "/=" | "%="
                | "&=" | "|=" | "^=" | "<<=" | ">>="

defer_stmt      = "defer" block "end"

unsafe_stmt     = "unsafe" block "end"

control_flow_stmt = control_flow_expr        # if/match/while/for used as a statement — no ";", it ends on "end"

return_stmt     = return_expr ";"            # return is statement-only, never nested inside an expression

expr_stmt       = expression ";"

comptime_expr      = "comptime" block "end"
control_flow_expr  = if_expr | match_expr | while_expr | for_expr
if_expr            = "if" expression block { elif_clause } [ else_clause ] "end"
elif_clause        = "elif" expression block
else_clause        = "else" block
return_expr        = "return" [ expression ]
for_expr           = "for" IDENT [ "," IDENT ] "in" expression [ "," additive ".." ] block "end"
while_expr         = "while" expression block "end"

# Match expression
match_expr      = "match" expression [ match_arms ] "end"
match_arms      = match_arm { match_arm } [ else_arm ]
match_arm       = "case" pattern block
else_arm        = "else" block

pattern         = literal_pattern | variant_pattern
literal_pattern = INTEGER | FLOAT | CHAR | STRING | BOOL
variant_pattern = IDENT [ "(" [ pattern_params ] ")" ]
pattern_params  = pattern { "," pattern } [ "," ]

expression      = orelse_expr
orelse_expr     = or_expr [ "orelse" expression ]
or_expr         = and_expr { "||" and_expr }
and_expr        = comparison { "&&" comparison }
comparison      = bitor_expr { ( "==" | "!=" | "<" | ">" | "<=" | ">=" ) bitor_expr }
bitor_expr      = bitxor_expr { "|" bitxor_expr }
bitxor_expr     = bitand_expr { "^" bitand_expr }
bitand_expr     = shift_expr { "&" shift_expr }
shift_expr      = range_expr { ( "<<" | ">>" ) range_expr }
range_expr      = additive [ ( ".." | "..=" ) additive ]
additive        = multiplicative { ( "+" | "-" ) multiplicative }
multiplicative  = unary { ( "*" | "/" | "%" ) unary }
unary           = ( "-" | "!" | "~" | "&" | "*" | "try" ) unary | postfix
postfix         = primary { suffix }
suffix          = "." IDENT
                | "(" [ call_args ] ")"
                | "[" expression { "," expression } [ "," ] "]" # handles both foo[index] and foo[type]
                | "?"

primary         = INTEGER | FLOAT | CHAR | STRING | BOOL | IDENT
                | control_flow_expr
                | comptime_expr
                | array_literal
                | struct_literal
                | "(" expression ")"

array_literal = "[" [ array_elems ] "]"
array_elems = expression { "," expression } [ "," ]

call_args       = call_arg { "," call_arg } [ "," ]
call_arg        = expression

type            = [ "?" ] base_type [ "!" ]

base_type       = "i8" | "i16" | "i32" | "i64"
                | "u8" | "u16" | "u32" | "u64"
                | "usize" | "isize"
                | "f32" | "f64"
                | "bool" | "char" | "str"
                | "*" type
                | array_type
                | slice_type
                | named_type
                | func_type
                | proc_type

array_type = "[" ( INTEGER | "_" ) "]" type
slice_type = "[" "]" type
named_type = IDENT [ "[" type { "," type } [ "," ] "]" ]

type_list  = type { "," type } [ "," ]
func_type  = "func" "(" [ type_list ] ")" result
proc_type  = "proc" "(" [ type_list ] ")"

# Lexical elements
INTEGER         = dec_literal | hex_literal | oct_literal | bin_literal
FLOAT           = dec_literal "." dec_literal
CHAR            = "'" ( char_char | escape ) "'"
char_char       = any character except "'" or "\"
dec_literal     = digit { digit | "_" }
hex_literal     = "0x" { hex_digit | "_" }
oct_literal     = "0o" { oct_digit | "_" }
bin_literal     = "0b" { bin_digit | "_" }
hex_digit       = digit | "a" | ... | "f" | "A" | ... | "F"
oct_digit       = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"
bin_digit       = "0" | "1"
STRING          = '"' { string_char | escape } '"'
escape          = "\\" ( "\\" | '"' | "n" | "t" | "r" | "0" )
BOOL            = "true" | "false"
letter          = "a" | ... | "z" | "A" | ... | "Z"
digit           = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
whitespace      = " " | "\t" | "\n" | "\r"
line_comment    = "//" { any_char_except_newline }