diff --git a/parsers/lisp.c b/parsers/lisp.c index 01ddef31cb..4e9a489c56 100644 --- a/parsers/lisp.c +++ b/parsers/lisp.c @@ -149,106 +149,121 @@ static int lisp_hint2kind (const vString *const hint) return k; } -/* TODO: implement this in hashtable. */ +/* Lookup code produced by gperf version 3.1 + * + * For example, run + * + * echo -e "(defconst\n(defmacro\n(defgroup\n(defalias" | gperf + * + * This is not included in the build process because gperf might not be + * available on all systems. + */ +static unsigned int hash_hint (const char *str, size_t len) +{ + static unsigned char asso_values[] = + { + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 8, 41, 30, + 41, 41, 0, 20, 41, 5, 41, 41, 41, 5, + 41, 41, 41, 41, 41, 0, 15, 15, 0, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41 + }; + return len + asso_values[(unsigned char)str[4]]; +} + static int elisp_hint2kind (const vString *const hint) { - int k = eK_UNKNOWN; - int n; - /* 4 means strlen("(def"). */ -#define EQN(X) strncmp(vStringValue (hint) + 4, &X[3], n) == 0 - switch (vStringLength (hint) - 4) +#define MIN_WORD_LENGTH 6 +#define MAX_WORD_LENGTH 31 +#define MAX_HASH_VALUE 40 + + static const struct { + const char *str; + int kind; + } tokens[] = { + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "(defvar", eK_VARIABLE, }, + { "(defface", eK_FACE, }, + { "(defsubst", eK_SUBST, }, + { "(defsubst*", eK_SUBST, }, + { "", eK_UNKNOWN, }, + { "(defvaralias", eK_VARALIAS, }, + { "(defvar-local", eK_VARIABLE, }, + { "(defmacro", eK_MACRO, }, + { "(defmacro*", eK_MACRO, }, + { "(define-key", KIND_GHOST_INDEX, }, + { "(defalias", eK_ALIAS, }, + { "(define-error", eK_ERROR, }, + { "(define-inline", eK_INLINE, }, + { "", eK_UNKNOWN, }, + { "(defun", eK_FUNCTION, }, + { "(defun*", eK_FUNCTION, }, + { "(define-minor-mode", eK_MINOR_MODE, }, + { "(deftheme", eK_THEME, }, + { "(define-derived-mode", eK_DERIVED_MODE, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "(defgroup", eK_GROUP, }, + { "(define-global-minor-mode", eK_MINOR_MODE, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "(define-globalized-minor-mode", eK_MINOR_MODE, }, + { "", eK_UNKNOWN, }, + { "(define-obsolete-function-alias", eK_ALIAS, }, + { "", eK_UNKNOWN, }, + { "", eK_UNKNOWN, }, + { "(defconst", eK_CONST, }, + { "(defcustom", eK_CUSTOM, }, + }; + + const char *const str = vStringValue (hint); + const size_t len = vStringLength (hint); + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { - case 2: - n = 2; - if (EQN("defun")) - k = eK_FUNCTION; - break; - case 3: - n = 3; - if (EQN("defvar")) - k = eK_VARIABLE; - else if (EQN("defun*")) - k = eK_FUNCTION; - break; - case 4: - n = 4; - if (EQN("defface")) - k = eK_FACE; - case 5: - n = 5; - if (EQN("defconst")) - k = eK_CONST; - else if (EQN("defmacro")) - k = eK_MACRO; - else if (EQN("defalias")) - k = eK_ALIAS; - else if (EQN("defsubst")) - k = eK_SUBST; - else if (EQN("defgroup")) - k = eK_GROUP; - else if (EQN("deftheme")) - k = eK_THEME; - break; - case 6: - n = 6; - if (EQN("defcustom")) - k = eK_CUSTOM; - else if (EQN("defsubst*")) - k = eK_SUBST; - else if (EQN("defmacro*")) - k = eK_MACRO; - break; - case 7: - n = 7; - if (EQN("define-key")) - k = KIND_GHOST_INDEX; - break; - case 9: - n = 9; - if (EQN("defvar-local")) - k = eK_VARIABLE; - else if (EQN("define-error")) - k = eK_ERROR; - break; - case 8: - n = 8; - if (EQN("defvaralias")) - k = eK_VARALIAS; - break; - case 10: - n = 10; - if (EQN("define-inline")) - k = eK_INLINE; - break; - case 14: - n = 14; - if (EQN("define-minor-mode")) - k = eK_MINOR_MODE; - break; - case 16: - n = 16; - if (EQN("define-derived-mode")) - k = eK_DERIVED_MODE; - break; - case 21: - n = 21; - if (EQN("define-global-minor-mode")) - k = eK_MINOR_MODE; - break; - case 25: - n = 25; - if (EQN("define-globalized-minor-mode")) - k = eK_MINOR_MODE; - break; - case 27: - n = 27; - if (EQN("define-obsolete-function-alias")) - k = eK_ALIAS; - break; + const unsigned int key = hash_hint (str, len); + if (key <= MAX_HASH_VALUE) + { + const char *const s = tokens[key].str; + if (*str == *s && 0 == strncmp (str + 1, s + 1, len - 1)) + return tokens[key].kind; + } } -#undef EQN - return k; + return eK_UNKNOWN; + +#undef MIN_WORD_LENGTH +#undef MAX_WORD_LENGTH +#undef MAX_HASH_VALUE + } static void L_getit (vString *const name, const unsigned char *dbp,