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 в порядке от младшего элемента к старшему, сохраняет число записанных элементов массива в *count и возвращает true. Если массив magnitude недостаточно велик, функция сохраняет требуемый размер массива в *count, сигнализирует об ошибке и возвращает false. Если count не равен NULL, а magnitude равен NULL, функция сохраняет требуемый размер массива в *count и возвращает true.

Emacs гарантирует, что максимальное требуемое значение *count никогда не превышает min (PTRDIFF_MAX, SIZE_MAX) / sizeof (emacs_limb_t), поэтому для выделения массива magnitude можно использовать malloc (*count * sizeof *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, закодированный в UTF-8 и заданный параметром arg, в массиве 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, и вызовите функцию ещё раз с ненулевым buf (не NULL), чтобы выполнить копирование текста.

Функция: 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. Если значение index недопустимо, функция вызывает ошибку args-out-of-range.

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

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

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

Функция: 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 элементов, задающих модуль возвращаемого значения в порядке от младшего элемента к старшему.

В следующем примере библиотека GNU Multiprecision Library (GMP) используется для вычисления следующего вероятного простого числа после заданного целого числа. Общий обзор GMP см. в разделе (gmp)Введение, а сведения о преобразовании массива magnitude в значения GMP типа mpz_t и обратно — в разделе (gmp)Импорт и экспорт целых чисел.

#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);

  /* Assume Emacs is linked to the full GMP library,
     not to its mini-gmp subset that lacks mpz_nextprime.  */
  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)

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

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

Эта функция, доступная начиная с Emacs 27, принимает аргумент time типа struct timespec и возвращает соответствующую временную метку 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 или строкой с символами вне ASCII, закодированной в UTF-8; она может содержать встроенные нулевые байты и не обязана завершаться нулевым байтом в str[len]. Если len отрицательно или превышает максимальную длину строки Emacs, функция вызывает ошибку overflow-error. Если len равно нулю, str может быть NULL; в противном случае оно должно указывать на допустимую область памяти. При ненулевом значении len функция make_string возвращает уникальные изменяемые строковые объекты.

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

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

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-2026 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