Справочник по Ada (Ada 2022)
4.9 Статические выражения и статические подтипы
Некоторые выражения скалярного или строкового типа определены как статические. Аналогично, некоторые дискретные диапазоны определены как статические, а некоторые скалярные и строковые подтипы — как статические подтипы. Статический означает определяемый на этапе компиляции, используя объявленные свойства или значения сущностей программы.
Статическая семантика
Статическое выражение — это скалярное или строковое выражение, которое является одним из следующих:
- числовая константа numeric_literal числового типа;
- строковая константа string_literal статического строкового подтипа;
- идентификатор name, обозначающий объявление статической константы;
- идентификатор name, обозначающий именованное число, и интерпретируемый как значение числового типа;
- вызов функции function_call, у которого имя функции name или префикс функции prefix статически обозначает статическую функцию, и все фактические параметры, если таковые имеются (явные или по умолчанию), являются статическими выражениями;
- ссылка на атрибут attribute_reference, обозначающая скалярное значение, у которой префикс prefix обозначает статический скалярный подтип;
- ссылка на атрибут attribute_reference, у которой префикс prefix статически обозначает статически ограниченный массив или подтип массива, а атрибутный идентификатор attribute_designator равен First, Last или Length с необязательной размерностью;
- ссылка на атрибут attribute_reference, у которой префикс prefix обозначает негенерическую сущность, не объявленную в генерируемой единице, а атрибутный идентификатор attribute_designator равен Nonblocking;
- преобразование типа type_conversion, у которого метка подтипа subtype_mark обозначает статический (скалярный или строковый) подтип, а операнд — статическое выражение;
- квалифицированное выражение qualified_expression, у которого метка подтипа subtype_mark обозначает статический (скалярный или строковый) подтип, а операнд — статическое выражение;
- тест на принадлежность, у которого проверяемое выражение simple_expression является статическим выражением, а список вариантов принадлежности membership_choice_list состоит только из вариантов принадлежности membership_choice, которые являются либо статическими выражениями simple_expression, статическими диапазонами range или метками подтипа subtype_mark, обозначающими статический (скалярный или строковый) подтип;
- форма управления короткого замыкания, у обоих отношений relation являются статическими выражениями;
- условное выражение conditional_expression, у которого все условия condition, выбираемые выражения и зависящие выражения являются статическими выражениями;
- выражение объявления declare_expression, у которого выражение тела expression является статическим, и каждое из его объявлений, если таковые имеются, является либо объявлением статической константы, либо переименованием объекта object_renaming_declaration с именем объекта name, которое статически обозначает переименованный объект;
- статическое выражение в скобках.
Идентификатор name статически обозначает сущность, если он обозначает сущность и:
- Это прямой идентификатор direct_name, расширенное имя или строковая константа character_literal, и он обозначает объявление, отличное от переименования renaming_declaration; или
- Это ссылка на атрибут attribute_reference, у которой префикс prefix статически обозначает какую-то сущность; или
- Это имя целевого объекта target_name (см. 5.2.1) в операторе присваивания assignment_statement, у которого имя переменной name статически обозначает какую-то сущность; или
- Он обозначает переименование renaming_declaration с именем name, которое статически обозначает переименованную сущность.
Имя name статически называет объект, если:
- статически обозначает объявление объекта (возможно, через одно или несколько переименований);
- это компонент selected_component, у которого префикс статически называет объект, явного разыменования префикса нет, и имя селектора selector_name не обозначает объявление компонента component_declaration в части варианта variant_part; или
- это индексированный компонент indexed_component, у которого префикс статически называет объект, явного разыменования префикса нет, объект статически ограничен, и выражения индексов объекта являются статическими и имеют значения, находящиеся в диапазоне ограничения индекса.
Для сущности, отличной от объекта, имя name статически называет сущность, если имя name статически обозначает сущность.
Статическая функция — это одна из следующих:
- предопределенный оператор, у которого типы параметров и результата — все скалярные типы, ни один из которых не является потомком формального скалярного типа;
- предопределенный оператор отношения, у которого параметры — строкового типа, не являющегося потомком формального массива;
- предопределенный оператор конкатенации, у которого тип результата — строковый тип, не являющийся потомком формального массива;
- функция сдвига или поворота, связанная с модульным типом, объявленным в пакете Interfaces (см. B.2);
- перечисление константы;
- функция статического выражения (см. 6.8);
- определённый в языке атрибут, являющийся функцией, если префикс prefix обозначает статический скалярный подтип и типы параметров и результата — скалярные.
В любом случае, формальный подпрограмма генерируемого параметра не является статической функцией.
Статическая константа — это константный вид, объявленный полным объявлением константы или переименованием объекта object_renaming_declaration со статическим номинальным подтипом, имеющий значение, определяемое статическим скалярным выражением или статическим строковым выражением и удовлетворяющий всем ограничениям или предикатам, применимым к номинальному подтипу.
Статический диапазон — это диапазон range, границы которого — статические выражения, или ссылка на атрибут диапазона range_attribute_reference, эквивалентная такому диапазону. Статический discrete_range — это диапазон, являющийся статическим диапазоном или указанием подтипа subtype_indication, определяющим статический скалярный подтип. Базовый диапазон скалярного типа — статический диапазон, за исключением случаев, когда тип является потомком формального скалярного типа.
Статический подтип — это либо статический скалярный подтип, либо статический строковый подтип. Статический скалярный подтип — это неограниченный скалярный подтип, тип которого не является потомком формального типа, или ограниченный скалярный подтип, образованный наложением совместимого статического ограничения на статический скалярный подтип. Статический строковый подтип — это неограниченный строковый подтип, у которого подтип индекса и подтип компонента являются статическими, или ограниченный строковый подтип, образованный наложением совместимого статического ограничения на статический строковый подтип. В любом случае, подтип генерируемого формального объекта в режиме in out и подтип результата генерируемой формальной функции не являются статическими. Кроме того, подтип не является статическим, если к нему применимы спецификации Dynamic_Predicate.
Различные типы статических ограничений определяются следующим образом:
- Нулевое ограничение всегда является статическим;
- Скалярное ограничение является статическим, если оно не имеет ограничения диапазона range_constraint или имеет статический диапазон;
- Ограничение индекса является статическим, если каждый discrete_range статический, и каждый тип подтипа индекса соответствующего массива является статическим;
- Ограничение дискриминанта является статическим, если каждое выражение ограничения статическое, и тип подтипа каждой дискриминанты является статическим.
В любом случае, ограничение первого подтипа скалярного формального типа не является ни статическим, ни нулевым.
Подтип является статически ограниченным, если он ограничен, а его ограничение статическое. Объект является статически ограниченным, если его номинальный подтип статически ограничен или если это статическая строковая константа.
Правила легальности
Выражение является статически неоцениваемым, если оно является частью:
- правого операнда статической формы короткого замыкания, значение которой определяется левым операндом; или
- dependent_выражения выражения_if, связанное с условием которого является статическим и равно False; или
- условие или dependent_выражение выражения_if, где условие, соответствующее по крайней мере одному предыдущему dependent_выражению выражения_if, является статическим и равно True; или
- dependent_выражение выражения_case, чьё selecting_выражение является статическим и чьё значение не покрывается соответствующим discrete_choice_list; или
- choice_simple_expression (или simple_expression диапазона диапазон, который встречается как membership_choice membership_choice_list) статического теста принадлежности, перед которым в окружающем membership_choice_list находится другой элемент, чей индивидуальный тест принадлежности (см. 4.5.2) статически дает True.
Статическое выражение оценивается во время компиляции, за исключением случаев, когда оно статически неоцениваемо. Оценка статического выражения во время компиляции выполняется точно, без выполнения Overflow_Checks. Для статического выражения, которое оценивается:
- Выражение является недопустимым, если его оценка не прошла проверку, определённую языком, отличную от Overflow_Check. В целях этой оценки предполагается, что политика утверждения равна Check.
- Если выражение не является частью более крупного статического выражения и выражение ожидается быть одного конкретного типа, то его значение должно находиться в базовом диапазоне ожидаемого типа. В противном случае значение может быть произвольно большим или малым.
- Если выражение имеет тип universal_real, а ожидаемый тип является десятичным типом с фиксированной точкой, то его значение должно быть кратным small десятичного типа. Это ограничение не применяется, если ожидаемый тип является потомком формального скалярного типа (или соответствующего фактического типа в экземпляре).
Помимо мест, где обычно применяются правила легальности (см. 12.3), вышеуказанные ограничения также применяются в частях экземпляра обобщенного блока.
Требования к реализации
Для вещественного статического выражения, которое не является частью более крупного статического выражения и чей ожидаемый тип не является потомком формального типа, реализация должна округлить или усечь значение (в соответствии с атрибутом Machine_Rounds ожидаемого типа) до ближайшего машинного числа ожидаемого типа; если значение находится ровно посередине между двумя машинными числами, выполняемое округление определяется реализацией. Если ожидаемый тип является потомком формального типа или если статическое выражение появляется в теле экземпляра обобщенного блока, а соответствующее выражение в соответствующем обобщенном блоке не является статическим, то специальное округление или усечение не требуется — применяются обычные правила точности (см. Приложение G).
Рекомендации по реализации
Для вещественного статического выражения, которое не является частью более крупного статического выражения, и чей ожидаемый тип не является потомком формального типа, округление должно быть таким же, как и стандартное округление для целевой системы.
ПРИМЕЧАНИЕ 1 Выражение может быть статическим, даже если оно встречается в контексте, где статичность не требуется.
ПРИМЕЧАНИЕ 2 Статический (или выполняемый во время выполнения) type_conversion из вещественного типа в целочисленный тип выполняет округление. Если значение операнда находится ровно посередине между двумя целыми числами, округление выполняется от нуля.
Примеры
Примеры статических выражений:
1 + 1 -- 2
abs(-10)*3 -- 30
abs(-10)*3 -- 30
Kilo : constant := 1000;
Mega : constant := Kilo*Kilo; -- 1_000_000
Long : constant := Float'Digits*2;
Mega : constant := Kilo*Kilo; -- 1_000_000
Long : constant := Float'Digits*2;
Half_Pi : constant := Pi/2; -- см. 3.3.2
Deg_To_Rad : constant := Half_Pi/90;
Rad_To_Deg : constant := 1.0/Deg_To_Rad;
-- эквивалентно 1.0/((3.14159_26536/2)/90)
Deg_To_Rad : constant := Half_Pi/90;
Rad_To_Deg : constant := 1.0/Deg_To_Rad;
-- эквивалентно 1.0/((3.14159_26536/2)/90)