Spec-Zone.ru › OCaml 4.14

10.12 Атрибуты

  • 10.12.1 Встроенные атрибуты

(Введены в OCaml 4.02, инфиксные обозначения для конструкций, отличных от выражений, добавлены в 4.03)

Атрибуты — это «декорации» синтаксического дерева, которые в основном игнорируются проверяющим типов, но могут использоваться внешними инструментами. Атрибут состоит из идентификатора и полезной нагрузки, которая может быть структурой, выражением типа (с префиксом :), сигнатурой (с префиксом :) или шаблоном (с префиксом ?) необязательно с последующим пунктом when:

attr-id ::= lowercase-ident
∣ capitalized-ident
∣ attr-id . attr-id
attr-payload ::= [ module-items ]
∣ : typexpr
∣ : [ specification ]
∣ ? pattern [when expr]

Первый вид атрибутов добавляется с использованием постфиксной нотации к «алгебраическим» категориям:

attribute ::= [@ attr-id attr-payload ]
expr ::= ...
∣ expr attribute

Этот вид атрибутов также может быть вставлен после `tag-name в выражениях полиморфных вариантов (tag-spec-first, tag-spec, tag-spec-full) или после method-name в method-type.

Такая же синтаксическая форма используется также для добавления атрибутов к меткам и конструкторам в объявлениях типов:

field-decl ::= [mutable] field-name : poly-typexpr { attribute }
constr-decl ::= (constr-name ∣ ()) [ of constr-args ] { attribute }

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

Второй вид атрибутов добавляется к «блокам», таким как объявления типов, поля классов и т. д.:

item-attribute ::= [@@ attr-id attr-payload ]
typedef ::= ...
∣ typedef item-attribute
exception-definition ::= exception constr-decl
∣ exception constr-name = constr
module-items ::= [;;] ( definition ∣ expr { item-attribute } ) { [;;] definition ∣ ;; expr { item-attribute } } [;;]
class-binding ::= ...
∣ class-binding item-attribute
class-spec ::= ...
∣ class-spec item-attribute
classtype-def ::= ...
∣ classtype-def item-attribute
definition ::= let [rec] let-binding { and let-binding }
∣ external value-name : typexpr = external-declaration { item-attribute }
∣ type-definition
∣ exception-definition { item-attribute }
∣ class-definition
∣ classtype-definition
∣ module module-name { ( module-name : module-type ) } [ : module-type ] = module-expr { item-attribute }
∣ module type modtype-name = module-type { item-attribute }
∣ open module-path { item-attribute }
∣ include module-expr { item-attribute }
∣ module rec module-name : module-type = module-expr { item-attribute } { and module-name : module-type = module-expr { item-attribute } }
specification ::= val value-name : typexpr { item-attribute }
∣ external value-name : typexpr = external-declaration { item-attribute }
∣ type-definition
∣ exception constr-decl { item-attribute }
∣ class-specification
∣ classtype-definition
∣ module module-name : module-type { item-attribute }
∣ модуль module-name { ( module-name : module-type ) } : module-type { item-attribute }
∣ модуль тип modtype-name { item-attribute }
∣ модуль тип modtype-name = module-type { item-attribute }
∣ открытие module-path { item-attribute }
∣ включение module-type { item-attribute }
class-field-spec ::= ...
∣ class-field-spec item-attribute
class-field ::= ...
∣ class-field item-attribute

Третья форма атрибутов появляется как самостоятельные структуры или элементы сигнатуры в модулях или классах. Они не прикреплены к какому-либо конкретному узлу в синтаксическом дереве:

floating-attribute ::= [@@@ attr-id attr-payload ]
definition ::= ...
∣ floating-attribute
specification ::= ...
∣ floating-attribute
class-field-spec ::= ...
∣ floating-attribute
class-field ::= ...
∣ floating-attribute

(Примечание: вопреки тому, что описано в грамматике выше, item-attributes не могут быть присоединены к этим плавающим атрибутам в class-field-spec и class-field.)

Также можно указывать атрибуты с помощью инфиксной синтаксической конструкции. Например:

let[@foo] x = 2 in x + 1          === (let x = 2 [@@foo] in x + 1)
begin[@foo][@bar x] ... end       === (begin ... end)[@foo][@bar x]
module[@foo] M = ...              === module M = ... [@@foo]
type[@foo] t = T                  === type t = T [@@foo]
method[@foo] m = ...              === method m = ... [@@foo]

Для let, атрибуты применяются к каждой привязке:

let[@foo] x = 2 and y = 3 in x + y === (let x = 2 [@@foo] and y = 3 in x + y)
let[@foo] x = 2
and[@bar] y = 3 in x + y           === (let x = 2 [@@foo] and y = 3 [@@bar] in x + y)

10.12.1 Встроенные атрибуты

Некоторые атрибуты понимаются проверкой типов:

  • «ocaml.warning» или «warning», со строковым литералом в качестве полезной нагрузки. Это можно использовать в качестве плавающих атрибутов в сигнатуре/структуре/объекте/типе объекта. Строка анализируется и имеет тот же эффект, что и командная опция -w, в области между атрибутом и концом текущей сигнатуры/структуры/объекта/типа объекта. Атрибут также может быть прикреплён к любому типу синтаксических элементов, поддерживающих атрибуты (таким как выражение или выражение типа), в этом случае его область действия ограничена этим элементом. Обратите внимание, что не определено, какая область действия используется для конкретного предупреждения. Это зависит от реализации и может меняться между версиями. Некоторые предупреждения даже полностью находятся вне контроля «ocaml.warning» (например, предупреждения 1, 2, 14, 29 и 50).
  • «ocaml.warnerror» или «warnerror», со строковым литералом в качестве полезной нагрузки. Аналогично «ocaml.warning», для командной опции -warn-error.
  • «ocaml.alert» или «alert»: см. раздел 10.21.
  • «ocaml.deprecated» или «deprecated»: псевдоним для предупреждения «deprecated», см. раздел 10.21.
  • «ocaml.deprecated_mutable» или «deprecated_mutable». Может быть применён к метке изменяемого (mutable) записей. Если метка используется позднее для изменения поля (с «expr.l <- expr»), будет сгенерировано предупреждение «deprecated». Если полезная нагрузка атрибута является строковым литералом, сообщение предупреждения включает этот текст.
  • «ocaml.ppwarning» или «ppwarning», в любом контексте, со строковым литералом в качестве полезной нагрузки. Текст отображается как предупреждение (22) компилятором (в настоящее время местоположение предупреждения находится в месте расположения строковой полезной нагрузки). Это в основном полезно для препроцессоров, которым нужно сообщать пользователю о предупреждениях. Это также можно использовать для явного обозначения некоторого местоположения кода для дальнейшего изучения.
  • «ocaml.warn_on_literal_pattern» или «warn_on_literal_pattern» аннотируют конструкторы в определении типа. Тогда генерируется предупреждение (52), когда этот конструктор сопоставляется с образцом константного литерала в качестве аргумента. Этот атрибут обозначает конструкторы, аргумент которых является чисто информативным и может измениться в будущем. Поэтому сопоставление с образцом по этому аргументу с константным литералом ненадежно. Например, все встроенные конструкторы исключений помечены как «warn_on_literal_pattern». Обратите внимание, что из-за ограничения реализации это предупреждение (52) срабатывает только для конструкторов с одним аргументом.
  • «ocaml.tailcall» или «tailcall» может быть применено к применению функции для проверки того, что вызов оптимизирован как хвостовая рекурсия. Если это не так, генерируется предупреждение (51).
  • «ocaml.inline» или «inline» принимают «never», «always» или ничего в качестве полезной нагрузки для определения функции или фукнтора. Если полезная нагрузка не указана, значение по умолчанию — «always». Эта полезная нагрузка управляет тем, когда приложения анотированных функций должны быть встроены.
  • «ocaml.inlined» или «inlined» может быть применено к любому применению функции или фукнтора, чтобы проверить, что вызов встроен компилятором. Если вызов не встроен, генерируется предупреждение (55).
  • «ocaml.noalloc», «ocaml.unboxed» и «ocaml.untagged» или «noalloc», «unboxed» и «untagged» могут быть использованы для внешних определений, чтобы получить более точный контроль над интерфейсом C-to-OCaml. Подробнее см. 20.11.
  • «ocaml.immediate» или «immediate», применённый к абстрактному типу, помечает тип как имеющий реализацию без указателей (например, «int», «bool», «char» или перечисляемые типы). Изменение этих немедленных типов не активирует барьер записи сборщика мусора, что может значительно повысить производительность программ, сильно зависящих от изменяемого состояния.
  • «ocaml.immediate64» или «immediate64», применённый к абстрактному типу, помечает тип как имеющий реализацию без указателей на 64-битных платформах. На других платформах предположений не делается. Для создания типа с атрибутом «immediate64» необходимо использовать фукнтор «Sys.Immediate64.Make».
  • ocaml.unboxed или unboxed можно использовать в определении типа, если тип является записью с одним полем или конкретным типом с одним конструктором, имеющим один аргумент. Это сообщает компилятору оптимизировать представление типа, удалив блок, представляющий запись или конструктор (т.е. значение этого типа физически равно его аргументу). В случае GADTs применяется дополнительное ограничение: аргумент не должен быть экзистенциальной переменной, представленной экзистенциальной переменной типа или конструктором абстрактного типа, применённым к экзистенциальной переменной типа.
  • ocaml.boxed или boxed можно использовать в определениях типов, что означает противоположное ocaml.unboxed: сохранить не оптимизированное представление типа. При отсутствии аннотации значение по умолчанию в настоящее время boxed, но оно может измениться в будущем.
  • ocaml.local или local принимают «never», «always», «maybe» или ничего в качестве полезной нагрузки для определения функции. Если полезная нагрузка не указана, значение по умолчанию — «always». Атрибут управляет оптимизацией, которая заключается в компиляции функции в статическое продолжение. В отличие от встраивания, эта оптимизация не дублирует тело функции. Это возможно, когда все ссылки на функцию — полные применения, все делящие одно и то же продолжение (например, возвращаемое значение нескольких ветвей сопоставления с образцом). never отключает оптимизацию, always утверждает, что оптимизация применяется (в противном случае выдается предупреждение 55), а maybe позволяет оптимизации применяться при необходимости (это поведение по умолчанию, когда атрибут не указан). Оптимизация неявным образом отключена при использовании компилятора байт-кода в режиме отладки (-g) и для функций, помеченных атрибутом ocaml.inline always или ocaml.unrolled, которые имеют приоритет над ocaml.local.
module X = struct
  [@@@warning "+9"]  (* locally enable warning 9 in this structure *)
  …
end
[@@deprecated "Please use module 'Y' instead."]

let x = begin[@warning "+9"] […] end

type t = A | B
  [@@deprecated "Please use type 's' instead."]
let fires_warning_22 x =
  assert (x >= 0) [@ppwarning "TODO: remove this later"]

Warning 22 [preprocessor]: TODO: remove this later
let rec is_a_tail_call = function
  | [] -> ()
  | _ :: q -> (is_a_tail_call[@tailcall]) q

let rec not_a_tail_call = function
  | [] -> []
  | x :: q -> x :: (not_a_tail_call[@tailcall]) q

Warning 51 [wrong-tailcall-expectation]: expected tailcall
let f x = x [@@inline]

let () = (f[@inlined]) ()
type fragile =
  | Int of int [@warn_on_literal_pattern]
  | String of string [@warn_on_literal_pattern]
let fragile_match_1 = function
| Int 0 -> ()
| _ -> ()

Warning 52 [fragile-literal-pattern]: Code should not depend on the actual values of
this constructor's arguments. They are only for information
and may change in future versions. (See manual section 11.5)
val fragile_match_1 : fragile -> unit = 
let fragile_match_2 = function
| String "constant" -> ()
| _ -> ()

Warning 52 [fragile-literal-pattern]: Code should not depend on the actual values of
this constructor's arguments. They are only for information
and may change in future versions. (See manual section 11.5)
val fragile_match_2 : fragile -> unit = 
module Immediate: sig
  type t [@@immediate]
  val x: t ref
end = struct
  type t = A | B
  let x = ref A
end
module Int_or_int64 : sig
  type t [@@immediate64]
  val zero : t
  val one : t
  val add : t -> t -> t
end = struct

  include Sys.Immediate64.Make(Int)(Int64)

  module type S = sig
    val zero : t
    val one : t
    val add : t -> t -> t
  end

  let impl : (module S) =
    match repr with
    | Immediate ->
        (module Int : S)
    | Non_immediate ->
        (module Int64 : S)

  include (val impl : S)
end

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/4.14/htmlman/attributes.html

Spec-Zone.ru

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