CSL grammar

The following grammar describes the CSL language.

CSL is whitespace insensitive. This means that the syntax allows an arbitrary amount of whitespace and comment lines around tokens (written as "token"). Anything on a line between // and the newline character is treated as a comment and ignored.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The top-level entry point to the grammar

csl-unit = declaration*

declaration = type-declaration
            | value-declaration
            | contract-declaration
            | template-declaration
            | module-declaration



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; modules

module-declaration = "module" upper-case-identifier "{" declaration*  "}"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; types

type-declaration = "type" (sum-type-declaration | record-type-declaration)

sum-type-declaration = upper-case-identifier
                       lower-case-identifier*
                       ("|" upper-case-identifier type-atom*)+

record-type-declaration = upper-case-identifier [ ":" type ]
                          "{" (record-field-declaration ",")* "}"
record-field-declaration = lower-case-identifier COLON type

type = type-atom
     | type type ; type application
     | type "->" type ; function type

type-atom = lower-case-identifer ; type variable
          | qualifier upper-case-identifier ; type name
          | "(" type ")"


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; expressions

value-declaration = "val" val-bindings

val-bindings =
  (val-binding "with")* val-binding

val-binding =
  ; Note: patterns are only allowed if the binding occurs within an expression.
  (pattern | lower-case-identifer)
  "="
  expression

expression = expression expression
           | expression BINARY_OPERATOR expression
           | "(" (expression ",")* expression ")"
           | if-expression
           | type-case-expression
           | function-expression
           | let-expression
           | record-expression
           | qualifier lower-case-identifier ; variable
           | literal
           | qualifier upper-case-identifier ; constructor
           | "[" [ (expression ",")* expression ] "]" ; list
           | expression ":>" type ; upcast operator

if-expression =
  "if" "(" expression ")" expression "else" expression

type-case-expression =
  "type" lower-case-identifier "=" expression "of"
  "{"
  (type-atom "->" expression ";")*
  "_" "->" expression
  "}"

function-expression =
  "\" pattern "->" expression
  [ "|" pattern "->" expression
    ("|" pattern "->" expression)* ]

let-expression =
  "let" ("val" pattern "=" expression)+
  "in" expression

record-expression =
  type "{" (lower-case-identifier "=" expression ",")* "}"


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; patterns

pattern =
  (pattern-apply | pattern-atom) ("as" lower-case-identifier)* (":" type)*

pattern-apply = qualifier upper-case-identifier pattern-atom*

pattern-atom = "_"
             | "(" (pattern ",")* pattern ")"
             | record-pattern
             | literal
             | qualifier upper-case-identifier ; constructor
             | lower-case-identifier ; variable

record-pattern =
  "?" type
  "{"
  [ (lower-case-identifier "=" pattern ",")*
    lower-case-identifier "=" pattern ]
  "}"


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; contracts

template-declaration = rec-template-declaration
                     | meta-template-declaration

rec-template-declaration = "template" ("rec")? rec-template-bindings
rec-template-bindings =
  (rec-template-binding "with")* rec-template-binding
rec-template-binding =
  upper-case-identifier
  "("
  [ (pattern ",")* pattern ]
  ")" "=" contract

meta-template-declaration = "template" meta-template-bindings
meta-template-bindings =
  (meta-template-binding "with")* meta-template-binding
meta-template-binding =
  "["
  [ (lower-case-identifier ",")* lower-case-identifier ]
  "]"
  upper-case-identifier
  "("
  [ (pattern ",")* pattern ]
  ")" "=" contract

contract-declaration = "contract" contract-bindings
contract-bindings =
  (contract-binding "with")* contract-binding
contract-binding =
  lower-case-identifier
  "="
  contract

local-declaration = template-declaration
                  | contract-declaration
                  | value-declaration

contract = "success"
         | "failure"
         | contract "and" contract
         | contract "or" contract
         | contract "then" contract
         | "(" contract ")"
         | application-contract
         | variable-contract
         | prefix-contract
         | let-contract

application-contract =
  qualifier upper-case-identifier
  [ "[" [ (contract ",")* contract ] "]" ]
  "(" [ (expression ",")* expression ] ")"

variable-contract = lower-case-identifier

prefix-contract =
  "<" ( "*" | expression) ">"
  [ lower-case-identifier ":" ] type
  [ "where" expression ]

let-contract =
  "let" (local-declaration)+
  "in" contract


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Basic grammar components

lower-case-identifier = /[a-z][a-zA-Z0-9_]*/
upper-case-identifier = /[A-Z][a-zA-Z0-9_]*/

literal = float-literal
        | integer-literal
        | duration-literal
        | date-time-literal
        | string-literal

float-literal = /[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?/
integer-literal = /[0-9]+/

fixed3 = /[0-9]+(\.[0-9]{1,3})?/
duration-literal =
  "#"
  /[+-]?P/ (duration-time | duration-date duration-time?)
  "#"

duration-date = fixed3 "D"
duration-time = "T" (duration-hours | duration-minutes | duration-seconds)
duration-hours = fixed3 "H" (duration-minutes | duration-seconds)?
duration-minutes = fixed3 "M" duration-seconds?
duration-seconds = fixed3 "S"

; These two are defined elsewhere.
date-time-literal =
  "#"
  ( ( /[0-9]{4}/
    | /[0-9]{4}-[0-9]{2}/
    | /[0-9]{4}-[0-9]{2}-[0-9]{2}/
    | /[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}/
    | /[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}/
    | /[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}/
    | /[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{0,3}/
    )
    [ /[+-][0-9]{4}|[+-}[0-9]{2}:[0-9]{2}|Z/ ]
  ) "#"
string-literal = haskell-style-string ; see Haskell 98 report

; A sequence of zero or more qualifer names interspersed with '::'.
qualifier = (upper-case-identifier "::")*

BINARY_OPERATOR = "+" | "-" | "*" | "/"
                | "<=" | ">=" | "<" | ">"
                | "=" | "&&" | "||"