<p>Comments are the same as in C/C++. They are removed by a lexical parser (for example, being replaced by a single space). Whitespace separates tokens. Except for string constants, tokens cannot contain spaces. </p>
<p><code>Final</code> is a reserved keyword, e.g. a special token. Words like <code>Type</code> are not keywords, rather they are identifiers with preset values. </p>
<p>Tokens consisting of one or more constant symbols shall be hereafter denoted using terms in quotation marks (for example, <code>---</code> replaces <em>triple-minus</em>). </p>
<h3><aclass="anchor"href="#general-syntax-of-a-tl-program"id="general-syntax-of-a-tl-program"name="general-syntax-of-a-tl-program"><iclass="anchor-icon"></i></a>General syntax of a TL program</h3>
<p>Syntactically, a TL program consists of a stream of tokens (separated by spaces, which are ignored at this stage). General program structure: </p>
<p>Before explaining how declarations of combinators, partial applications, and type <code>finalization</code> are given, we will introduce additional syntactical categories: </p>
<h3><aclass="anchor"href="#syntactical-categories-and-constructions"id="syntactical-categories-and-constructions"name="syntactical-categories-and-constructions"><iclass="anchor-icon"></i></a>Syntactical categories and constructions</h3>
<p>The concept of an expression (<em>expr</em>) is important. There are type expressions (<em>type-expr</em>) and numeric expressions (<em>nat-expr</em>). However, they are defined the same way. Their correctness as type- or numeric expressions is checked when the type of the analyzed expression is checked. </p>
<p>Note that writing <code>E = E_1 E_2 ... E_n</code> in the expression for <em>expr</em> means applying the function <em>E_1</em> to the argument <em>E_2</em>, applying the result to <em>E_3</em>, etc. Specifically, <code>E_1 E_2 E_3 = (E_1 E_2) E_3</code>. A solitary <code>#</code> is included in <em>type-ident</em>, because it is actually the identifier for a built-in type (<code>#</code> alias <code>nat</code>). </p>
<p>The expression <code>E<E_1,...,E_n></code> is syntactic sugar for <code>(E (E_1) ... (E_n))</code>, i.e. both expressions are transformed into the same internal representation. </p>
<p>See <ahref="TL-combinators">Formal declaration of TL combinators</a> for a description of what exactly this means. Here we will only note that when declaring the type of a combinator's next argument, only the names of previously arranged (more to the left) arguments of the same combinator may be used as variables, but when declaring the result type you can use all of its parameters (of type <code>Type</code> and <code>#</code>). </p>
<p>Note that the names of combinators declared in this way may be used in TL itself only as the corresponding bare types. The only combinators that appear in declarations are built-in: <code>O : #</code> and <code>S : # -> #</code>. </p>
<p>There are also “pseudo-declarations” that are allowed only to declare built-in types (such as <code>int ? = Int;</code>): </p>
<p>This type of declaration means that there must not be any constructor for the indicated type: before the declaration for <code>New</code> and after the declaration for <code>Final</code>. The keyword <code>Empty</code> enables both effects.</p>
map {X:Type} {Y:Type} key:X value:Y = Map X Y; </p>
<p>Empty False;<br>
true = True; </p>
<p>unit = Unit; </p>
</div>
<ul>
<li>
<p>Predefined identifier <code>Type</code>: This type signifies the type of all types. It is usually used to specify the types of optional parameters in the constructors of polymorphic types. If strongly desired, it can be used in its own right, but this is very rarely needed in practice.</p>
</li>
<li>
<p>Identifier <code>#</code>: This type is used to specify a special type of nonnegative integers in the range from 0 to 2^31-1; its main purpose is the same as that of <code>Type</code>. There are two built-in constructors: <code>O</code> : # and <code>S</code> : # -> # (“null” and “next number”, respectively), which work as if <code>#</code> was defined using the schema</p>
</li>
</ul>
<divclass="richcode">
<p>O = #;<br>
S # = #; </p>
</div>
<ul>
<li>
<p>Identifier <code>Tuple</code>: Type -> # -> Type denotes a set of the specified number of values of the indicated type. In other words, <em>Tuple X n</em> means “a set of <em>n</em> values of type <em>X</em>".</p>
</li>
<li>
<p>The type<code>Bool</code>, with two constructors <code>boolTrue</code> and <code>boolFalse</code>, is used to transmit Boolean values.</p>
</li>
<li>
<p>The constructor-less type <code>False</code> may be used instead of undeclared or invalid types in the construction of a TL schema, because any attempt to (de)serialize a value of type <code>False</code> will produce an error. Usage Example:</p>
</li>
</ul>
<divclass="richcode">
<p>user {flags:#} id:flags.0?string first_name:flags.1?string last_name:flags.2?string reserved3:flags.3?False reserved4:flags.4?False = User flags;<br>
<p>In the future, bits 3 and 4 in the <code>flags</code> field may be used to transmit new fields after changing the names and types of the <code>reserved3</code> and <code>reserved4</code> fields. This will change the <code>user</code> constructor's number, but this isn't too important, since the <code>User flags</code> type is only used as a bare type. Transmitting bits 3 or 4 in the <code>flags</code> field in a <code>getUser</code> query before these fields have actually been defined will lead to an error in the (de)serialization of the request.</p>
<li>The type <code>True</code> with a single null constructor <code>true</code> plays a role similar to the void type in C/C++. It is especially useful as a bare type <code>%True</code>, alias <code>true</code>, because its serialization has zero length. For example, the <code>first_name:flags.1?string</code> constructor used above is in fact shorthand for (the as-yet unsupported) alternative-type general constructor <code>first_name:(flags.1?string:true)</code>.</li>
</ul>
<p>When directly used in a <ahref="https://core.telegram.org/mtproto/TL-combinators#conditional-fields">conditional field</a> it may simply indicate the presence (absence) of a certain parameter with void type.
If the conditional field exists, the associated parameter will not be populated; the conditional field simply exists and the existance value can be used to perform certain operations, example:</p>
<pre><code>user {flags:#} id:flags.0?string first_name:flags.1?string last_name:flags.2?string bot:flags.3?true reserved4:flags.4?False = User flags;</code></pre>
<p>If bit 3 of the <code>flags</code> parameter isn't set, the user is a normal user.
If bit 3 of the <code>flags</code> parameter is set, this indicates that the specified user is a bot: however, during deserialization, the <code>bot</code> parameter must not be assigned any value, since <code>true</code> is actually a <code>void</code> type.</p>
<ul>
<li>The type<code>Unit</code> with a single null constructor <code>Unit</code> is similar to the previous type.</li>
<p>An <ahref="https://www.antlr.org">ANLTR</a> definition of TL grammar can be found <ahref="https://gitlab.com/telekram/telekram/-/blob/master/generator/src/commonMain/antlr/TL.g4">here »</a>. </p></div>
</div>
</div>
</div>
<divclass="footer_wrap">
<divclass="footer_columns_wrap footer_desktop">
<divclass="footer_column footer_column_telegram">
<h5>Telegram</h5>
<divclass="footer_telegram_description"></div>
Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.