Syntax: A Casual and Formal Look

! This section is incomplete. Proceed with caution.

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
    • suspend resume spawn pool thread closure
    • cyclic acyclic sink move destroy copy trace deepcopy

The following identifiers are in use by the standard prelude:

  • logic: not and or xor shl shr div mod rem
  • logic: + - * / < > <= >= == != is
  • async: async await
  • types: int uint float
    • i8 i16 i32 i64 i128
    • u8 u16 u32 u64 u128
    • f32 f64 f128
    • dec64 dec128
  • types: bool byte char str
  • types: void never
  • strings: & (string append)

The following punctuation is taken:

  • = (assignment)
  • . (chaining)
  • , (params)
  • ; (statements)
  • : (types)
  • # (comment)
  • _ (unused bindings)
  • | (generics)
  • \ (string/char escaping)
  • () (params, tuples)
  • {} (scope, structs)
  • [] (generics, lists)
  • "" (strings)
  • '' (chars)
  • `` (unquoting)
  • unused: ~ @ $ %

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 (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: