1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

//! # Grammar
//! ## Identifiers
//! ```text
//! f ∈ FieldName     // [a-zA-Z$_][a-zA-Z0-9$_]*
//! p ∈ ProcedureName // [a-zA-Z$_][a-zA-Z0-9$_]*
//! m ∈ ModuleName    // [a-zA-Z$_][a-zA-Z0-9$_]*
//! n ∈ StructName    // [a-zA-Z$_][a-zA-Z0-9$_]*
//! x ∈ Var           // [a-zA-Z$_][a-zA-Z0-9$_]*
//! ```
//!
//! ## Types
//! ```text
//! k ∈ Kind ::=
//!   | R // Linear resource struct value. Must be used, cannot be copied
//!   | V // Non-resource struct value. Can be silently discarded, can be copied
//!
//! g ∈ GroundType ::=
//!   | bool
//!   | u8        // unsigned 8 bit integer
//!   | u64       // unsigned 64 bit integer
//!   | u128      // unsigned 128 bit integer
//!   | address   // 32 byte account address
//!   | bytearray // immutable, arbitrarily sized array of bytes
//!
//! d ∈ ModuleAlias ::=
//!   | m         // module name that is an alias to a declared module, addr.m
//!   | Self      // current module
//!
//! t ∈ BaseType ::=
//!   | g     // ground type
//!   | k#d.n // struct 'n' declared in the module referenced by 'd' with kind 'k'
//!           // the kind 'k' cannot differ from the declared kind
//!
//! 𝛕 ∈ Type ::=
//!   | t      // base type
//!   | &t     // immutable reference to a base type
//!   | &mut t // mutable reference to a base type
//!
//! 𝛕-list ∈ [Type] ::=
//!   | unit            // empty type list.
//!                     // in the actual syntax, it is represented by the abscense of a type
//!   | 𝛕_1 * ... * 𝛕_j // 'j' >= 1. list of multiple types. used for multiple return values
//! ```
//!
//! ## Values
//! ```text
//! u ∈ Unsigned64        // Unsigned, 64-bit Integer
//! addr ∈ AccountAddress // addresses of blockchain accounts
//! bytes ∈ vector<u8>    // byte array of arbitrary length
//! v ∈ Value ::=
//!   | true
//!   | false
//!   | u        // u64 literal
//!   | 0xaddr   // 32 byte address literal
//!   | b"bytes" // arbitrary length bytearray literal
//! ```
//!
//! ## Expressions
//! ```text
//! o ∈ VarOp ::=
//!   | copy(x) // returns value bound to 'x'
//!   | move(x) // moves the value out of 'x', i.e. returns the value and makes 'x' unusable
//!
//! r ∈ ReferenceOp ::=
//!   | &x        // type: 't -> &mut t'
//!               // creates an exclusive, mutable reference to a local
//!   | &e.f      // type: '&t_1 -> &t_2' or '&mut t_1 -> &mut t_2'
//!               // borrows a new reference to field 'f' of the struct 't_1'. inherits exclusive or shared from parent
//!               // 't_1' must be a struct declared in the current module, i.e. 'f' is "private"
//!   | *e        // type: '&t -> t' or '&mut t -> t'. Dereferencing. Not valid for resources
//!
//! e ∈ Exp ::=
//!   | v
//!   | o
//!   | r
//!   | n { f_1: e_1, ... , f_j: e_j } // type: '𝛕-list -> k#Self.n'
//!                                    // "constructor" for 'n'
//!                                    // "packs" the values, binding them to the fields, and creates a new instance of 'n'
//!                                    // 'n' must be declared in the current module
//!   // boolean operators
//!   | !e_1
//!   | e_1 || e_2
//!   | e_1 && e_2
//!   // u64 operators
//!   | e_1 >= e_2
//!   | e_1 <= e_2
//!   | e_1 > e_2
//!   | e_1 < e_2
//!   | e_1 + e_2
//!   | e_1 - e_2
//!   | e_1 * e_2
//!   | e_1 / e_2
//!   | e_1 % e_2
//!   | e_1 ^ e_2
//!   | e_1 | e_2
//!   | e_g & e_2
//!   // operators over any ground type
//!   | e_1 == e_2
//!   | e_1 != e_2
//! ```
//! ## Commands
//! ```text
//! // module operators are available only inside the module that declares n.
//! mop ∈ ModuleOp ::=
//!   | move_from<n>(e)      // type: 'address -> Self.n'
//!                          // removes the resource struct 'n' at the specified address
//!                          // fails if there is no resource present for 'Self.n'
//!   | borrow_global<n>(e)  // type: 'address -> &mut Self.n'
//!                          // borrows a mutable reference to the resource struct 'n' at the specified address
//!                          // fails if there is no resource
//!                          // fails if it is already borrowed in this transaction's execution
//!   | exists<n>(e)         // type: 'address -> bool', s.t. 'n' is a resource struct
//!                          // returns 'true' if the resource struct 'n' at the specified address exists
//!                          // returns 'false' otherwise
//!
//! builtin ∈ Builtin ::=
//!   | create_account(e)         // type: 'addr -> unit'
//!                               // creates new account at the specified address, failing if it already exists
//!   | release(e)                // type: '&t -> unit' or '&mut t -> unit'
//!                               // releases the reference given
//!   | freeze(x)                 // type: '&mut t -> &t'
//!                               // coerce a mutable reference to an immutable reference
//!
//! call ∈ Call ::=
//!   | mop
//!   | builtin
//!   | d.p(e_1, ..., e_j) // procedure 'p' defined in the module referenced by 'd'
//!
//! c ∈ Cmd ::=
//!   | x = e                               // assign the result of evaluating 'e' to 'x'
//!   | x_1, ..., x_j = call                // Invokes 'call', assigns result to 'x_1' to 'x_j'
//!   | call                                // Invokes 'call' that has a return type of 'unit'
//!   | *x = e                              // mutation, s.t. 'x: &mut t' and 'e: t' and 't' is not of resource kind
//!   | assert(e_1, e_2)                    // type: 'bool * u64 -> unit'
//!                                         // halts execution with error code 'e_2' if 'e_1' evaluates to 'false'
//!   | break                               // exit a loop
//!   | continue                            // return to the top of a loop
//!   | return e_1, ..., e_n                // return values from procedure
//!   | n { f_1: x_1, ... , f_j: x_j } = e  // "de-constructor" for 'n'
//!                                         // "unpacks" a struct value 'e: _#Self.n'
//!                                         // value for 'f_i' is bound to local 'x_i'
//! ```
//!
//! ## Statements
//! ```text
//! s ∈ Stmt ::=
//!   | if (e) { s_1 } else { s_2 } // conditional
//!   | if (e) { s }                // conditional without else branch
//!   | while (e) { s }             // while loop
//!   | loop { s }                  // loops forever
//!   | c;                          // command
//!   | s_1 s_2                     // sequencing
//! ```
//!
//! ## Imports
//!```text
//! idecl ∈ Import ::=
//!   | import addr.m_1 as m_2; // imports 'addr.m_1' with the alias 'm_2'
//!   | import addr.m_1;        // imports 'addr.m_1' with the alias 'm_1'
//! ```
//! ## Modules
//! ```text
//! sdecl ∈ StructDecl ::=
//!   | resource n { f_1: t_1, ..., f_j: t_j } // declaration of a resource struct
//!   | struct n { f_1: t_1, ..., f_j: t_j }   // declaration of a non-resource (value) struct
//!                                            // s.t. any 't_i' is not of resource kind
//!
//! body ∈ ProcedureBody ::=
//!  | let x_1; ... let x_j; s // The locals declared in this procedure, and the code for that procedure
//!
//! pdecl ∈ ProcedureDecl ::=
//!   | (public?) p(x_1: 𝛕_1, ..., x_j: 𝛕_j): 𝛕-list { body } // declaration of a defined procedure
//!                                                          // the procedure may be public, or internal to the module
//!   | native (public?) p(x_1: 𝛕_1, ..., x_j: 𝛕_j): 𝛕-list; // declaration of a native procedure
//!                                                         // the implementation is provided by the VM
//!                                                         // the procedure may be public, or internal to the module
//!
//! mdecl ∈ ModuleDecl ::=
//!   | module m { idecl_1 ... idecl_i sdecl_1 ... sdecl_j pdecl_1 ... pdecl_k }
//! ```
//!
//! ## Transaction Scripts
//! ```text
//! TransactionScript ::=
//!   // declaration of the transaction scripts procedure
//!   // the 'main' procedure must be 'public' and any parameters must have a ground type
//!   | idecl_1 ... idecl_i public main(x_1: g_1, ..., x_j: g_j) { s }
//! ```

mod lexer;
pub mod syntax;