Глава 12 Расширения языка
12 Атрибуты
(Введены в OCaml 4.02, инфиксные обозначения для конструкций, отличных от выражений, добавлены в 4.03)
Атрибуты — это «декорации» синтаксического дерева, которые в основном игнорируются проверяющим типы, но могут использоваться внешними инструментами. Атрибут состоит из идентификатора и полезной нагрузки, которая может быть структурой, выражением типа (префикс :), сигнатурой (префикс :) или шаблоном (префикс ?), необязательно после которого следует фраза when:
|
Первый вид атрибутов прикрепляется с помощью постфиксной записи к «алгебраическим» категориям:
Этот вид атрибутов также может быть вставлен после `tag-name в выражениях полиморфных вариантов (tag-spec-first, tag-spec, tag-spec-full) или после method-name в method-type.
Такая же синтаксическая форма также используется для прикрепления атрибутов к меткам и конструкторам в объявлениях типов:
|
Примечание: если за объявлением метки следует точка с запятой, атрибуты также можно поместить после точки с запятой (в этом случае они объединяются с теми, которые указаны ранее).
Второй вид атрибутов прикрепляется к «блокам», таким как объявления типов, поля классов и т. д.:
|
Третья форма атрибутов появляется как самостоятельные структуры или элементы сигнатуры в модулях или подязыках классов. Они не привязаны к какому-либо конкретному узлу в синтаксическом дереве:
|
(Примечание: вопреки тому, что описывает грамматика выше, 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)
12.1 Встроенные атрибуты
Некоторые атрибуты понимаются проверяющим типы:
- “ocaml.warning” или “warning”, со строковым литеральным значением. Это можно использовать в качестве плавающих атрибутов в сигнатуре/структуре/объекте/типе объекта. Строка парсится и имеет тот же эффект, что и командная опция -w, в области между атрибутом и концом текущей сигнатуры/структуры/объекта/типа объекта. Атрибут также может быть присоединён к любому виду синтаксических элементов, поддерживающих атрибуты (таким как выражение или выражение типа), в этом случае его область действия ограничивается этим элементом. Обратите внимание, что не определено однозначно, какая область действия используется для конкретного предупреждения. Это зависит от реализации и может меняться между версиями. Некоторые предупреждения даже полностью не подконтрольны “ocaml.warning” (например, предупреждения 1, 2, 14, 29 и 50).
- “ocaml.warnerror” или “warnerror”, со строковым литеральным значением. Аналогично “ocaml.warning”, для командной опции -warn-error.
- “ocaml.alert” или “alert”: см. раздел 12.21.
- “ocaml.deprecated” или “deprecated”: псевдоним для предупреждения “deprecated”, см. раздел 12.21.
- “ocaml.deprecated_mutable” или “deprecated_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. Подробности см. в 22.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 13.5.3) 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 13.5.3) 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-2024 INRIA.
https://ocaml.org/manual/5.2/attributes.html