« ^ »

Emacs Lispのシンボルを眺めつつfsetを調べる

所要時間: 約 2分

Emacs Lispのシンボルの定義を確認したくなった。

struct Lisp_Symbol
{
  union
  {
    struct
    {
      bool_bf gcmarkbit : 1;

      /* Indicates where the value can be found.  */
      ENUM_BF (symbol_redirect) redirect : 2;

      ENUM_BF (symbol_trapped_write) trapped_write : 2;

      /* Interned state of the symbol.  */
      ENUM_BF (symbol_interned) interned : 2;

      /* True means that this variable has been explicitly declared
	 special (with `defvar' etc), and shouldn't be lexically bound.  */
      bool_bf declared_special : 1;

      /* True if pointed to from purespace and hence can't be GC'd.  */
      bool_bf pinned : 1;

      /* The symbol's name, as a Lisp string.  */
      Lisp_Object name;

      /* Value of the symbol or Qunbound if unbound.  Which alternative of the
	 union is used depends on the `redirect' field above.  */
      union {
	Lisp_Object value;
	struct Lisp_Symbol *alias;
	struct Lisp_Buffer_Local_Value *blv;
	lispfwd fwd;
      } val;

      /* Function value of the symbol or Qnil if not fboundp.  */
      Lisp_Object function;

      /* The symbol's property list.  */
      Lisp_Object plist;

      /* Next symbol in obarray bucket, if the symbol is interned.  */
      struct Lisp_Symbol *next;
    } s;
    GCALIGNED_UNION_MEMBER
  } u;
};
src/lisp.h

name はシンボル名、 val は値セル function は関数セルといった感じだろうか。

ついでに fset の定義も確認する。

DEFUN ("fset", Ffset, Sfset, 2, 2, 0,
       doc: /* Set SYMBOL's function definition to DEFINITION, and return DEFINITION.
If the resulting chain of function definitions would contain a loop,
signal a `cyclic-function-indirection' error.  */)
  (register Lisp_Object symbol, Lisp_Object definition)
{
  CHECK_SYMBOL (symbol);
  /* Perhaps not quite the right error signal, but seems good enough.  */
  if (NILP (symbol) && !NILP (definition))
    /* There are so many other ways to shoot oneself in the foot, I don't
       think this one little sanity check is worth its cost, but anyway.  */
    xsignal1 (Qsetting_constant, symbol);

  eassert (valid_lisp_object_p (definition));

  /* Ensure non-circularity.  */
  for (Lisp_Object s = definition; SYMBOLP (s) && !NILP (s);
       s = XSYMBOL (s)->u.s.function)
    if (EQ (s, symbol))
      xsignal1 (Qcyclic_function_indirection, symbol);

#ifdef HAVE_NATIVE_COMP
  register Lisp_Object function = XSYMBOL (symbol)->u.s.function;

  if (!NILP (Vnative_comp_enable_subr_trampolines)
      && SUBRP (function)
      && !SUBR_NATIVE_COMPILEDP (function))
    CALLN (Ffuncall, Qcomp_subr_trampoline_install, symbol);
#endif

  set_symbol_function (symbol, definition);

  return definition;
}
src/data.c

いろいろな処理を行っているが、本質的な部分は最後の方に実行している set_symbol_function (symbol, definition); となる。そこで set_symbol_function についても確認する。

INLINE void
set_symbol_function (Lisp_Object sym, Lisp_Object function)
{
  XSYMBOL (sym)->u.s.function = function;
}
src/lisp.h

(sym)->u.s.function は第1引数に渡したLisp_Object symの共用体uの先頭に配置されている構造体sの function スロットだ。そこに第2引数に渡したLisp_Object functionを代入している。なるほど。少し理解できた。