Spec-Zone.ru › Elixir 1.8

Справочник по синтаксису

Синтаксис Elixir был разработан для простого преобразования в абстрактное синтаксическое дерево (AST). Это означает, что синтаксис Elixir в основном единообразен с небольшим количеством конструкций «синтаксического сахара», чтобы уменьшить шум в распространённых выражениях Elixir.

В этом документе описываются все конструкции синтаксиса Elixir как справочник, а затем обсуждается их точное представление в AST.

Зарезервированные слова

Это зарезервированные слова языка Elixir. Они подробно описываются в этом руководстве, но здесь приведены для удобства:

  • true, false, nil — используются как атомы
  • when, and, or, not, in — используются как операторы
  • fn — используется для определения анонимных функций
  • do, end, catch, rescue, after, else — используются в блоках do/end

Типы данных

Числа

Целые числа (1234) и числа с плавающей точкой (123.4) в Elixir представляются как последовательность цифр, которые могут быть разделены подчеркиванием для улучшения читаемости, например, 1_000_000. Целые числа никогда не содержат точки (.) в своём представлении. Числа с плавающей точкой содержат точку и по крайней мере одну другую цифру после точки. Числа с плавающей точкой также поддерживают научную запись, например, 123.4e10 или 123.4E10.

Атомы

Незаявленные атомы начинаются с двоеточия (:), за которым сразу же должен следовать символ подчёркивания или буква Юникода. Атом может продолжаться с помощью последовательности букв, цифр, подчёркиваний и @. Атомы могут заканчиваться на ! или ?. См. Синтаксис Юникода для формального описания. Действительными незаявленными атомами являются: :ok, :ISO8601, и :integer?.

Если за двоеточием сразу следует пара двойных или одинарных кавычек, окружающих имя атома, то атом считается заявленным. В отличие от незаявленного атома, этот может состоять из любого символа Юникода (а не только букв), например, :'🌢 Elixir', :"++olá++", и :"123".

Заявленные и незаявленные атомы с одинаковым именем считаются эквивалентными, поэтому :atom, :"atom", и :'atom' представляют один и тот же атом. Единственный нюанс заключается в том, что компилятор выведет предупреждение, когда в атомах используются кавычки, которые не требуются.

Все операторы в Elixir также являются допустимыми атомами. Примерами являются :foo, :FOO, :foo_42, :foo@bar, и :++. Недопустимыми примерами являются :@foo (@ не допускается в начале), :123 (цифры недопустимы в начале) и :(*) (не является допустимым оператором).

true, false, и nil — это зарезервированные слова, которые представлены атомами :true, :false и :nil соответственно.

Строки

Однострочные строки в Elixir записываются между двойными кавычками, например, "foo". Любая двойная кавычка внутри строки должна быть экранирована с помощью \. Строки поддерживают символы Юникода и хранятся в кодировке UTF-8.

Многострочные строки в Elixir записываются с помощью трёх двойных кавычек и могут содержать неэкранированные кавычки внутри них. Результирующая строка будет заканчиваться новой строкой. Отступ последней """ используется для удаления отступа из внутренней строки. Например:

iex> test = """
...>     this
...>     is
...>     a
...>     test
...> """
"    this\n    is\n    a\n    test\n"
iex> test = """
...>     This
...>     Is
...>     A
...>     Test
...>     """
"This\nIs\nA\nTest\n"

Строки всегда представлены сами по себе в AST.

Список символов

Списки символов в Elixir записываются в одинарных кавычках, например, 'foo'. Любая одинарная кавычка внутри строки должна быть экранирована с помощью \. Списки символов являются списком целых чисел, каждое целое число представляет собой символ Юникода.

Многострочные списки символов записываются с помощью трёх одинарных кавычек ('''), аналогично многострочным строкам.

Списки символов всегда представлены сами по себе в AST.

Списки, кортежи и двоичные данные

Структуры данных, такие как списки, кортежи и двоичные данные, помечаются соответственно разделителями [...], {...}, и <<...>>. Каждый элемент разделяется запятой. Допускается также наличие запятой в конце, как в [1, 2, 3,].

Карты и списки ключевых слов

Карты используют обозначение %{...} и каждое значение ключа задаётся парами, отмеченными =>, например, %{"hello" => 1, 2 => "world"}.

Как списки ключевых слов (список кортежей из двух элементов, где первый элемент — атом), так и карты с атомными ключами поддерживают обозначение ключевых слов, где символ двоеточия : перемещается в конец атома. %{hello: "world"} эквивалентно %{:hello => "world"}, а [foo: :bar] эквивалентно [{:foo, :bar}]. Это обозначение является синтаксическим сахаром, который генерирует то же представление AST. Это будет объяснено в последующих разделах.

Структуры

Структуры построены на синтаксисе карт путём передачи имени структуры между % и {. Например, %User{...}.

Выражения

Переменные

Переменные в Elixir должны начинаться с символа подчёркивания или буквы Юникода, которая не является заглавной или прописной. Переменная может продолжаться с помощью последовательности букв, цифр и подчёркиваний. Переменные могут заканчиваться на ? или !. См. Синтаксис Юникода для формального описания.

Рекомендации по именованию Elixir рекомендуют использовать переменные в формате snake_case.

Неквалифицированные вызовы (локальные вызовы)

Неквалифицированные вызовы, такие как add(1, 2), должны начинаться с подчёркивания или буквы Юникода, которая не является заглавной или прописной. Вызов может продолжаться с помощью последовательности букв, цифр и подчёркиваний. Вызовы могут заканчиваться на ? или !. См. Синтаксис Юникода для формального описания.

Скобки для неквалифицированных вызовов необязательны, за исключением вызовов с нулевой арностью, которые в таком случае были бы неоднозначны с переменными. Если скобки используются, они должны сразу следовать за именем функции без пробелов. Например, add (1, 2) — это синтаксическая ошибка, так как (1, 2) рассматривается как недопустимый блок, который пытается передать в качестве единственного аргумента функции add.

Рекомендации по именованию Elixir рекомендуют использовать вызовы в формате snake_case.

Операторы

Как и многие языки программирования, Elixir также поддерживает операторы как неквалифицированные вызовы со своими правилами приоритета и ассоциативности. Конструкции, такие как =, when, & и @, просто рассматриваются как операторы. См. страницу Операторов для полного справочника.

Квалифицированные вызовы (удалённые вызовы)

Квалифицированные вызовы, такие как Math.add(1, 2), должны начинаться с подчёркивания или буквы Юникода, которая не является заглавной или прописной. Вызов может продолжаться с помощью последовательности букв, цифр и подчёркиваний. Вызовы могут заканчиваться на ? или !. См. Синтаксис Юникода для формального описания.

Рекомендации по именованию Elixir рекомендуют использовать вызовы в формате snake_case.

Для квалифицированных вызовов Elixir также позволяет записывать имя функции между двойными или одинарными кавычками, что позволяет использовать вызовы, такие как Math."++add++"(1, 2). Операторы могут использоваться в качестве квалифицированных вызовов без кавычек, таких как Kernel.+(1, 2).

Скобки для квалифицированных вызовов необязательны. Если скобки используются, они должны сразу следовать за именем функции без пробелов.

Псевдонимы

Псевдонимы — это конструкции, которые расширяются до атомов во время компиляции. Псевдоним String расширяется до атома :"Elixir.String". Псевдонимы должны начинаться с заглавной буквы ASCII, за которой может следовать любая буква, цифра или символ подчёркивания ASCII. Символы, не являющиеся ASCII, не поддерживаются в псевдонимах.

Рекомендации по именованию Elixir рекомендуют использовать псевдонимы в формате CamelCase.

Блоки

Блоки — это несколько выражений Elixir, разделённых новыми строками или точкой с запятой. Новый блок может быть создан в любой момент с помощью скобок.

Стрелка слева направо

Стрелка слева направо (->) используется для установления связи между левой и правой частями, обычно называемых клаузами. Левая часть может иметь ноль, один или более аргументов; правая часть — ноль, один или более выражений, разделённых новой строкой. -> может появляться один или более раз между одним из следующих терминаторов: do/end, fn/end или (/). Когда используется ->, между этими терминаторами разрешены только другие клаузы. Смешивание клауз и регулярных выражений является недопустимым синтаксисом.

Он виден в конструкциях case и cond между do/end:

case 1 do
  2 -> 3
  4 -> 5
end

cond do
  true -> false
end

Виден в описаниях типов между (/):

(integer(), boolean() -> integer())

Также используется между fn/end для создания анонимных функций:

fn
  x, y -> x + y
end

Сигилы

Сигилы начинаются с ~ и следуют за буквой и одной из следующих пар:

  • ( и )
  • { и }
  • [ и ]
  • < и >
  • " и "
  • ' и '
  • | и |
  • / и /

После закрытия пары можно указать ноль или более букв ASCII в качестве модификатора. Сигилы выражаются как неквалифицированные вызовы, префикс sigil_, где первый аргумент — содержимое сигила в виде строки, а второй — список целых чисел в качестве модификаторов:

Если буква сигила заглавная, интерполяция в сигиле запрещена, в противном случае её содержимое может быть динамическим. Сравните результаты сигилов ниже для получения дополнительной информации:

~s/f#{"o"}o/
~S/f#{"o"}o/

Сигилы полезны для кодирования текста со своими правилами экранирования, такими как регулярные выражения, даты и время и т. д.

Абстрактное синтаксическое дерево Elixir

Синтаксис Elixir был разработан для простого преобразования в абстрактное синтаксическое дерево (AST). AST Elixir — это обычная структура данных Elixir, состоящая из следующих элементов:

  • атомы - такие как :foo
  • целые числа - такие как 42
  • вещественные числа - такие как 13.1
  • строки - такие как "hello"
  • списки - такие как [1, 2, 3]
  • кортежи с двумя элементами - такие как {"hello", :world}
  • кортежи с тремя элементами, представляющие вызовы или переменные, как объяснено далее

Основной строительный блок AST Elixir — это вызов, например:

sum(1, 2, 3)

который представлен как кортеж с тремя элементами:

{:sum, meta, [1, 2, 3]}

первый элемент — это атом (или другой кортеж), второй элемент — это список кортежей из двух элементов с метаданными (например, номерами строк), а третий — это список аргументов.

Мы можем получить AST для любого выражения Elixir, вызвав quote:

quote do
  sum()
end
#=> {:sum, [], []}

Переменные также представлены с помощью кортежа из трёх элементов и сочетания списков и атомов, например:

quote do
  sum
end
#=> {:sum, [], Elixir}

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

В следующем разделе мы рассмотрим многие конструкции синтаксиса Elixir вместе с их представлением в AST.

Операторы

Операторы обрабатываются как неквалифицированные вызовы:

quote do
  1 + 2
end
#=> {:+, [], [1, 2]}

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

quote do
  foo.bar(1, 2, 3)
end
#=> {{:., [], [{:foo, [], Elixir}, :bar]}, [], [1, 2, 3]}

Вызов анонимных функций использует точку в AST с одним аргументом, отражая тот факт, что имя функции «отсутствует» справа от точки:

quote do
  foo.(1, 2, 3)
end
#=> {{:., [], [{:foo, [], Elixir}]}, [], [1, 2, 3]}

Псевдонимы

Псевдонимы представлены вызовом __aliases__ с каждым сегментом, разделенным точкой, в качестве аргумента:

quote do
  Foo.Bar.Baz
end
#=> {:__aliases__, [], [:Foo, :Bar, :Baz]}

quote do
  __MODULE__.Bar.Baz
end
#=> {:__aliases__, [], [{:__MODULE__, [], Elixir}, :Bar, :Baz]}

Все аргументы, кроме первого, гарантированно являются атомами.

Структуры данных

Помните, что списки — это литералы, поэтому они представлены сами по себе в AST:

quote do
  [1, 2, 3]
end
#=> [1, 2, 3]

Кортежи имеют собственное представление, за исключением кортежей из двух элементов, которые представлены сами по себе:

quote do
  {1, 2}
end
#=> {1, 2}

quote do
  {1, 2, 3}
end
#=> {:{}, [], [1, 2, 3]}

Бинарные данные имеют представление, аналогичное кортежам, за исключением того, что они помечены :<<>> вместо :{}:

quote do
  <<1, 2, 3>>
end
#=> {:<<>>, [], [1, 2, 3]}

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

quote do
  %{1 => 2, 3 => 4}
end
#=> {:%{}, [], [{1, 2}, {3, 4}]}

Блоки

Блоки представлены как вызов __block__ с каждой строкой в качестве отдельного аргумента:

quote do
  1
  2
  3
end
#=> {:__block__, [], [1, 2, 3]}

quote do 1; 2; 3; end
#=> {:__block__, [], [1, 2, 3]}

Стрелка слева направо

Стрелка слева направо (->) представлена аналогично операторам, за исключением того, что она всегда является частью списка, его левая сторона представляет список аргументов, а правая сторона — выражение.

Например, в case и cond:

quote do
  case 1 do
    2 -> 3
    4 -> 5
  end
end
#=> {:case, [], [1, [do: [{:->, [], [[2], 3]}, {:->, [], [[4], 5]}]]]}

quote do
  cond do
    true -> false
  end
end
#=> {:cond, [], [[do: [{:->, [], [[true], false]}]]]}

Между (/):

quote do
  (1, 2 -> 3
   4, 5 -> 6)
end
#=> [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]

Между fn/end:

quote do
  fn
    1, 2 -> 3
    4, 5 -> 6
  end
end
#=> {:fn, [], [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]}

Синтаксический сахар

Все вышеперечисленные конструкции являются частью синтаксиса Elixir и имеют собственное представление в составе AST Elixir. В этом разделе будут обсуждаться оставшиеся конструкции, которые «раскладываются» до одной из вышеупомянутых конструкций. Другими словами, конструкции ниже могут быть представлены в коде Elixir более чем одним способом и сохраняют эквивалентность AST.

Целые числа в других системах счисления и коды Юникода

Elixir позволяет целым числам содержать _ для разделения цифр и предоставляет удобства для представления целых чисел в других системах счисления:

1_000_000
#=> 1000000

0xABCD
#=> 43981 (Hexadecimal base)

0o01234567
#=> 342391 (Octal base)

0b10101010
#=> 170 (Binary base)

?é
#=> 233 (Unicode codepoint)

Эти конструкции существуют только на уровне синтаксиса. Все примеры выше представлены как их основополагающие целые числа в AST.

Синтаксис доступа

Синтаксис доступа представлен как вызов Access.get/2:

quote do
  opts[arg]
end
#=> {{:., [], [Access, :get]}, [], [{:opts, [], Elixir}, {:arg, [], Elixir}]}

Необязательные скобки

Elixir предоставляет необязательные скобки для неквалифицированных и квалифицированных вызовов.

quote do
  sum 1, 2, 3
end
#=> {:sum, [], [1, 2, 3]}

Вышеупомянутое обрабатывается так же, как sum(1, 2, 3) анализатором.

То же самое относится к квалифицированным вызовам, таким как Foo.bar(1, 2, 3), который эквивалентен Foo.bar 1, 2, 3. Однако помните, что скобки не являются необязательными для неквалифицированных вызовов без аргументов, таких как sum(). Удаление скобок в sum приводит к тому, что он представляется как переменная sum, а это значит, что они больше не будут эквивалентны.

Ключевые слова

Ключевые слова в Elixir — это список кортежей из двух элементов, где первый элемент — атом. Используя базовые конструкции, они были бы представлены как:

[{:foo, 1}, {:bar, 2}]

Однако Elixir вводит синтаксический сахар, где вышеупомянутые ключевые слова могут быть записаны следующим образом:

[foo: 1, bar: 2]

Атомы с иностранными символами, такими как пробелы, должны быть заключены в кавычки. Это правило применяется и к ключевым словам:

[{:"foo bar", 1}, {:"bar baz", 2}] == ["foo bar": 1, "bar baz": 2]

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

Ключевые слова в качестве последних аргументов

Elixir также поддерживает синтаксис, в котором, если последний аргумент вызова является ключевым словом, квадратные скобки можно опустить. Это означает, что следующее:

if(condition, do: this, else: that)

эквивалентно

if(condition, [do: this, else: that])

что, в свою очередь, эквивалентно

if(condition, [{:do, this}, {:else, that}])

do/end блоки

Последняя удобная функция — это блоки do/end. Блоки do/end эквивалентны ключевым словам в качестве последнего аргумента вызова функции, где содержимое блока заключено в скобки. Например:

if true do
  this
else
  that
end

эквивалентно:

if(true, do: (this), else: (that))

что мы рассмотрели в предыдущем разделе.

Скобки важны для поддержки нескольких выражений. Это:

if true do
  this
  that
end

эквивалентно:

if(true, do: (
  this
  that
))

Внутри блоков do/end вы можете вводить другие ключевые слова, такие как else, используемые в if выше. Поддерживаемые ключевые слова между do/end статичны и являются:

  • after
  • catch
  • else
  • rescue

Вы можете видеть их использование в конструкциях, таких как receive, try и других.

Резюме

Этот документ предоставляет справку по синтаксису Elixir, исследуя его конструкции и их эквиваленты в AST.

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

defmodule Math do
  def add(a, b) do
    a + b
  end
end

вместо

defmodule(Math, [
  {:do, def(add(a, b), [{:do, a + b}])}
])

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

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.8.2/syntax-reference.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API