Нативные типы
Нативные типы данных
Нативными (машинными) данными могут быть как переменные, так и функции, а имя нативных объектов начинается на символ процента “%”.
В случае переменных, это двоичные данные, которые располагаются в одной неразрывной области машинной памяти по определенному адресу и имеют строго определенный формат.
Чтобы использовать уже существующие библиотеки, нужно либо импортировать нативный объект, тем самым создав объкт TrustLang, но с реализацией на другом языке, например на С/С++, либо сделать предварительное определение (декларацию) нативного объекта.
Импорт нативных объектов
Импорт — связывание trust-имени функции/переменной с именем существующей нативной функции/переменной. В отличие от предварительного объявления, импортируемая функция регистрируется под своим trust-именем, а её имя и аргументы могут отличаться от имени и аргументов импортируемой нативной функции.
Синтаксис такой же, как у создания обычных объектов, только правым операндом указывается имя нативного объекта. Типы аргументов и возвращаемого значения всегда указываются явно.
-
Если типы регистрируемой и нативной функции совпадают (преобразование не требуется), нативное имя можно указать с многоточием — оно означает, что аргументы вызова повторяют аргументы левой сигнатуры (дублировать их не нужно):
sqr(x:Float64):Float64 := %std::sqrt...; # аргументы как у sqr -
В общем случае аргументы и тип импортируемой функции задаются явно; при генерации вставляется вызов правой функции, а при необходимости аргументы приводятся через
static_cast:sqr(x:Float64):Float64 := %std::sqrt(x:Float128, true):Float128;
При импорте аргументы автоматически преобразуются к нативным типам импортируемой функции. Импорт может выполняться во время компиляции программы или во время выполнения (динамическая загрузка библиотеки).
:FILE ::= :Plain;
fopen(filename:StrChar, modes:StrChar):FILE := %fopen...;
fclose(f:FILE):Int32 := %fclose...;
fflush(f:FILE):Int32 := %fflush...;
fprintf(f:FILE, format:FmtChar, ...):Int32 := %fprintf...;
fremove(filename:String):Int32 := :Native('%remove...');
frename(old:String, new:String):Int32 := :Native('%rename...');
Если нативная функция/переменная требует линковки внешней библиотеки, имя библиотеки
указывается атрибутом @[link("имя")]@ перед декларацией. Атрибут добавляет флаг -l<имя>
к шагу линковки (build.conf LIBS). Существование символа/библиотеки не проверяется —
ответственность линковщика. Поддерживается только статическая линковка.
@[link("m")]@
fsqrt(x:Float64):Float64 := %sqrt...;
@[link("z")]@
fcrc(crc:UInt32):UInt32 := %crc32...;
Предварительное объявление нативных объектов
Предварительное объявление (forward-declaration) — регистрация нативной функции/переменной,
имя которой и есть нативный C-style идентификатор (напр. %sqrt — функция sqrt). Имя и аргументы
объявляемой функции совпадают с нативной сигнатурой — никакой адаптации не выполняется.
Реализация может быть расположена ниже в текущем файле или во внешней библиотеке — линковщик найдёт
символ по имени на этапе сборки.
Правило линковки нативного имени: если оно без :: (напр. %sqrt, %open, %abs) — декларация
линкуется как C-символ (extern "C"), что позволяет корректно вызывать функции libc/libm;
если имя содержит :: (напр. %std::sqrt) — как C++-символ (extern "C" не добавляется).
Синтаксис такой же, как у создания, но нативное имя стоит слева, а справа — символ многоточия (тела нет). Типы аргументов и возвращаемого значения указываются явно.
%open(path:StrChar, flags:Int32):Int32 := ...;
%close(fd:Int32):Int32 := ...;
%read(fd:Int32, buf:Buffer, cnt:SizeT):SizeT := ...;
/*
int fd, sz;
char* c = (char*)calloc(100, sizeof(char));
fd = open("foo.txt", O_RDONLY);
if (fd < 0) {
perror("r1");
exit(1);
}
sz = read(fd, c, 10);
printf("called read(% d, c, 10). returned that"
" %d bytes were read.\n",
fd, sz);
c[sz] = '\0';
printf("Those bytes are as follows: % s\n", c);
*/
%fd^:Int32 := 0;
%sz^:SizeT := 0;
%buf^:StrChar := StrChar( :Tensor[100](0, ... ) );
fd = %open("foo.txt", O_RDONLY);
if (fd < 0) {
@perror("r1");
@exit(1);
}
sz = %read(fd, buf, 10);
%printf("called read(%d, buf, 10). returned that"
" %d bytes were read.\n",
fd, sz);
buf[sz] = 0';
%printf("Those bytes are as follows: %s\n", :Pointer(buf));
Последующее описание находится в процессе разработки.
:Pointer — указатель на системную область памяти или нативную функцию
⚠️ НЕ РЕАЛИЗОВАНО: тип :Pointer и его использование в текущей версии не реализованы; ввод/вывод через системные типы (FILE, Buffer, SizeT) не соответствует текущей реализации. Нижеследующий пример устарел
Так как любой программе приходится взаимодействовать с внешним миром, то по неволе приходится закладывать возможность использования других библиотек и системы типов данных, и для этих целей служит тип :Pointer. Он создается при импорте функций из внешних библиотек и вручную адрес в памяти указать нельзя. Но его значение можно вывести, например для отладки.
:Binary Иштфкн Plain — указатель на представление данных в бинарном виде
Для взаимодействия с внешними библиотеками требуется еще и обмен данными. И для этих целей служит тип данных :Plain — который также является указателем, но на двоичное представление данных в области памяти. Конечно, если их можно представить в виде одного фрагмента.
Перечисление, структура и объединение
Некоторые типы данных являются полными аналогами нативных типов, что требуется для взаимодействия с внешними библиотеками, в том числе и для блоков кода с нативным синтаксисом.
https://habr.com/ru/companies/otus/articles/770404/
C++98: std::map, std::set, std::multimap и std::multiset
C++11: std::unordered_map, std::unordered_set, std::unordered_multimap и std::unordered_multiset
C++23: std::flat_map, std::flat_set, std::flat_multimap и std::flat_multiset
std::list, std::deque и т.д.
:Map, :MultiMap :Pair???????????????????????????????????????
:StrChar, :StrWide, :Array, :Set, :Struct, :Union, :Enum и :Optional — это такие же словари или перечисления, но на их элементы накладываются определённые ограничения. Каждый элемент должен иметь уникальное имя, а его тип данных должен быть простым, т.е. числом или строкой фиксированного размера. Типы данных :Plain могут быть представлены в двоичном виде в одной области машинной памяти и бинарно совместимы с соответствующими типами данных C/C++.