Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Part 5: Formal Grammar

source_file     ::= prelude_directive* program

prelude_directive ::= import_directive
                    | supported_targets
                    | target_if
                    | meta_diagnostic

import_directive ::= 'import' path_string
path_string     ::= 'p' STRING

supported_targets ::= '$supported_targets' '=' '[' STRING* ']'

target_if       ::= 'if' target_condition '{' prelude_directive* '}'
target_condition ::= '$target' ('=?' | 'not=?') STRING

meta_diagnostic ::= ('$warning' | '$error') '(' STRING ')'

program         ::= top_level_stmt*

top_level_stmt  ::= fn_decl
                  | const_decl
                  | ignored_type_decl

fn_decl         ::= ('let' | 'const') IDENT '=' '(' param_list ')' fn_type_annot '=>' (block | 'extern')

const_decl      ::= ('let' | 'const') IDENT type_annot '=' (const_expr | 'extern')

param_list      ::= (IDENT type_annot)*

fn_type_annot   ::= ':>' IDENT type_param?
                  | ':>' type_param
type_annot      ::= ':' IDENT type_param?
                  | type_param
type_param      ::= '<' type_content '>'

block           ::= '{' statement* '}'

statement       ::= var_decl
                  | ignored_type_decl
                  | assign_stmt
                  | if_stmt
                  | loop_stmt
                  | 'break'
                  | 'continue'
                  | return_stmt
                  | expr

var_decl        ::= ('let' | 'const') IDENT type_annot '=' expr

ignored_type_decl ::= IDENT ':type' '=' ignored_expr
                    | ('let' | 'const') IDENT ':type' '=' ignored_expr

assign_stmt     ::= IDENT '=' expr
                  | IDENT compound_op expr

compound_op     ::= '+=' | '-=' | '*=' | '//=' | '%=' 
                  | '<<=' | '>>=' | 'and=' | 'or=' | 'xor='

if_stmt         ::= 'if' expr block else_clause?
else_clause     ::= 'else' 'if' expr block else_clause?
                  | 'else' block

loop_stmt       ::= 'loop' expr block

return_stmt     ::= 'return' expr

expr            ::= prefix_expr (binop prefix_expr)* cast_annot?

prefix_expr     ::= '-' prefix_expr
                  | 'not' prefix_expr
                  | atom

atom            ::= NUMBER
                  | STRING
                  | BASED_STRING
                  | 'true'
                  | 'false'
                  | 'void'
                  | IDENT
                  | IDENT '(' arg_list ')'
                  | '(' expr ')' ('(' arg_list ')')?

arg_list        ::= expr*

cast_annot      ::= 'transmute' (IDENT type_param? | type_param)

ignored_expr    ::= a Dewy-compatible type expression or struct/type literal
                  # udewy consumes this syntax but does not evaluate it

binop           ::= '+' | '-' | '*' | '//' | '%'
                  | '<<' | '>>'
                  | '=?' | 'not=?' | '>?' | '<?' | '>=?' | '<=?'
                  | 'and' | 'or' | 'xor'

const_expr      ::= NUMBER | STRING | BASED_STRING | IDENT

# Lexical elements
IDENT           ::= [a-zA-Z_][a-zA-Z0-9_]*
NUMBER          ::= decimal | hex | binary
decimal         ::= [0-9][0-9_]*
hex             ::= '0x' [0-9a-fA-F_]+
binary          ::= '0b' [01_]+
STRING          ::= '"' string_char* '"'
string_char     ::= <any char except '"' or '\'>
                  | '\' <any char>
BASED_STRING    ::= ('0b' binary_string_body | '0x' hex_string_body)
binary_string_body ::= '"' ([01_] | whitespace | line_comment)* '"'
hex_string_body ::= '"' ([0-9a-fA-F_] | whitespace | line_comment)* '"'
line_comment    ::= '#' <characters through end of line>

NOTE: prelude_directive forms are consumed during preprocessing and do not appear in the token stream seen by the parser. The word import remains reserved, so any surviving import is rejected during tokenization.