# Syntax: A Casual and Formal Look ## Reserved Keywords The following keywords are reserved: - variables: `let` `var` `const` - control flow: `if` `elif` `else` - pattern matching: `match` `of` - loops: `loop` `while` `for` `in` - blocks: `block` `break` `continue` `return` - functions: `func` `mut` `static` `varargs` - modules: `pub` `mod` `use` `as` - error handling: `try` `catch` `finally` - metaprogramming: `macro` `quote` `when` - types: `type` `distinct` `ref` - types: `struct` `tuple` `union` `enum` `interface` - reserved: - `impl` `object` `class` `concept` `auto` `empty` `effect` `case` `nil` - `suspend` `resume` `spawn` `pool` `thread` `closure` - `cyclic` `acyclic` `sink` `move` `destroy` `copy` `trace` `deepcopy` ## A Formal Grammar We now shall take a look at a more formal description of Puck's syntax. Syntax rules are described in [extended Backus–Naur form](https://en.wikipedia.org/wiki/Extended_Backus–Naur_form) (EBNF): however, most rules surrounding whitespace, and scope, and line breaks, are modified to how they would appear after a lexing step. ### Identifiers ``` Ident ::= (Letter | '_') (Letter | Digit | '_')* Letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff' # todo Digit ::= '0'..'9' ``` ### Literals ``` Int ::= '-'? (DecLit | HexLit | OctLit | BinLit) Float ::= '-'? DecLit '.' DecLit BinLit ::= '0b' BinDigit ('_'? BinDigit)* OctLit ::= '0o' OctDigit ('_'? OctDigit)* HexLit ::= '0x' HexDigit ('_'? HexDigit)* DecLit ::= Digit ('_'? Digit)* BinDigit ::= '0'..'1' OctDigit ::= '0'..'7' HexDigit ::= Digit | 'A'..'F' | 'a'..'f' ``` ### 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 | Float | String | Char | Array | Tuple | Struct Array ::= '[' (Expr (',' Expr)*)? ']' Tuple ::= '(' (Ident ':')? Expr (',' (Ident ':')? Expr)* ')' Struct ::= '{' Ident ':' Expr (',' Ident ':' Expr)* '}' ``` ### Variables ``` Decl ::= Let | Var | Const | Func | Type Let ::= 'let' Pattern Annotation? '=' Expr Var ::= 'var' Pattern Annotation? ('=' Expr)? Const ::= 'pub'? 'const' Pattern Annotation? '=' Expr Pattern ::= Char | String | Number | Float | Ident | '(' Pattern (',' Pattern)* ')' Ident '(' Pattern (',' Pattern)* ')' ``` ### Declarations ``` Func ::= 'pub'? 'func' Ident Generics? Parameters? Annotation? '=' Body Macro ::= 'pub'? 'macro' Ident Generics? Parameters? Annotation? '=' Body Generics ::= '[' Ident Annotation? (',' Ident Annotation?)* ']' Parameters ::= '(' Ident Annotation? (',' Ident Annotation?)* ')' Annotation ::= ':' Type ``` ### Types ``` TypeDecl ::= 'pub'? 'type' Ident Generics? '=' Type Type ::= StructType | TupleType | EnumType | UnionType | Interface | (('distinct' | 'ref' | 'ptr' | 'mut' | 'static') (Type | ('[' Type ']'))?) StructType ::= 'struct' ('[' Ident ':' Type (',' Ident ':' Type)* ']')? UnionType ::= 'union' ('[' Ident ':' Type (',' Ident ':' Type)* ']')? TupleType ::= 'tuple' ('[' (Ident ':')? Type (',' (Ident ':')? Type)* ']')? EnumType ::= 'enum' ('[' Ident ('=' Expr)? (',' Ident ('=' Expr)?)* ']')? Interface ::= 'interface' ('[' Signature (',' Signature)* ']')? Signature ::= Ident Generics? ('(' Type (',' Type)* ')')? Annotation? ``` ## Control Flow ``` If ::= 'if' Expr ':' Body ('elif' Expr ':' Body)* ('else' ':' Body)? When ::= 'when' Expr ':' Body ('elif' Expr ':' Body)* ('else' ':' Body)? Try ::= 'try' ':' Body ('except' Ident ('as' Ident)? (',' Ident ('as' Ident)?)*) ':' Body)* ('finally' ':' Body)? Match ::= 'match' Expr ('of' Pattern (',' Pattern)* ('where' Expr)? ':' Body)+ Block ::= 'block' Ident? ':' Body Block ::= 'static' ':' Body Loop ::= 'loop' ':' Body While ::= 'while' Expr ':' Body For ::= 'for' Pattern 'in' Expr Body ``` ## Modules ``` Mod ::= 'pub'? 'mod' Ident ':' Body Use ::= 'use' Ident ('/' Ident)* ('/' ('[' Ident (',' Ident)* ']'))? ``` ### Operators ``` Operator ::= 'and' | 'or' | 'not' | 'xor' | 'shl' | 'shr' | 'div' | 'mod' | 'rem' | 'is' | 'in' | Opr+ Opr ::= '=' | '+' | '-' | '*' | '/' | '<' | '>' | '@' | '$' | '~' | '&' | '%' | '|' | '!' | '?' | '^' | '.' | ':' | '\\' ``` ## Calls and Expressions ``` Call ::= Ident ('[' Call (',' Call)* ']')? ('(' (Ident '=')? Call (',' (Ident '=')? Call)* ')')? | Ident Call (',' Call)* | Call Operator Call? | Call ':' Body Expr ::= Let | Var | Const | Func | Type | Mod | Use | Block | Static | For | While | Loop | If | When | Try | Match | Call Body ::= Expr | ('{' Expr (';' Expr)* '}') ``` --- References: - https://www.joshwcomeau.com/javascript/statements-vs-expressions/ - https://pgrandinetti.github.io/compilers/ - https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html - https://nim-lang.github.io/Nim/manual.html