Skip to content

Tact Specification

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

Terminal window
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)*
}