# Syntax: A Casual and Formal Look ... ## A Formal Look We now shall take a look at a more formal description of Puck's syntax. Syntax rules are described in extended Backus–Naur form (EBNF) - but most rules surrounding whitespace, and scope, and line breaks, are modified to how they would appear after a lexing step (whitespace is removed, line breaks are normalized, scope is switched to use `{` and `}`). ### Identifiers ``` IDENT ::= LETTER (LETTER | DIGIT | '_')* LETTER ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff' # todo DIGIT ::= '0'..'9' ``` ### Literals ``` INT_LIT ::= '-'? (DEC_LIT | HEX_LIT | OCT_LIT | BIN_LIT) BIN_LIT ::= '0b' BIN_DIGIT ('_'? BIN_DIGIT)* OCT_LIT ::= '0o' OCT_DIGIT ('_'? OCT_DIGIT)* HEX_LIT ::= '0x' HEX_DIGIT ('_'? HEX_DIGIT)* DEC_LIT ::= DIGIT ('_'? DIGIT)* BIN_DIGIT ::= '0'..'1' OCT_DIGIT ::= '0'..'7' HEX_DIGIT ::= DIGIT | 'A'..'F' | 'a'..'f' ``` ### Operators ``` OPERATOR ::= 'and' | 'or' | 'not' | 'xor' | 'shl' | 'shr' | # todo: more? 'div' | 'mod' | 'rem' | 'is' | 'isnot' | OPR+ OPR ::= '=' | '+' | '-' | '*' | '/' | '<' | '>' | # todo: more? '@' | '$' | '~' | '&' | '%' | '|' | '!' | '?' | '^' | '.' | ':' | '\\' ``` ### Chars, Strings, and Comments ``` CHAR ::= '\'' (PRINT - '\'' | '\\\'')* '\'' STRING ::= SINGLE_LINE_STRING | MULTI_LINE_STRING COMMENT ::= SINGLE_LINE_COMMENT | MULTI_LINE_COMMENT | EXPRESSION_COMMENT SINGLE_LINE_STRING ::= '"' (PRINT - '"' | '\\"')* '"' MULTI_LINE_STRING ::= '"""' (PRINT | '\n' | '\r')* '"""' SINGLE_LINE_COMMENT ::= '#' PRINT* MULTI_LINE_COMMENT ::= '#[' (PRINT | '\n' | '\r' | MULTI_LINE_COMMENT)* ']#' EXPRESSION_COMMENT ::= '#;' SINGLE_STMT PRINT ::= LETTER | DIGIT | OPR | '"' | '#' | "'" | '(' | ')' | # notably the dual of OPR ',' | ';' | '[' | ']' | '_' | '`' | '{' | '}' | ' ' | '\t' ``` ### Values ``` VALUE ::= INT_LIT | STRING | CHAR | LIST_DECL ::= '[' (EXPR (',' EXPR)*)? ']' ARRAY_DECL ::= '[' (EXPR (',' EXPR)*)? ']' TUPLE_DECL ::= '(' (IDENT '=')? EXPR (',' (IDENT '=')? EXPR)* ')' STRUCT_DECL ::= '{' IDENT '=' EXPR (',' IDENT '=' EXPR)* '}' # note: no union or enum. should struct exist? only in a structural system. ``` ### Variables ``` DECL ::= LET_DECL | VAR_DECL | CONST_DECL LET_DECL ::= 'let' GROUP (':' TYPE_DESC)? '=' EXPR VAR_DECL ::= 'var' GROUP (':' TYPE_DESC)? ('=' EXPR)? CONST_DECL ::= 'pub'? 'const' GROUP (':' TYPE_DESC)? '=' EXPR GROUP ::= ('(' IDENT (',' IDENT)* ')') | IDENT ``` ## Types and Functions ``` FUNC_DECL ::= SIGNATURE '=' (EXPR | STMT) SIGNATURE ::= 'pub'? ('pure' | 'yeet' | IDENT)? 'func' IDENT ('(' (PARAMETER (',' PARAMETER)?)? ')')? (':' TYPE_DESC)? PARAMETER ::= (IDENT (':' ('var' | 'static')? TYPE_DESC)? ``` ``` TYPE_DECL ::= 'pub'? 'type' IDENT '=' 'ref'? 'distinct'? TYPE_DESC TYPE_DESC ::= TUPLE_TYPE | STRUCT_TYPE | UNION_TYPE | ENUM_TYPE | INTERFACE | IDENT TUPLE_TYPE ::= 'tuple' '[' (IDENT ':')? TYPE_DESC (',' (IDENT ':')? TYPE_DESC)* ']' STRUCT_TYPE ::= 'struct' '[' 'pub'? IDENT ':' TYPE_DESC' (',' 'pub'? IDENT ':' 'TYPE_DESC')* ']' # note: pub in structs conflicts w/ a structural system UNION_TYPE ::= 'union' '[' IDENT ':' TYPE_DESC' (',' IDENT ':' 'TYPE_DESC')* ']' ENUM_TYPE ::= 'enum' '[' IDENT ('=' EXPR)? (',' IDENT ('=' EXPR)?)* ']' FUNC_TYPE ::= 'func' ('(' (PARAMETER (',' PARAMETER)?)? ')')? (':' TYPE_DESC)? INTERFACE ::= 'interface' '[' SIGNATURE (',' SIGNATURE)* ('for' TYPE_DESC)? ']' ``` ## Control Flow ``` IF_EXPR ::= 'if' EXPR ':' EXPR ('elif' EXPR ':' EXPR)* 'else' ':' EXPR IF_STMT ::= 'if' EXPR ':' STMT ('elif' EXPR ':' STMT)* ('else' ':' STMT)? WHEN_EXPR ::= 'when' EXPR ':' EXPR ('else' ':' EXPR)? WHEN_STMT ::= 'when' EXPR ':' STMT ('else' ':' STMT)? BLOCK_EXPR ::= 'block' IDENT? ':' EXPR BLOCK_STMT ::= 'block' IDENT? ':' STMT MATCH_EXPR ::= 'match' EXPR ':' ('case' EXPR ('where' EXPR)? (',' EXPR ('where' EXPR)?)* ':' EXPR)+ MATCH_STMT ::= 'match' EXPR ':' ('case' EXPR ('where' EXPR)? (',' EXPR ('where' EXPR)?)* ':' STMT)+ LOOP_STMT ::= 'loop' ':' STMT WHILE_STMT ::= 'while' EXPR ':' STMT FOR_STMT ::= 'for' GROUP 'in' EXPR ':' STMT ``` ## Modules ``` IMPORT_STMT ::= 'import' IDENT_AS? ('/' (IDENT_AS | '[' (IDENT_AS (',' IDENT_AS)*)? ']'))* EXPORT_STMT ::= 'export' IDENT_AS? ('/' (IDENT_AS | '[' (IDENT_AS (',' IDENT_AS)*)? ']'))* MODULE_STMT ::= 'module' IDENT ':' STMT IDENT_AS ::= IDENT ('as' IDENT)? ``` ## Macros ``` MACRO_FUNC ::= IDENT '(' EXPR ')' MACRO_BLOCK ::= IDENT ':' EXPR # todo ``` ## Calls, Statements, and Expressions ``` OPERATION ::= EXPR OPERATOR EXPR PREFIX ::= OPERATOR EXPR SUFFIX ::= EXPR OPERATOR APPLICATION ::= IDENT EXPR | IDENT PARAMS? | (IDENT | APPLICATION) '.' IDENT PARAMS? PARAMS ::= '(' ((IDENT '=')? EXPR (',' (IDENT '=')? EXPR)*)? ')' ``` ``` STMT ::= SINGLE_STMT | STMT+ SINGLE_STMT ::= IF_STMT | WHEN_STMT | BLOCK_STMT | MATCH_STMT | LOOP_STMT | WHILE_STMT | FOR_STMT | IMPORT_STMT | EXPORT_STMT | MODULE_STMT | TYPE_DECL | FUNC_DECL | (EXPR ';') EXPR ::= IF_EXPR | WHEN_EXPR | BLOCK_EXPR | MATCH_EXPR | MACRO_FUNC | MACRO_BLOCK | VALUE | APPLICATION | (STMT EXPR) ```