Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| # Test file for the wrappers for Emacs Module API | |
| # http://phst.github.io/emacs-modules.html. | |
| #[ | |
| License: | |
| This program is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation, either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| ]# | |
| # Official test file for Emacs Modules: | |
| # http://git.savannah.gnu.org/cgit/emacs.git/tree/test/data/emacs-module/mod-test.c | |
| import emacs_module | |
| import emacs_module/wrappers | |
| # Force the Emacs-Lisp provided module to be named "modtest". | |
| init(emacs, "modtest") | |
| # emacs.defun(wrappers_p, 0): | |
| # ## This function being defined means that modtest2 (with wrappers) | |
| # ## was compiled; used in test-modtest.el | |
| # return symT(env) | |
| #[ | |
| struct emacs_env_26 | |
| { | |
| /* Structure size (for version checking). */ | |
| ptrdiff_t size; | |
| /* Private data; users should not touch this. */ | |
| struct emacs_env_private *private_members; | |
| ]# | |
| #[ | |
| /* Memory management. */ | |
| emacs_value (*make_global_ref) (emacs_env *env, | |
| emacs_value any_reference) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| void (*free_global_ref) (emacs_env *env, | |
| emacs_value global_reference) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| ]# | |
| emacs.defun(globref_make, 0): | |
| ## Make a big string and make it global. | |
| var str: string = "" | |
| for i in 0 ..< (26 * 100): | |
| str.add(char('a'.ord + (i mod 26))) | |
| let lispStr = MakeString(env, str) | |
| return env.make_global_ref(env, lispStr) | |
| #[ | |
| /* Non-local exit handling. */ | |
| enum emacs_funcall_exit (*non_local_exit_check) (emacs_env *env) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| void (*non_local_exit_clear) (emacs_env *env) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| enum emacs_funcall_exit (*non_local_exit_get) | |
| (emacs_env *env, | |
| emacs_value *non_local_exit_symbol_out, | |
| emacs_value *non_local_exit_data_out) | |
| EMACS_ATTRIBUTE_NONNULL(1, 2, 3); | |
| void (*non_local_exit_signal) (emacs_env *env, | |
| emacs_value non_local_exit_symbol, | |
| emacs_value non_local_exit_data) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| void (*non_local_exit_throw) (emacs_env *env, | |
| emacs_value tag, | |
| emacs_value value) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| ]# | |
| # non_local_exit_check, non_local_exit_signal | |
| emacs.defun(signal, 0): | |
| assert isSuccessExitStatus(env) | |
| exitSignalError(env, "error", MakeInteger(env, 100)) | |
| # non_local_exit_check, non_local_exit_throw | |
| emacs.defun(throw, 0): | |
| assert isSuccessExitStatus(env) | |
| env.non_local_exit_throw(env, toEmacsValue(env, "'tag"), # testing toEmacsValue | |
| toEmacsValue(env, 42)) # testing toEmacsValue | |
| return symNil(env) | |
| # non_local_exit_get, non_local_exit_clear | |
| emacs.defun(non_local_exit_funcall, 1): | |
| ## Call argument function (which takes 0 arguments), catch all | |
| ## non-local exists and return either normal result or a list | |
| ## describing the non-local exit. | |
| let | |
| fSym = args[0] | |
| elispFuncallRet = env.funcall(env, fSym, 0, nil) | |
| var | |
| non_local_exit_symbol, non_local_exit_data: emacs_value | |
| let exitCode: emacs_funcall_exit = | |
| env.non_local_exit_get(env, | |
| addr non_local_exit_symbol, | |
| addr non_local_exit_data) | |
| case exitCode | |
| of emacs_funcall_exit_return: | |
| return elispFuncallRet | |
| of emacs_funcall_exit_signal: | |
| clearExitStatus(env) | |
| return MakeList(env, [Intern(env, "signal"), non_local_exit_symbol, non_local_exit_data]) | |
| of emacs_funcall_exit_throw: | |
| clearExitStatus(env) | |
| return MakeList(env, [Intern(env, "throw"), non_local_exit_symbol, non_local_exit_data]) | |
| #[ | |
| /* Function registration. */ | |
| emacs_value (*make_function) (emacs_env *env, | |
| ptrdiff_t min_arity, | |
| ptrdiff_t max_arity, | |
| emacs_value (*function) (emacs_env *env, | |
| ptrdiff_t nargs, | |
| emacs_value args[], | |
| void *) | |
| EMACS_NOEXCEPT | |
| EMACS_ATTRIBUTE_NONNULL(1), | |
| const char *documentation, | |
| void *data) | |
| EMACS_ATTRIBUTE_NONNULL(1, 4); | |
| emacs_value (*funcall) (emacs_env *env, | |
| emacs_value function, | |
| ptrdiff_t nargs, | |
| emacs_value args[]) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| emacs_value (*intern) (emacs_env *env, | |
| const char *symbol_name) | |
| EMACS_ATTRIBUTE_NONNULL(1, 2); | |
| ]# | |
| emacs.defun(make_string, 2): | |
| ## Returns string created by Emacs-Lisp ``make-string``. | |
| return Funcall(env, "make-string", args[]) | |
| emacs.defun(return_t, 1): | |
| ## Returns ``t``, always. | |
| symT(env) | |
| #[ | |
| /* Type conversion. */ | |
| emacs_value (*type_of) (emacs_env *env, | |
| emacs_value value) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| bool (*is_not_nil) (emacs_env *env, emacs_value value) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| bool (*eq) (emacs_env *env, emacs_value a, emacs_value b) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| intmax_t (*extract_integer) (emacs_env *env, emacs_value value) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| emacs_value (*make_integer) (emacs_env *env, intmax_t value) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| double (*extract_float) (emacs_env *env, emacs_value value) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| emacs_value (*make_float) (emacs_env *env, double value) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| ]# | |
| emacs.defun(get_type, 1): | |
| ## Returns the Emacs-Lisp symbol of the argument type. | |
| ## See http://git.savannah.gnu.org/cgit/emacs.git/tree/src/data.c?id=5583e6460c38c5d613e732934b066421349a5259#n204. | |
| env.type_of(env, args[0]) | |
| emacs.defun(is_true, 1): | |
| ## Returns ``t`` if argument is non-nil, else returns ``nil``. | |
| MakeBool(env, ExtractBool(env, args[0])) | |
| emacs.defun(make_cons, 2): | |
| ## Returns a cons made of the two input arguments. | |
| result = MakeCons(env, args[0], args[1]) | |
| # echo strEmacsValue(env, result) | |
| emacs.defun(make_list, 3): | |
| ## Returns a list made of three input arguments. | |
| result = MakeList(env, args[]) | |
| # echo strEmacsValue(env, result) | |
| emacs.defun(eq, 2): | |
| ## Returns ``t`` if both arguments are the same Lisp object, else returns ``nil``. | |
| ## Note that this returns the value of Emacs-Lisp ``eq``, not ``equal``. | |
| toEmacsValue(env, env.eq(env, args[0], args[1])) # testing toEmacsValue | |
| emacs.defun(sum, 2): | |
| ## Returns the sum of two integers. | |
| # assert(nargs == 2) | |
| # The above assert statement is never reached! Emacs throws the | |
| # "wrong-number-of-arguments" error signal before the execution | |
| # reaches this assert statement. | |
| let | |
| a = ExtractInteger(env, args[0]) | |
| b = ExtractInteger(env, args[1]) | |
| MakeInteger(env, a + b) | |
| emacs.defun(sum_float, 2): | |
| ## Returns the sum of two floats. | |
| let | |
| a = ExtractFloat(env, args[0]) | |
| b = ExtractFloat(env, args[1]) | |
| MakeFloat(env, a + b) | |
| #[ | |
| /* Create a Lisp string from a utf8 encoded string. */ | |
| emacs_value (*make_string) (emacs_env *env, | |
| const char *contents, ptrdiff_t length) | |
| EMACS_ATTRIBUTE_NONNULL(1, 2); | |
| ]# | |
| # make_string | |
| emacs.defun(lazy, 0): | |
| ## Returns a string constant. | |
| return MakeString(env, "The quick brown fox jumped over the lazy dog.") | |
| # CopyStringContents | |
| emacs.defun(hello, 1): | |
| ## Returns "Hello " prefixed to the passed string argument. | |
| let | |
| name = CopyStringContents(env, args[0]) | |
| res = "Hello " & name | |
| return toEmacsValue(env, res) # testing toEmacsValue | |
| from osproc import execCmdEx | |
| from strutils import strip | |
| emacs.defun(uname, 1): | |
| ## Returns the output of the ``uname`` command run the passed string argument. | |
| let | |
| unameArg = CopyStringContents(env, args[0]) | |
| var | |
| (res, _) = execCmdEx("uname " & unameArg) | |
| res = res.strip() | |
| return MakeString(env, res) | |
| # /* Return a copy of the argument string where every 'a' is replaced | |
| # with 'b'. */ | |
| # static emacs_value | |
| # Fmod_test_string_a_to_b (emacs_env *env, ptrdiff_t nargs, emacs_value args[], | |
| # void *data) | |
| # { | |
| # emacs_value lisp_str = args[0]; | |
| # ptrdiff_t size = 0; | |
| # char * buf = NULL; | |
| # env->copy_string_contents (env, lisp_str, buf, &size); | |
| # buf = malloc (size); | |
| # env->copy_string_contents (env, lisp_str, buf, &size); | |
| # for (ptrdiff_t i = 0; i + 1 < size; i++) | |
| # if (buf[i] == 'a') | |
| # buf[i] = 'b'; | |
| # return env->make_string (env, buf, size - 1); | |
| # } | |
| #[ | |
| /* Embedded pointer type. */ | |
| emacs_value (*make_user_ptr) (emacs_env *env, | |
| void (*fin) (void *) EMACS_NOEXCEPT, | |
| void *ptr) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| void *(*get_user_ptr) (emacs_env *env, emacs_value uptr) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| void (*set_user_ptr) (emacs_env *env, emacs_value uptr, void *ptr) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| ]# | |
| # /* Embedded pointers in lisp objects. */ | |
| # /* C struct (pointer to) that will be embedded. */ | |
| # struct super_struct | |
| # { | |
| # int amazing_int; | |
| # char large_unused_buffer[512]; | |
| # }; | |
| # /* Return a new user-pointer to a super_struct, with amazing_int set | |
| # to the passed parameter. */ | |
| # static emacs_value | |
| # Fmod_test_userptr_make (emacs_env *env, ptrdiff_t nargs, emacs_value args[], | |
| # void *data) | |
| # { | |
| # struct super_struct *p = calloc (1, sizeof *p); | |
| # p->amazing_int = env->extract_integer (env, args[0]); | |
| # return env->make_user_ptr (env, free, p); | |
| # } | |
| # /* Return the amazing_int of a passed 'user-pointer to a super_struct'. */ | |
| # static emacs_value | |
| # Fmod_test_userptr_get (emacs_env *env, ptrdiff_t nargs, emacs_value args[], | |
| # void *data) | |
| # { | |
| # struct super_struct *p = env->get_user_ptr (env, args[0]); | |
| # return env->make_integer (env, p->amazing_int); | |
| # } | |
| # static emacs_value invalid_stored_value; | |
| # /* The next two functions perform a possibly-invalid operation: they | |
| # store a value in a static variable and load it. This causes | |
| # undefined behavior if the environment that the value was created | |
| # from is no longer live. The module assertions check for this | |
| # error. */ | |
| # static emacs_value | |
| # Fmod_test_invalid_store (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | |
| # void *data) | |
| # { | |
| # return invalid_stored_value = env->make_integer (env, 123); | |
| # } | |
| # static emacs_value | |
| # Fmod_test_invalid_load (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | |
| # void *data) | |
| # { | |
| # return invalid_stored_value; | |
| # } | |
| # /* An invalid finalizer: Finalizers are run during garbage collection, | |
| # where Lisp code can’t be executed. -module-assertions tests for | |
| # this case. */ | |
| # static emacs_env *current_env; | |
| # static void | |
| # invalid_finalizer (void *ptr) | |
| # { | |
| # current_env->intern (current_env, "nil"); | |
| # } | |
| # static emacs_value | |
| # Fmod_test_invalid_finalizer (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | |
| # void *data) | |
| # { | |
| # current_env = env; | |
| # env->make_user_ptr (env, invalid_finalizer, NULL); | |
| # return env->funcall (env, env->intern (env, "garbage-collect"), 0, NULL); | |
| # } | |
| #[ | |
| void (*(*get_user_finalizer) (emacs_env *env, emacs_value uptr)) | |
| (void *) EMACS_NOEXCEPT EMACS_ATTRIBUTE_NONNULL(1); | |
| void (*set_user_finalizer) (emacs_env *env, | |
| emacs_value uptr, | |
| void (*fin) (void *) EMACS_NOEXCEPT) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| ]# | |
| #[ | |
| /* Vector functions. */ | |
| emacs_value (*vec_get) (emacs_env *env, emacs_value vec, ptrdiff_t i) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| void (*vec_set) (emacs_env *env, emacs_value vec, ptrdiff_t i, | |
| emacs_value val) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vec) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| ]# | |
| # vec_size, vec_get | |
| emacs.defun(vector_eq, 2): | |
| var | |
| vec = args[0] | |
| val = args[1] | |
| size = env.vec_size(env, vec) | |
| for i in 0 ..< size: | |
| if not env.eq(env, env.vec_get(env, vec, i), val): | |
| result = symNil(env) | |
| result = symT(env) | |
| # vec_size, vec_set | |
| emacs.defun(vector_fill, 2): | |
| var | |
| vec = args[0] | |
| val = args[1] | |
| size = env.vec_size(env, vec) | |
| for i in 0 ..< size: | |
| env.vec_set(env, vec, i, val) | |
| result = symT(env) | |
| #[ | |
| /* Returns whether a quit is pending. */ | |
| bool (*should_quit) (emacs_env *env) | |
| EMACS_ATTRIBUTE_NONNULL(1); | |
| }; | |
| ]# | |
| emacs.provide() # (provide 'modtest) |