Документация

Лексическая структура

Строка, разделенная расширенными разделителями, представляет собой последовательность символов, заключенную в кавычки и в равное количество символов. Лексическая структура Swift описывает какая последовательность символов образует валидные токены языка. Эти токены образуют строительные блоки низшего уровня языка и используются для описания остальной части языка в последующих главах. Токен состоит из идентификатора, ключевого слова, пунктуации, литерала или оператора.

В большинстве случаев, токены генерируются из символов исходного файла Swift с учетом максимально длинной подстроки вводимого текста, с грамматическими ограничениями, описанными ниже. Такое поведение называется longest match или maximal munch.

Пробелы и комментарии

Пробелы используются для двух целей: для разделения токенов в исходном файле и для того, чтобы помочь определить является ли оператор префиксом или постфиксом (см. раздел "Операторы" ниже), в остальных случаях их использование игнорируется. Следующие символы считаются пробелами: промежуток (U + 0020), перевод строки (U + 000A), возврат каретки (U + 000D), горизонтальная вкладка (U + 0009), вертикальная вкладка (U + 000B), смена страницы (очистка экрана)(U + 000C) и нуль (U + 0000).

Комментарии обрабатываются как пробелы компилятором. Однострочные комментарии начинаются с // и продолжаются до расстояния между строкой (U + 000A) или возврата каретки (U + 000D). Многострочные комментарии начинаются с / * и заканчиваются */. Вложение многострочных комментариев допускается, но маркеры комментариев должны быть сбалансированы.

Комментарии могут содержать дополнительное форматирование и разметку, как описано в Markup Formatting Reference.

Грамматика пробелов

whitespace → whitespace-item whitespaceopt
whitespace-item → line-break
whitespace-item → comment
whitespace-item → multiline-comment
whitespace-item → U+0000, U+0009, U+000B, U+000C, or U+0020

line-break → U+000A
line-break → U+000D
line-break → U+000D followed by U+000A

comment → // comment-text line-break
multiline-comment → /* multiline-comment-text */

comment-text → comment-text-item comment-textopt
comment-text-item → Any Unicode scalar value except U+000A or U+000D

multiline-comment-text→multiline-comment-text-item multiline-comment-textopt
multiline-comment-text-item → multiline-comment
multiline-comment-text-item → comment-text-item
multiline-comment-text-item → Any Unicode scalar value except /* or */ 

Идентификаторы

Идентификаторы начинаются с заглавной или строчной буквы от А до Z, знак подчеркивания (_), некомбинируемого алфавитно-цифрового символа Unicode в базовом многоязычном разделе, или символа вне базового многоязычного раздела, который не находится в зоне личного пользования. После первого символа, цифры и комбинируемые символы Unicode также допускаются.

Чтобы использовать зарезервированное слово в качестве идентификатора, поставьте обратные одиночные кавычки (`) до и после него. Например, class не является допустимым идентификатором, но `class` действителен. Открывающиеся кавычки не считаются частью идентификатора, `x` и x имеют одинаковое значение.

Внутри замыкания, где имена параметров не указываются явно, можно использовать неявные имена параметров: $0, $1, $2 и так далее. Эти имена являются допустимыми идентификаторами в пределах замыкания.

Грамматика идентификатора

identifier identifier-head­ identifier-characters­opt­
identifier identifier-head­ identifier-characters­opt­
identifier implicit-parameter-name­
identifier-list identifier­ identifier­identifier-list­
identifier-head → Upper- or lowercase letter A through Z
identifier-head 
identifier-head → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
identifier-head → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
identifier-head → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
identifier-head → U+1E00–U+1FFF
identifier-head → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F
identifier-head → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793
identifier-head → U+2C00–U+2DFF or U+2E80–U+2FFF
identifier-head → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF
identifier-head → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44
identifier-head → U+FE47–U+FFFD
identifier-head → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD
identifier-head → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD
identifier-head → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD
identifier-head → U+D0000–U+DFFFD or U+E0000–U+EFFFD
identifier-character → Цифры от 0 до 9 (включительно)
identifier-character → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F
identifier-character identifier-head­
identifier-characters identifier-character­identifier-characters­opt­
implicit-parameter-name decimal-digits­

Ключевые слова и пунктуация

Следующие ключевые слова зарезервированы и не могут быть использованы в качестве идентификаторов, если не помещены в одиночные кавычки, как описано выше в "Идентификаторы". Ключевые слова, кроме inout, var, и let могут быть использованы в качестве внешних имен параметров в объявлении функции или в вызове функции без необходимости помещать их в одиночные кавычки. Когда член имеет то же самое имя, что и ключевое слово, то нет необходимости экранировать это ключевое слово при помощи обратных одинарных кавычек, если только существует неоднозначность с использованием таких ключевых слов как self, Type, Protocol. Эти слова имеют особенное значение, поэтому их обязательно нужно экранировать с помощью обратных одинарных кавычек.

  • Ключевые слова, используемые в объявлениях: associatedtype, class, deinit, enum, extension, fileprivatefunc, import, init, inout, internal, let, operator, private, protocol, public, static, struct, subscript, typealias и var.
  • Ключевые слова, используемые в выражениях: break, case, continue, default, defer, do, else, fallthrough, for, guard, if, in, repeat, return, switch, where, и while..
  • Ключевые слова, используемые в выражениях и типах: ascatchfalse, is, nil, rethrows, super, self, Self, throw, throws, true, и try.
  • Ключевые слова, используемые в шаблонах: _.
  • Ключевые слова, начинающиеся со знака (#): #available, #column, #else, #elseif, #endif, #file, #function, #if, #line, #sourceLocation, #imageLiteral, #fileliteral, #colorLiteral, и #selector.
  • Ключевые слова, зарезервированные в определенных контекстах: associativity, convenience, dynamic, didSet, final, get, infix, indirect, lazy, left, mutating, none, nonmutating, optional, override, postfix, precedence, prefix, Protocol, required, right, set, Type, unowned, weak, и willSet. Вне контекста, в котором они используются в грамматике, они могут быть использованы в качестве идентификаторов.

Следующие токены зарезервированы как знаки препинания и не могут быть использованы в качестве пользовательских операторов: (, ), {, }, [, ], ., ,, :, ;, =, @, #, & (в качестве префиксного оператора), ->, `, ? и ! (в качестве постфиксного оператора).

Литералы

Литералы являются исходным кодом представления типа значения, например, цифры или строки.

Ниже приведены примеры литералов:

42               // целочисленный литерал
3.14159          // литерал дробного числа с плавающей точкой
"Hello, world!"  // строковый литерал
true             // логический литерал

Литерал не имеет самостоятельный тип. Вместо этого, литерал обрабатывается как имеющий бесконечную точность и выводимый тип в Swift пытается вывести тип для литерала. Например, в объявлении let x: Int8 = 42, Swift использует явную аннотацию типа (: Int8) и делает вывод, что тип целочисленного литерала 42 будет Int8. Если не доступна информация о типе, Swift делает вывод, что тип литерала является одним из дефолтных типов литерала, определенных в стандартной библиотеке Swift. Дефолтные типы (или типы по умолчанию) являются Int для целочисленных литералов, Double для литералов с плавающей точкой, String для строковых литералов и Bool для логических литералов. Например, в объявлении let str = "Hello, world", дефолтный выведенный тип литерала строки "Hello, world" будет String.

Устанавливая тип аннотации для значения литерала, тип аннотации должен быть типом, экземпляр которого будет создан из этого значения литерала. То есть, тип должен соответствовать одному из следующих стандартных протоколов библиотеки Swift: ExpressibleByIntegerLiteral для целочисленных литералов, FloatingPointLiteralConvertible для литералов с плавающей точкой, StringLiteralConvertible для строковых литералов, и BooleanLiteralConvertible для булева литералов. Например, Int8 соответствует протоколу ExpressibleByIntegerLiteral, и поэтому может быть использован в аннотации типа для целочисленного литерала 42 в объявлении let x: Int8 = 42.

Грамматика литерала

literal numeric-literal­ | string-literal­ | boolean-literal­ | nil-literal­
numeric-literal opt­ integer-literal­ | optfloating-point-literal­
boolean-literal true­ | false­
nil-literal nil­

Целочисленные литералы

Целочисленные литералы представляют собой целые значения неустановленной точности. По умолчанию целочисленные литералы выражаются в десятичной системе исчисления. Вы можете указать альтернативную базу с использованием префикса. Двоичные литералы начинаются с 0b, восьмеричные литералы начинаются с 0o, и шестнадцатеричные литералы начинаются с 0x.

Десятичные литералы содержат цифры от 0 до 9. Двоичные литералы содержат 0 и 1, восьмеричные литералы содержат от 0 до 7, и шестнадцатеричные литералы содержат от 0 до 9, а также от A до F в верхнем или нижнем регистре.

Отрицательные целочисленные литералы имеют знак минус (-) для целочисленного литерала, как в -42.

Знак подчеркивания (_) разрешен между цифрами для удобства чтения, но игнорируются, и, следовательно, не влияет на величину или значение литерала. Целочисленные литералы могут начинаться с нулей (0), но они так же игнорируются и не влияют на значение возводимое в степень или значение литерала.

Если не указано иное, дефолтный выводимый тип целочисленного литерала - это стандартный тип библиотеки Swift - Int. Стандартная библиотека Swift также определяет типы для различных размеров беззнаковых и знаковых Int.

Грамматика целочисленного литерала

integer-literal binary-literal­
integer-literal octal-literal­
integer-literal decimal-literal­
integer-literal hexadecimal-literal­
binary-literal 0b binary-digit­binary-literal-characters­opt­
binary-digit Цифры 0 или 1
binary-literal-character binary-digit­
binary-literal-characters binary-literal-character­ binary-literal-characters­opt­
octal-literal 0o­ octal-digit­octal-literal-characters­opt­
octal-digit Цифры от 0 до 7 включительно
octal-literal-character octal-digit­ |  _ ­
octal-literal-characters octal-literal-character ­octal-literal-characters­opt­
decimal-literal decimal-digit­ decimal-literal-characters­opt­
decimal-digit Цифры от 0 до 9 включительно
decimal-digits decimal-digit­decimal-digits­opt­
decimal-literal-character decimal-digit­  | 
decimal-literal-characters decimal-literal-character ­decimal-literal-characters­opt­
hexadecimal-literal 0x hexadecimal-digit­hexa decimal-literal-characters­opt­
hexadecimal-digit Цифры от 0 до 9 включительно, от a до f включительно или от A до F включительно
hexadecimal-literal-character hexadecimal-digit­ 
hexadecimal-literal-characters hexadecimal-literal-character­ hexadecimal-literal-characters­opt­

Литералы с плавающей точкой

Литералы с плавающей точкой представляют значения с плавающей точкой неуказанной точности.

По умолчанию, литералы с плавающей точкой выражаются в десятичной системе (без префикса), но они также могут быть выражены в шестнадцатеричном формате (с префиксом литералов).

Десятичные литералы с плавающей точкой состоят из последовательности, состоящей из десятичных цифр с последующей десятичной дробью, или десятичным экспонентом (показателем степени или порядка), или и тем и тем. Десятичная дробь состоит из десятичной точки (.), за которой идет последовательность десятичных цифр. Экспонент состоит из префикса e верхнего или нижнего регистра, за которым следует последовательность десятичных цифр, которая указывает, на 10 какой степени будет умножается это значения перед e, например, 1.25e2 будет представлено как 1.25 x 102, и принимает значение 125.0. Точно так же, 1.25e-2 будет представлено как 1.25 x 10-2, что равно 0.0125.

Шестнадцатиричные литералы с плавающей точкой состоят из префикса 0x, за которым может следовать шестнадцатеричная дробь, с последующим шестнадцатеричным экспонентом. Шестнадцатеричная дробь состоит из десятичной точки, за которой следует последовательность шестнадцатеричного разряда. Экспонент состоит из префикса p верхнего или нижнего регистра, за которым следует последовательность десятичных цифр, которая указывает на степень, в которую будет возводиться 2, стоящая перед p. Например, 0xFp2 это 15 x 22, что равно 60. Точно так же, 0xFp-2 составляет 15 x 2-2, и имеет значение 3.75.

Отрицательные литералы с плавающей точкой имеют знак минус (-) перед литералом с плавающей точкой, например -42.5.

Знак подчеркивания (_) разрешен между цифрами для удобства чтения, но игнорируются, и, следовательно, не влияет на значение литерала. Литералы с плавающей точкой могут начинаться с нуля (0), но он также же игнорируются и не влияют на значение возводимого в степень основания или на значение литерала.

Если не указано иное, по умолчанию выводимый тип с плавающей точкой - это стандартный тип библиотеки Swift Double, который представляет собой 64-битное число с плавающей точкой. Стандартная библиотека Swift также определяет тип Float, представляющее собой 32-битное число с плавающей точкой.

Грамматика числа с плавающей точкой

floating-point-literal decimal-literal­ decimal-fraction­opt­ decimal-exponent­opt­
floating-point-literal hexadecimal-literal­ hexadecimal-fraction­opt­ hexadecimal-exponent­
decimal-fraction decimal-literal­
decimal-exponent floating-point-e­sign­opt ­decimal-literal­
hexadecimal-fraction hexadecimal-digit­ hexadecimal-literal-characters­opt­
hexadecimal-exponent floating-point-p­sign­opt­ decimal-literal­
floating-point-e  | 
floating-point-p  | 
sign  | 

Строковые литералы

Строковый литерал представляет собой последовательность символов, взятых в двойные кавычки, и выглядит вот так:

"characters"

Строковые литералы не могут содержать неэкранированные двойные кавычки ("), неэкранированный обратный слеш (\), возврат каретки или перевод строки.

Многострочный строковый литерал заключен тремя двойными кавычками и выглядит следующим образом:

"""
characters

"""

В отличие от однострочного строкового литерала, многострочный строковый литерал может содержать неэксклюзивные двойные кавычки («), возврат каретки и перевод строки. Многострочный не может содержать три неизолированные двойные кавычки рядом друг с другом.

Разрыв строки после """, который начинается в многострочном строковом литерале, не является частью строки. Разрыв строки перед """, который завершает литерал, также не является частью строки. Чтобы создать многострочный строковый литерал, который начинается или заканчивается переводом строки, введите пустую строку в качестве ее первой или последней строки.

Многострочный строковый литерал может быть отступом, используя любую комбинацию пробелов и Tab-ов; этот отступ не входит в строку. Три кавычки - """, которые завершают литерал, определяет отступ: каждая непустая строка в литерале должна начинаться с точно такого же отступа, который появляется перед закрытием """. Вы можете добавить дополнительные пробелы после этого отступа.

Разрывы строк в многострочном строковом литерале нормализуются для использования символа перевода строки. Даже если ваш исходный файл имеет сочетание возврата каретки, все разрывы в строке будут одинаковыми.

В многострочном строковом литерале запись обратной косой черты (\) в конце строки опускает эту строку из строки. Любые пробелы между обратным слэшем и разрывом строки также опущены. Вы можете использовать этот синтаксис для жесткого переноса многострочного литерала строки в исходном коде без изменения значения результирующей строки.

Специальные символы могут быть включены в строковые литералы, используя следующие экранированные последовательные записи:

  • Нулевой символ (\0)
  • Обратный слеш (\\)
  • Горизонтальная табуляция (\t)
  • Перевод строки (\n)
  • Возврат каретки (\r)
  • Двойные кавычки (\")
  • Одиночные кавычки (\')
  • Скаляр Юникода (\u {n}), где n между первым и восьмым шестнадцатеричными символами

Значение выражения может быть вставлено в строку литерала, поместив выражение в скобки после обратного слеша (\). Интерполированное выражение может содержать строковый литерал, но не может содержать неэкранированный обратный слеш (\), возврат каретки или перевод строки.

Например, все следующие строковые литералы имеют одинаковое значение:

"1 2 3"
"1 2 \("3")"
"1 2 \(3)"
"1 2 \(1 + 2)"
let x = 3; "1 2 \(x)"
Строка, разделенная расширенными разделителями, представляет собой последовательность символов, заключенную в кавычки и в равное количество символов (#). Строка, разделенная расширенными разделителями, имеет следующий вид:
#"characters"#

#"""
characters
"""#

Специальные символы в строке, разделенной расширенными разделителями, отображаются в результирующей строке как обычные символы, а не как специальные символы. Вы можете использовать расширенные разделители для создания строк с символами, которые обычно используются для создания каких-то эффектов: генерация интерполяции строк, запуск последовательности символов или закрытие строки.

В следующем примере показан строковый литерал и строка, разделенная расширенными разделителями, которые создают эквивалентные строковые значения:

let string = #"\(x) \ " \u{2603}"#
let escaped = "\\(x) \\ \" \\u{2603}"
print(string)
// Выведет "\(x) \ " \u{2603}"
print(string == escaped)
// Выведет "true"
Если вы используете более одного числового знака для формирования строки, разделенной расширенными разделителями, не ставьте пробелы между числовыми знаками:
print(###"Line 1\###nLine 2"###) // OK
print(# # #"Line 1\# # #nLine 2"# # #) // Error

Многострочные строковые литералы, создаваемые с использованием расширенных разделителей, имеют те же требования к отступам, что и обычные многострочные строковые литералы.

Дефолтный выводимый тип строчного литерала является String. Для получения дополнительной информации о типе String, см. Строки и символы и Справка по структуре String.

Строковые литералы, которые объединяются с оператором +, делают это во время компиляции. Например, значения textA и textB в примере ниже, являются идентичными, и объединения во время компиляции не происходит.

let textA = "Hello " + "world"
let textB = "Hello world"

Грамматика строкового литерала

string-literal → static-string-literal | interpolated-string-literal
static-string-literal → " quoted-text opt "
static-string-literal → """ multiline-quoted-text opt """

quoted-text → quoted-text-item quoted-text opt
quoted-text-item → escaped-character
quoted-text-item → Any Unicode scalar value except ", \, U+000A, or U+000D

multiline-quoted-text → multiline-quoted-text-item multiline-quoted-text opt
multiline-quoted-text-item → escaped-character
multiline-quoted-text-item → Any Unicode scalar value except \
multiline-quoted-text-item → escaped-newline

interpolated-string-literal → " interpolated-text opt "
interpolated-string-literal → """ multiline-interpolated-text opt """
interpolated-text → interpolated-text-item interpolated-text opt
interpolated-text-item → \( expression ) | quoted-text-item

multiline-interpolated-text → multiline-interpolated-text-item multiline-interpolated-text opt
multiline-interpolated-text-item → \( expression ) | multiline-quoted-text-item

escaped-character → \0 | \\ | \t | \n | \r | \" | \'
escaped-character → \u { unicode-scalar-digits }
unicode-scalar-digits → Between one and eight hexadecimal digits

escaped-newline → \ whitespace opt line-break

Операторы

Стандартная библиотека Swift определяет ряд операторов для вашего использования, многие из которых обсуждаются в Базовые операторы и Продвинутые операторы. В настоящем разделе описывается, какие символы могут быть использованы для определения пользовательских операторов.

Пользовательские операторы могут начинаться с одного из символов ASCII: /, =, -, +, !, *, %, <, >, &, |, ^, ?, или ~, или одного из символов Unicode, которые мы разберем позднее (которые, среди других, включают в себя символы из Математических Операторов, Смешанные Символы и Графические метки блоков Unicode. После первого символа, использование других символов Unicode также является допустимым.

Можно также определить пользовательские операторы, которые начинаются с точки (.). Эти операторы могут содержать дополнительные точки, такие как .+.. Если оператор не начинается с точки, он не может содержать точку в другом месте. Например, +.+ Рассматривается как оператор +, за которым следует оператор +..

Вы также можете определить пользовательские операторы, содержащие знак вопроса (?), но они не могут состоять только из одного символа - знака вопроса. И хотя операторы и могут содержать восклицательный знак (!), но постфиксные операторы не могут начинаться знаком вопроса, либо восклицательным знаком.

Заметка

Токены =, ->, //, /*, */, ., префиксные операторы <, &, и ?, инфиксный оператор ?, и постфиксные операторы >, !, и ? зарезервированы. Эти токены не могут быть перезагружены, и не могут быть использованы в качестве пользовательских операторов.

Пробелы вокруг оператора используется для того, чтобы понять, используется ли оператор в качестве префиксного оператора, постфиксного оператора или бинарного оператора. Такое поведение представлено в следующих правилах:

  • Если у оператора пробелы по обеим сторонам или их нет вообще, то он рассматривается как бинарный оператор. Например, оператор +++ в a+++b и a +++ b рассматривается как бинарный оператор.
  • Если у оператора пробелы только слева, он рассматривается как префиксный унарный оператор. В качестве примера, оператор +++  в a +++b  рассматривается как префиксный унарный оператор.
  • Если у оператора пробелы только на правой стороне, он рассматривается как постфиксный унарный оператор. Например, оператор +++ в a+++ b рассматривается как унарный постфиксный оператор.
  • Если у оператора нет вообще пробелов слева, но за ним сразу идет точка (.), то это унарный постфиксный оператор. Например, оператор +++ в a+++.b рассматривается как унарный постфиксный оператор (a+++ .b, а не a +++ .b).

В целях следования настоящим правилам, символы (, [, и { перед оператором, символами ), ], и }, после оператора, и символов ,, ;, и : также рассматриваются в качестве пробелов.

Для вышеуказанных правил существует одно “но”. Если у предопределенного оператора ! или ? нет пробелов слева, то он рассматривается как постфиксный оператор, независимо от того, имеет ли он пробел справа. Чтобы использовать ? в качестве оператора опциональной цепочки, то у него не должно быть пробела слева. Для того, чтобы использовать его в тернарном операторе (? :), у него должны быть пробелы с двух сторон.

В некоторых конструкциях, операторы, начинающиеся с < или > могут быть разделены на два или более токена. То, что осталось обрабатывается так же, и может быть разделено снова. В результате, нет необходимости использовать пробел для устранения неоднозначности между символами замыкания > в конструкциях, таких как Dictionary<String, Array<Int>>. В этом примере, символы замыкания > не рассматриваются как один токен, который затем может быть неправильно истолкован в качестве a оператора побитового смещения >>.

Для того чтобы узнать, как определять новые, пользовательские операторы, см. Пользовательские операторы. Для того чтобы узнать, как перегружать существующие операторы, см. Операторные функции.

Грамматика операторов

operator operator-head­ operator-characters­opt­
operator dot-operator-head­ dot-operator-characters­
operator-head <­ | 
operator-head → U+00A1–U+00A7
operator-head → U+00A9 or U+00AB
operator-head → U+00AC or U+00AE
operator-head → U+00B0–U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or U+00F7
operator-head → U+2016–U+2017 or U+2020–U+2027
operator-head → U+2030–U+203E
operator-head → U+2041–U+2053
operator-head → U+2055–U+205E
operator-head → U+2190–U+23FF
operator-head → U+2500–U+2775
operator-head → U+2794–U+2BFF
operator-head → U+2E00–U+2E7F
operator-head → U+3001–U+3003
operator-head → U+3008–U+3030
operator-character operator-head­
operator-character → U+0300–U+036F
operator-character → U+1DC0–U+1DFF
operator-character → U+20D0–U+20FF
operator-character → U+FE00–U+FE0F
operator-character → U+FE20–U+FE2F
operator-character → U+E0100–U+E01EF
operator-characters operator-character­ operator-characters­opt­
dot-operator-head 
dot-operator-character  | operator-character­
dot-operator-characters dot-operator-character­dot-operator-characters­opt­
binary-operator operator­
prefix-operator operator­
postfix-operator operator­

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: