Language
Specification

Tact Specification

🚨

This page is mostly a stub until it's implemented in #76 (opens in a new tab)

Tact grammar used in its compiler is written in an Ohm language (opens in a new tab), which is based on parsing expression grammars (opens in a new tab) (PEGs), which are a formal way of describing syntax, similar to regular expressions and context-free grammars.

Tact {
 
    // Starting point of the program
    Program = ProgramItem*
    ProgramItem = Struct
                | Contract
                | Primitive
                | StaticFunction
                | NativeFunction
                | ProgramImport
                | Trait
                | Constant
    ProgramImport = import stringLiteral ";"
 
    // Built-in declarations
    Primitive = "primitive" Type ";"
 
    // Static function
    StaticFunction = Function
    NativeFunction = nameAttribute "(" funcId ")" FunctionAttribute* native id "(" ListOf<FunctionArg,","> ")" ";" --withVoid
                   | nameAttribute "(" funcId ")" FunctionAttribute* native id "(" ListOf<FunctionArg,","> ")" ":" Type ";" --withType
 
    // Field declarations
    Type = typeLiteral "?" --optional
         | typeLiteral --required
         | "map" "<" typeLiteral (as id)? "," typeLiteral (as id)? ">" --map
         | "bounced" "<" typeLiteral ">" --bounced
    Field = id ":" Type ";" --default
          | id ":" Type "=" Expression ";" --defaultWithInit
          | id ":" Type as id ";" --withSerialization
          | id ":" Type as id "=" Expression ";" --withSerializationAndInit
 
    // Constant
    ConstantAttribute = virtual    --virtual
                      | override   --override
                      | abstract   --abstract
    Constant = ConstantAttribute* ~fun const id ":" Type "=" Expression ";" --withValue
             | ConstantAttribute* ~fun const id ":" Type ";"                --withEmpty
 
    // Struct
    Struct = "struct" typeLiteral "{" StructBody* "}" --originary
           | "message" typeLiteral "{" StructBody* "}" --message
           | "message" "(" integerLiteral ")" typeLiteral "{" StructBody* "}" --messageWithId
    StructBody = Field
 
    // Contract
    Contract = ContractAttribute* contract id "{" ContractBody* "}" --simple
             | ContractAttribute* contract id with ListOf<id,","> "{" ContractBody* "}" --withTraits
    ContractInit = "init" "(" ListOf<FunctionArg,","> ")" "{" Statement* "}"
    ContractBody = Field
                 | ContractInit
                 | ReceiveFunction
                 | Function
                 | Constant
 
    // Trait
    Trait = ContractAttribute* trait id "{" TraitBody* "}" --originary
          | ContractAttribute* trait id with ListOf<id,","> "{" TraitBody* "}" --withTraits
    TraitBody = Field
              | ReceiveFunction
              | Function
              | Constant
 
    // Contract attributes
    ContractAttribute = "@interface" "(" stringLiteral ")" --interface
 
    // Function
    FunctionAttribute = "get"     --getter
                      | mutates   --mutates
                      | extends   --extends
                      | virtual   --virtual
                      | override  --override
                      | inline    --inline
                      | abstract  --abstract
    Function = FunctionAttribute* fun id "(" ListOf<FunctionArg,","> ")" "{" Statement* "}" --withVoid
             | FunctionAttribute* fun id "(" ListOf<FunctionArg,","> ")" ":" Type "{" Statement* "}" --withType
             | FunctionAttribute* fun id "(" ListOf<FunctionArg,","> ")" ";" --abstractVoid
             | FunctionAttribute* fun id "(" ListOf<FunctionArg,","> ")" ":" Type ";" --abstractType
    FunctionArg = id ":" Type
 
    ReceiveFunction = "receive" "(" FunctionArg ")" "{" Statement* "}" --simple
                    | "receive" "(" ")" "{" Statement* "}" --empty
                    | "receive" "(" stringLiteral ")" "{" Statement* "}" --comment
                    | "bounced" "(" FunctionArg ")" "{" Statement* "}" --bounced
                    | "external" "(" FunctionArg ")" "{" Statement* "}" --externalSimple
                    | "external" "(" stringLiteral ")" "{" Statement* "}" --externalComment
                    | "external" "(" ")" "{" Statement* "}" --externalEmpty
 
    // Statements
    Statement = StatementLet
              | StatementBlock
              | StatementReturn
              | StatementExpression
              | StatementAssign
              | StatementAugmentedAssign
              | StatementCondition
              | StatementWhile
              | StatementRepeat
              | StatementUntil
    StatementBlock = "{" Statement* "}"
    StatementLet = let id ":" Type "=" Expression ";"
    StatementReturn = return Expression ";" --withExpression
                    | return ";" --withoutExpression    
    StatementExpression = Expression ";"
    StatementAssign = LValue "=" Expression ";"
    StatementAugmentedAssign = StatementAugmentedAssignAdd
                             | StatementAugmentedAssignSub
                             | StatementAugmentedAssignMul
                             | StatementAugmentedAssignDiv
                             | StatementAugmentedAssignRem
    StatementAugmentedAssignAdd = LValue "+=" Expression ";"
    StatementAugmentedAssignSub = LValue "-=" Expression ";"
    StatementAugmentedAssignMul = LValue "*=" Expression ";"
    StatementAugmentedAssignDiv = LValue "/=" Expression ";"
    StatementAugmentedAssignRem = LValue "%=" Expression ";"
    StatementCondition = if Expression "{" Statement* "}" ~else --simple
                       | if Expression "{" Statement* "}" else "{" Statement* "}" --withElse
                       | if Expression "{" Statement* "}" else StatementCondition --withElseIf
    StatementWhile = while "(" Expression ")" "{" Statement* "}"
    StatementRepeat = repeat "(" Expression ")" "{" Statement* "}"
    StatementUntil = do "{" Statement* "}" until "(" Expression ")" ";"
 
    // L-value
    LValue = id "." LValue --more
           | id --single
 
    // Expressions
    Expression = ExpressionConditional
    ExpressionConditional = ExpressionOr "?" ExpressionOr ":" ExpressionConditional --ternary
                          | ExpressionOr
    ExpressionOr = ExpressionOr "||" ExpressionAnd --or
                 | ExpressionAnd
    ExpressionAnd = ExpressionAnd "&&" ExpressionCompare --and
                  | ExpressionCompare
    ExpressionCompare = ExpressionCompare "!=" ExpressionBinary --not
                      | ExpressionCompare "==" ExpressionBinary --eq
                      | ExpressionCompare ">" ExpressionBinary --gt
                      | ExpressionCompare ">=" ExpressionBinary --gte
                      | ExpressionCompare "<" ExpressionBinary --lt
                      | ExpressionCompare "<=" ExpressionBinary --lte
                      | ExpressionBinary
    ExpressionBinary = ExpressionBinary ">>" ExpressionAdd --shr
                    | ExpressionBinary "<<" ExpressionAdd --shl
                    | ExpressionBinary "&" ExpressionAdd --bin_and
                    | ExpressionBinary "|" ExpressionAdd --bin_or
                    | ExpressionAdd
    ExpressionAdd = ExpressionAdd "+" ~"+" ExpressionMul --add
                  | ExpressionAdd "-" ~"-" ExpressionMul --sub
                  | ExpressionMul
    ExpressionMul = ExpressionMul "*" ExpressionUnary --mul
                  | ExpressionMul "/" ExpressionUnary --div
                  | ExpressionMul "%" ExpressionUnary --rem
                  | ExpressionUnary
    ExpressionUnary = "-" ExpressionUnarySuffix --neg
                    | "+" ExpressionUnarySuffix --add
                    | "!" ExpressionUnarySuffix --not
                    | ExpressionUnarySuffix
    ExpressionUnarySuffix = ExpressionValue "!!" --notNull
                          | ExpressionValue
    ExpressionBracket = "(" Expression ")"
 
    // Order is important
    ExpressionValue = ExpressionCall
                    | ExpressionField
                    | ExpressionStaticCall
                    | ExpressionBracket
                    | ExpressionNew
                    | integerLiteral
                    | boolLiteral
                    | id
                    | null
                    | ExpressionInitOf
                    | ExpressionString
    ExpressionString = stringLiteral
    ExpressionField = ExpressionValue "." id ~"("
    ExpressionCall = ExpressionValue "." id "(" ListOf<Expression, ","> ")"
    ExpressionNew = id "{" ListOf<NewParameter, ","> "}"
    NewParameter = id ":" Expression
    ExpressionStaticCall = id "(" ListOf<Expression, ","> ")"
    ExpressionInitOf = initOf id "(" ListOf<Expression, ","> ")"
 
    // Type Literal
    typeLiteral = letterAsciiUC typeLiteralPart*
    typeLiteralPart = letterAscii | digit | "_"
 
    // Integer Literal
    // hexDigit defined in Ohm's built-in rules (otherwise: hexDigit = "0".."9" | "a".."f" | "A".."F")
    // digit defined in Ohm's built-in rules (otherwise: digit = "0".."9")
    integerLiteral = integerLiteralHex | integerLiteralBin | integerLiteralOct | integerLiteralDec // Order is important
    integerLiteralDec = nonZeroDigit ("_"? digit)*  --nonZeroIntegerLiteralDec
                      | "0" digit*                  --integerLiteralWithLeadingZero
    integerLiteralHex = ("0x" | "0X") hexDigit ("_"? hexDigit)*
    integerLiteralBin = ("0b" | "0B") binDigit ("_"? binDigit)*
    integerLiteralOct = ("0o" | "0O") octDigit ("_"? octDigit)*
    binDigit = "0" | "1"
    octDigit = "0".."7"
    nonZeroDigit = "1".."9"
 
    // Letters
    letterAsciiLC = "a".."z"
    letterAsciiUC = "A".."Z"
    letterAscii = letterAsciiLC | letterAsciiUC
    letterComment = letterAsciiLC | letterAsciiUC | digit | "_"
 
    // ID Literal
    idStart = letterAscii | "_"
    idPart = letterAscii | digit | "_"
    id = ~reservedWord #idStart #(idPart*)
 
    // FunC id
    funcLetter = letterAscii | "_" | "'" | "?" | "!" | "::" | "&"
    funcId = funcLetter #(funcLetter | digit)*
 
    // Bool Literal
    boolLiteral = ("true" | "false") ~idPart
 
    // String literal
    stringLiteralCharacter = ~("\"" | "\\" | lineTerminator) any
    stringLiteral = "\"" stringLiteralCharacter* "\""
 
    // Keywords
    // NOTE Order is important
    keyword = fun
            | let
            | return
            | extend
            | native
            | public
            | null
            | if
            | else
            | while
            | repeat
            | do
            | until
            | as
            | mutates
            | extends
            | import
            | with
            | trait
            | initOf
            | override
            | abstract
            | virtual
            | inline
            | const
    contract = "contract" ~idPart
    let = "let" ~idPart
    fun = "fun" ~idPart
    return = "return" ~idPart
    extend = "extend" ~idPart
    native = "native" ~idPart
    public = "public" ~idPart
    null = "null" ~idPart
    if = "if" ~idPart
    else = "else" ~idPart
    while = "while" ~idPart
    repeat = "repeat" ~idPart
    do = "do" ~idPart
    until = "until" ~idPart
    as = "as" ~idPart
    mutates = "mutates" ~idPart
    extends = "extends" ~idPart
    import = "import" ~idPart
    with = "with" ~idPart
    trait = "trait" ~idPart
    initOf = "initOf" ~idPart
    virtual = "virtual" ~idPart
    override = "override" ~idPart
    inline = "inline" ~idPart
    const = "const" ~idPart
    abstract = "abstract" ~idPart
 
    // Attributes
    nameAttribute = "@name"
 
    // Reserved
    reservedWord = keyword
 
    // Comments
    space += comment | lineTerminator
    comment = multiLineComment | singleLineComment
    lineTerminator = "\n" | "\r" | "\u2028" | "\u2029"
    multiLineComment = "/*" (~"*/" any)* "*/"
    singleLineComment = "//" (~lineTerminator any)*
}