Описания и области действия
Каждый идентификатор, встречающийся в программе, должен быть описан, если только это не предопределенный идентификатор. Идентификатор может быть описан как тип, константа, переменная, функция или метод, а так же как параметр в сигнатуре функции или метода, и как поле в типе класса.
Описание
: Описание-типа
| Описание-констант
| Описание-переменной
| Описание-функции
| Описание-метода
Области действия
Описанный идентификатор используется для ссылки на связанный объект, в тех частях программы, которые попадают в область действия описания. Идентификатор не может обозначать более одного объекта в пределах заданной области действия. Область действия может содержать внутри себя другие области действия, в которых идентификатор может быть переопределен.
Область действия, которая содержит в себе все исходные тексты на языке Тривиль называется Универсум.
Области действия:
- Областью действия предопределенного идентификатора является Универсум
- Областью действия идентификатора, описанного на верхнем уровне (вне какой-либо функции), является весь модуль.
- Областью действия идентификатора импортируемого модуля является файл (часть модуля), содержащего импорт.
- Областью действия идентификатора, обозначающего параметр функции, является тело функции.
- Областью действия идентификатора, описанного в теле функции или теле входа, является часть блока, в котором описан идентификатор, от точки завершения описания и до завершения этого блока.
В описании верхнего уровня за идентификатором может следовать признак экспорта *, указывающий, что идентификатор экспортирован и может использоваться в другом модуле, импортирующем данный.
Правило для опционально экспортированного идентификатора:
Идент-оп: Идентификатор '*'?
Предопределенные идентификаторы
Следующие идентификаторы неявно описаны в области действия Универсум.
Типы:
Байт Цел64 Слово64 Вещ64 Лог Символ Строка Строка8 Пусто
Константы типа Лог:
ложь истина
Литерал, обозначающий отсутствие значения для может быть типа:
пусто
длина тег нечто сигнатура
Кроме того, для векторных типов определен набор встроенных методов.
Описание констант
Описание константы связывает идентификатор с постоянным значением. Значение константы может быть задано явно или неявно, в случае группового описания констант.
Описание-констант: 'конст' (Константа | Группа-констант)
Константа: Идент-оп (':' Указ-типа)? '=' Выражение
Если тип константы не указан, то он устанавливается равным типу выражения. Выражение для константы должно быть константным выражением.
конст к1: Цел64 = 1 // тип Цел64
конст к2: Байт = 2 // тип Байт
конст к3 = 3 // тип Цел64
конст к4 = "Привет" // тип Строка
Групповое описание констант позволяет опускать тип и выражение для всех констант, кроме первой константы в группе и указать признак экспорт для всех констант группы.
Группа-констант:
'*'? '('
Константа (Разделитель След-константа)*
')'
След-константа: Идент-оп ((':' Указ-типа)? '=' Выражение)?
Пример группового экспорта:
конст *(
Счетчик = 1
Имя = "Вася"
)
Пример неявного задания значения для констант:
конст (
/ / операции
ПЛЮС = 1 // тип Цел64, значение = 1
МИНУС // тип Цел64, значение = 2
ОСТАТОК // тип Цел64, значение = 3
// ключевые слова
ЕСЛИ = 21 // тип Цел64, значение = 21
ИНАЧЕ // тип Цел64, значение = 22
ПОКА // тип Цел64, значение = 23
)
Описание переменных
Описание переменной создает переменную, привязывает к ней идентификатор и указывает её тип и начальное значение через Инициализацию.
Описание-переменной:
'пусть' Идент-оп (':' Указ-типа)? Инициализация
Инициализация: (':=' | '=') ('позже' | Выражение)
Если тип переменной не указан, то он устанавливается равным типу выражения.
Каждая переменная должна быть явно проинициализирована. Если инициализация задана через лексему =, то значениe переменной не может быть изменено (переменная с единственным присваиванием), если же в инициализации используется лексема :=, то значение может быть изменено, а переменная называется изменяемой.
Явное указание типа:
пусть ц1: Цел64 = 1
пусть ц2: Цел64 := 2
Неявное указание типа:
пусть ц3 = 3 // неявное указание типа
пусть ц4 := 4
пусть имя = Имя языка()
Компилятор выдает ошибку, при попытке изменить значение переменной с единственным присваиванием:
Изменение значения переменной с единственным присваиванием
ц1 := 2
ц3++
имя := "С++"
Если в инициализации задано Выражение, то начальным значением переменной является значение выражения. Если при этом тип переменной явно задан, то выражение должно быть совместимо по присваиванию с типом переменной.
Вместо выражения может быть указано ключевое слово позже, это поздняя инициализация. Такая форма инициализации разрешена только для переменных уровня модуля, при этом тип таких переменных, должен быть явно указан.
Значение переменной с поздней инициализацией должно быть задано в инициализации модуля. Текущая реализация компилятора запрещает позднюю инициализацию для переменных с единственным присваиванием.
Описание функций
Описание функции состоит из идентификатора, сигнатуры и тела функции. Сигнатура функции определяет формальные параметры и тип результата (если таковой имеется). Особым видом функции является метод.
Описание-функции: 'фн' Идент-оп Сигнатура-функции Тело
Сигнатура-функции: '(' Список-параметров? ')' Тип-результата?
Тип-результата: ':' ('*' | Указ-типа)
Тело: (Блок | Модификатор)?
Вместо тела функции может стоять модификтор @внеш.
Если у функции задан тип результата, тело функции должно завершаться операторами вернуть или авария на каждом пути управления.
Если в типе результата вместо указания типа использован символ *, то функция возвращает полиморфный результат. Такая функция может возвращать значение любого типа. Для работы с полиморфным значением определены специальные стандартные функции.
фн Факториал(ц: Цел64): Цел64 {
если ц <= 1 { вернуть 1 }
вернуть ц * Факториал(ц - 1)
}
Параметры
Формальные параметры - это идентификаторы, которые обозначают аргументы (фактические параметры), указанные при вызове функции.
Список-параметров: Параметр (',' Параметр)* ','?
Параметр:
Идентификатор (':' | ':=') '...'? ('*' | Указ-типа)
Параметры бывают двух видов: входные и выходные параметры. Вид параметра задается символом после идентификатора, задающего имя параметра. Для входных параметров это символ :, для выходных - символ :=. Выходной параметр, в более привычной терминологии, является in out параметром.
Аргументом для входного параметра должно быть выражение, тип которого совместим по присваиванию с типом параметра. Аргументом для выходного параметра должно быть изменяемое выражение, тип которого эквивалентен типу параметра.
В теле функции, входной параметр имеет значение, которое передается в функцию, изменяется функцией и передается обратно из функции для замены исходного значения.
фн извлечь число(стр: Строка, число:= Цел64): Лог {...}
пусть рез := 0
если ~ извлечь число(с, рез) {
вывод.ф("не удалось извлечь число")
}
Последний параметр функции может иметь тип с префиксом ... - это вариативный параметр. Функция с таким параметром может быть вызвана с нулем или более аргументов для этого параметра. Если тип вариативного параметра указан как Т, то в теле функции типом параметра является []T.
фн сумма(числа: ...Цел64): Цел64 {...}
// В вызове можно указать любое число аргументов
ответ := сумма() // без аргументов
ответ := сумма(1, 2, 3) // три аргумента
Полиморфные параметры
Если вместо типа параметра указан символ *, то параметр называется полиморфным. Аргумент, соотвествующий этому параметру, может быть выражением любого типа. Для вариативного полиморфного параметра каждый аргумент может быть выражением любого типа. Для работы с полиморфным параметром определены специальные стандартные функции.
фн печать по формату(формат: Строка, аргументы: ...*) {
...
}
Внешние функции
Функция, в которой вместо тела стоит модификатор @внеш, является внешней функцией, то есть реализованной каким-то внешним способом. Атрибут "имя" модификатора задает внешнее имя функции.
фн строка(с: Строка) @внеш("имя":"print_string")
Если атрибут “имя”\space не задан, внешнее имя совпадает с идентификатором функции.
Описание методов
Метод – это функция, связанная с типом классом. Для вызова метода должен быть указан экземпляр этого класса или расширенного класса. В описание метода класс, с которым связан метод указывается с помощью Привязки.
Описание-метода: 'фн' Привязка Идент-оп Сигнатура-функции Блок
Привязка: '(' Идентификатор ':' Указ-типа ')'
Привязка определяет идентификатор и тип, который должен быть типом класса. В теле функции идентификатор привязки является параметром указанного типа.
тип К = класс {}
фн (к: К) метод() {}
Идентификатор метода должен быть уникальным в классе среди идентификатором полей и методов.
В расширенном классе может быть определен метод с таким же идентификатором как в одном из базовых классов.
Переопределен, то есть опеределен другой метод.
При этом сигнатура переопределеного метода должна совпадать с сигнатуром переопределяемого метода, а именно:
- Число параметров должно совпадать
- Типы результата должны быть равны
- Типы параметров должны быть равны
- Признаки вариативности и полиморфности для каждого параметра должны совпадать
Пример ошибки при переопределении метода (разное число параметров):
Разное число параметров
тип К1 = класс (К) {}
фн (к: К1) метод(с: Строка) {}