Spec-Zone.ru › Elisp

Преобразование между значениями Lisp и модуля

Практически все модули должны обмениваться данными с программами Lisp, которые их вызывают: принимать аргументы функций модуля и возвращать значения из функций модуля. Для этой цели модуль API предоставляет тип emacs_value, который представляет объекты Emacs Lisp, передаваемые через API; он функционально эквивалентен типу Lisp_Object , используемому в Emacs C-примитивах (см. Написание Emacs-примитивов). В этом разделе описываются части модуля API, которые позволяют создавать объекты emacs_value , соответствующие основным типам данных Lisp, и как получить данные C из объектов emacs_value , соответствующих объектам Lisp.

Все описанные ниже функции на самом деле являются указателями на функции, предоставляемые через указатель на среду, который принимает каждая функция модуля. Поэтому код модуля должен вызывать эти функции через указатель на среду, как показано ниже:

emacs_env *env;  /* the environment pointer */
env->some_function (arguments…);

Указатель emacs_env обычно поступает из первого аргумента функции модуля или из вызова get_environment , если вам нужна среда в функции инициализации модуля.

Большинство функций, описанных ниже, стали доступны в Emacs 25, первой версии Emacs, поддерживающей динамические модули. Для нескольких функций, ставших доступными в более поздних версиях Emacs, мы указываем первую версию Emacs, в которой они появились.

Следующие функции API извлекают значения различных типов данных C из объектов emacs_value . Все они поднимают условие ошибки wrong-type-argument (см. Предикаты типов), если аргумент emacs_value объект не имеет ожидаемого типом функции. Подробности о работе с ошибками в модулях Emacs и о том, как перехватывать условия ошибок внутри модуля, прежде чем они будут сообщены Emacs, см. в разделе Нелокальные модули. Функция API type_of (см. type_of) может использоваться для получения типа объекта emacs_value .

Функция: intmax_t extract_integer (emacs_env *env, emacs_value arg)

Эта функция возвращает значение целого числа Lisp, указанного arg. Тип данных C возвращаемого значения, intmax_t, является самым широким типом целочисленных данных, поддерживаемым компилятором C, обычно long long. Если значение arg не помещается в intmax_t, функция сигнализирует об ошибке, используя символ ошибки overflow-error.

Функция: bool extract_big_integer (emacs_env *env, emacs_value arg, int *sign, ptrdiff_t *count, emacs_limb_t *magnitude)

Эта функция, доступная начиная с Emacs 27, извлекает целое значение arg. Значение arg должно быть целым числом (fixnum или bignum). Если sign не NULL, он сохраняет знак arg (-1, 0 или +1) в *sign. Величина сохраняется в magnitude следующим образом. Если count и magnitude оба не NULL, то magnitude должен указывать на массив длиной не менее *count unsigned long элементов. Если magnitude достаточно велик для хранения величины arg, то функция записывает величину в массив magnitude в формате little-endian, сохраняет количество записанных элементов в *count, и возвращает true. Если magnitude недостаточно велик, он сохраняет необходимый размер массива в *count, сигнализирует об ошибке и возвращает false. Если count не NULL и magnitude NULL, то функция сохраняет необходимый размер массива в *count и возвращает true.

Emacs гарантирует, что максимальное необходимое значение *count никогда не превышает min (PTRDIFF_MAX, SIZE_MAX) / sizeof (emacs_limb_t), поэтому вы можете использовать malloc (*count * sizeof *magnitude) для выделения массива magnitude без опасений целочисленного переполнения при расчёте размера.

Тип алиаса: emacs_limb_t

Это тип беззнакового целого числа, используемый в качестве типа элементов для массивов величин в функциях преобразования больших целых чисел. Тип гарантирует уникальные представления объектов, т.е. без битов заполнения.

Макрос: EMACS_LIMB_MAX

Этот макрос расширяется до константного выражения, определяющего максимальное возможное значение для объекта emacs_limb_t . Выражение подходит для использования в #if.

Функция: double extract_float (emacs_env *env, emacs_value arg)

Эта функция возвращает значение Lisp-числа с плавающей запятой, указанное arg, как значение C double .

Функция: struct timespec extract_time (emacs_env *env, emacs_value arg)

Эта функция, доступная начиная с Emacs 27, интерпретирует arg как значение времени Emacs Lisp и возвращает соответствующее значение struct timespec. См. Время суток. struct timespec представляет собой временную метку с наносекундной точностью. Она имеет следующие члены:

time_t tv_sec

Целочисленное значение секунд.

long tv_nsec

Дробная часть секунд как число наносекунд. Для временных меток, возвращаемых extract_time, это всегда неотрицательное значение, меньшее одного миллиарда. (Хотя POSIX требует, чтобы тип tv_nsec был long, тип long long на некоторых нестандартных платформах).

См. (libc)Время выполнения.

Если time имеет более высокую точность, чем наносекунды, функция усекает ее до наносекундной точности в сторону отрицательной бесконечности. Функция сигнализирует об ошибке, если time (усеченное до наносекунд) не может быть представлено struct timespec. Например, если time_t является 32-битным целочисленным типом, то значение time в десять миллиардов секунд вызовет ошибку, но значение time в 600 пикосекунд будет усечено до нуля.

Если вам необходимо работать со значениями времени, не представимыми типом struct timespec, или если вам нужна более высокая точность, вызовите функцию Lisp encode-time и работайте со значением, которое она возвращает. См. Преобразование времени.

Функция: bool copy_string_contents (emacs_env *env, emacs_value arg, char *buf, ptrdiff_t *len)

Эта функция сохраняет текст Lisp-строки, заданной arg в кодировке UTF-8, в массив char, указанный buf, который должен быть достаточно большим, чтобы содержать не менее *len байтов, включая завершающий нулевой байт. Аргумент len не должен быть указателем NULL, и, при вызове функции, он должен указывать на значение, определяющее размер buf в байтах.

Если размер буфера, указанный *len, достаточно велик для хранения текста строки, функция сохраняет в *len фактическое количество скопированных байтов в buf, включая завершающий нулевой байт, и возвращает true. Если буфер слишком мал, функция поднимает условие ошибки args-out-of-range, сохраняет необходимое количество байтов в *len, и возвращает false. См. Нелокальные модули для обработки ожидаемых условий ошибки.

Аргумент buf может быть указателем NULL, в этом случае функция сохраняет в *len количество байтов, необходимых для хранения содержимого arg, и возвращает true. Таким образом вы можете определить размер buf, необходимый для хранения конкретной строки: сначала вызовите copy_string_contents с NULL как buf, затем выделите достаточно памяти, чтобы сохранить количество байтов, сохранённых функцией в *len, и вызовите функцию снова с не-NULL buf для фактического копирования текста.

Функция: emacs_value vec_get (emacs_env *env, emacs_value vector, ptrdiff_t index)

Эта функция возвращает элемент массива vector по индексу index. Индекс первого элемента массива равен нулю. Функция поднимает условие ошибки args-out-of-range если значение index некорректно. Для извлечения данных C из возвращаемого значения используйте другие функции извлечения, подходящие для типа данных Lisp, хранящихся в этом элементе массива.

Функция: ptrdiff_t vec_size (emacs_env *env, emacs_value vector)

Эта функция возвращает количество элементов в vector.

Функция: void vec_set (emacs_env *env, emacs_value vector, ptrdiff_t index, emacs_value value)

Эта функция сохраняет value в элементе массива vector с индексом index. Она поднимает условие ошибки args-out-of-range если значение index некорректно.

Следующие функции API создают объекты emacs_value из основных типов данных C. Все они возвращают созданный объект emacs_value .

Функция: emacs_value make_integer (emacs_env *env, intmax_t n)

Эта функция принимает целочисленный аргумент n и возвращает соответствующий объект emacs_value . Она возвращает либо fixnum, либо bignum, в зависимости от того, находится ли значение n в пределах, установленных most-negative-fixnum и most-positive-fixnum (см. Основы целых чисел).

Функция: emacs_value make_big_integer (emacs_env *env, int sign, ptrdiff_t count, const emacs_limb_t *magnitude)

Эта функция, доступная начиная с Emacs 27, принимает целое число произвольной длины и возвращает соответствующий объект emacs_value. Аргумент sign определяет знак возвращаемого значения. Если sign отличен от нуля, то magnitude должен указывать на массив, содержащий не менее count элементов, определяющих представление возвращаемого значения в формате little-endian.

В следующем примере используется библиотека GNU для работы с большими числами (GMP) для вычисления следующего вероятного простого числа после заданного целого числа. См. (gmp)Top для общего обзора GMP и (gmp)Integer Import and Export для преобразования массива magnitude в значения GMP mpz_t и обратно.

#include <emacs-module.h>
int plugin_is_GPL_compatible;

#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include <gmp.h>

static void
memory_full (emacs_env *env)
{
  static const char message[] = "Memory exhausted";
  emacs_value data = env->make_string (env, message,
                                       strlen (message));
  env->non_local_exit_signal
    (env, env->intern (env, "error"),
     env->funcall (env, env->intern (env, "list"), 1, &data));
}

enum
{
  order = -1, endian = 0, nails = 0,
  limb_size = sizeof (emacs_limb_t),
  max_nlimbs = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
                / limb_size)
};

static bool
extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
{
  ptrdiff_t nlimbs;
  bool ok = env->extract_big_integer (env, arg, NULL, &nlimbs, NULL);
  if (!ok)
    return false;
  assert (0 < nlimbs && nlimbs <= max_nlimbs);
  emacs_limb_t *magnitude = malloc (nlimbs * limb_size);
  if (magnitude == NULL)
    {
      memory_full (env);
      return false;
    }
  int sign;
  ok = env->extract_big_integer (env, arg, &sign, &nlimbs, magnitude);
  assert (ok);
  mpz_import (result, nlimbs, order, limb_size, endian, nails, magnitude);
  free (magnitude);
  if (sign < 0)
    mpz_neg (result, result);
  return true;
}

static emacs_value
make_big_integer (emacs_env *env, const mpz_t value)
{
  size_t nbits = mpz_sizeinbase (value, 2);
  int bitsperlimb = CHAR_BIT * limb_size - nails;
  size_t nlimbs = nbits / bitsperlimb + (nbits % bitsperlimb != 0);
  emacs_limb_t *magnitude
    = nlimbs <= max_nlimbs ? malloc (nlimbs * limb_size) : NULL;
  if (magnitude == NULL)
    {
      memory_full (env);
      return NULL;
    }
  size_t written;
  mpz_export (magnitude, &written, order, limb_size, endian, nails, value);
  assert (written == nlimbs);
  assert (nlimbs <= PTRDIFF_MAX);
  emacs_value result = env->make_big_integer (env, mpz_sgn (value),
                                              nlimbs, magnitude);
  free (magnitude);
  return result;
}

static emacs_value
next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
            void *data)
{
  assert (nargs == 1);
  mpz_t p;
  mpz_init (p);
  extract_big_integer (env, args[0], p);
  mpz_nextprime (p, p);
  emacs_value result = make_big_integer (env, p);
  mpz_clear (p);
  return result;
}

int
emacs_module_init (struct emacs_runtime *runtime)
{
  emacs_env *env = runtime->get_environment (runtime);
  emacs_value symbol = env->intern (env, "next-prime");
  emacs_value func
    = env->make_function (env, 1, 1, next_prime, NULL, NULL);
  emacs_value args[] = {symbol, func};
  env->funcall (env, env->intern (env, "defalias"), 2, args);
  return 0;
}
Функция: emacs_value make_float (emacs_env *env, double d)

Эта функция принимает аргумент double d и возвращает соответствующее значение с плавающей точкой Emacs.

Функция: emacs_value make_time (emacs_env *env, struct timespec time)

Эта функция, доступная начиная с Emacs 27, принимает аргумент struct timespec time и возвращает соответствующую временную метку Emacs в виде пары (ticks . hz). См. Время суток. Возвращаемое значение представляет точно такую же временную метку, что и time: все входные значения могут быть представлены, и точность никогда не теряется. time.tv_sec и time.tv_nsec могут быть произвольными значениями. В частности, нет требования, чтобы time была нормализована. Это означает, что time.tv_nsec может быть отрицательным или больше 999 999 999.

Функция: emacs_value make_string (emacs_env *env, const char *str, ptrdiff_t len)

Эта функция создаёт строку Emacs из C-строки, указанной str, длина которой в байтах, не включая завершающий нулевой байт, равна len. Исходная строка в str может быть как строкой ASCII, так и строкой UTF-8 с не-ASCII символами; она может содержать вложенные нулевые байты и не должна заканчиваться завершающим нулевым байтом в str[len]. Функция вызывает ошибку overflow-error если len отрицательное или превышает максимальную длину строки Emacs. Если len равно нулю, то str может быть NULL, в противном случае он должен указывать на допустимую область памяти. Для ненулевого len, make_string возвращает уникальные изменяемые строковые объекты.

Функция: emacs_value make_unibyte_string (emacs_env *env, const char *str, ptrdiff_t len)

Эта функция аналогична make_string, но не имеет ограничений на значения байтов в C-строке и может использоваться для передачи двоичных данных в Emacs в виде строки unibyte.

API не предоставляет функций для манипулирования списками Lisp, например, создания списков с cons и list (см. Создание списков), извлечения элементов списка с car и cdr (см. Элементы списка), создания векторов с vector (см. Функции векторов) и т. д. Для этого используйте intern и funcall, описанные в следующем подразделе, чтобы вызвать соответствующие функции Lisp.

Обычно объекты emacs_value имеют довольно короткий срок жизни: он заканчивается, когда указатель emacs_env , используемый для их создания, выходит из области видимости. Иногда вам может потребоваться создать глобальные ссылки: объекты emacs_value , которые живут так долго, как вам нужно. Используйте следующие две функции для управления такими объектами.

Функция: emacs_value make_global_ref (emacs_env *env, emacs_value value)

Эта функция возвращает глобальную ссылку для value.

Функция: void free_global_ref (emacs_env *env, emacs_value global_value)

Эта функция освобождает global_value, ранее созданный функцией make_global_ref. global_value больше недействителен после вызова. Ваш модульный код должен сопоставить каждый вызов make_global_ref с соответствующим free_global_ref.

Альтернативой сохранению C-структур данных, которые необходимо передать функциям модуля позже, является создание объектов пользовательского указателя. Объект пользовательского указателя, или user-ptr, представляет собой объект Lisp, который инкапсулирует указатель C и может иметь связанную функцию-финализатор, которая вызывается при сборе мусора объекта (см. Сбор мусора). Модульный API предоставляет функции для создания и доступа к объектам user-ptr . Эти функции вызывают ошибку wrong-type-argument , если они вызываются для объектов emacs_value, которые не представляют собой объект user-ptr.

Функция: emacs_value make_user_ptr (emacs_env *env, emacs_finalizer fin, void *ptr)

Эта функция создаёт и возвращает объект user-ptr , который оборачивает указатель C ptr. Функция-финализатор fin может быть указателем NULL (что означает отсутствие финализатора) или функцией со следующим сигнатуром:

typedef void (*emacs_finalizer) (void *ptr);

Если fin не является указателем NULL, она будет вызвана с ptr в качестве аргумента, когда объект user-ptr будет собран мусором. Не выполняйте никакие дорогостоящие вычисления в финализаторе, так как сборка мусора должна выполняться быстро, чтобы Emacs оставался отзывчивым.

Функция: void * get_user_ptr (emacs_env *env, emacs_value arg)

Эта функция извлекает указатель C из объекта Lisp, представленного arg.

Функция: void set_user_ptr (emacs_env *env, emacs_value arg, void *ptr)

Эта функция устанавливает указатель C, встроенный в объект user-ptr , представленный arg, в ptr.

Функция: emacs_finalizer get_user_finalizer (emacs_env *env, emacs_value arg)

Эта функция возвращает финализатор объекта user-ptr , представленного arg, или NULL , если у него нет финализатора.

Функция: void set_user_finalizer (emacs_env *env, emacs_value arg, emacs_finalizer fin)

Эта функция изменяет финализатор объекта user-ptr , представленного arg, на fin. Если fin является указателем NULL , объект user-ptr не будет иметь финализатора.

Обратите внимание, что тип emacs_finalizer работает как для финализаторов пользовательских указателей, так и для финализаторов функций модулей. См. Финализаторы функций модулей.

Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Module-Values.html

Spec-Zone.ru

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