C API ===== You can write Picrin's extension by yourself from both sides of C and Scheme. This page describes the way to control the interpreter from the C world. Extension Library ----------------- If you want to create a contribution library with C, the only thing you need to do is make a directory under contrib/. Below is a sample code of extension library. * contrib/add/CMakeLists.txt .. sourcecode:: cmake list(APPEND PICRIN_CONTRIB_INITS add) list(APPEND PICRIN_CONTRIB_SOURCES ${PROJECT_SOURCE_DIR}/contrib/add/add.c) * contrib/add/add.c .. sourcecode:: c #include "picrin.h" static pic_value pic_add(pic_state *pic) { double a, b; pic_get_args(pic, "ff", &a, &b); return pic_float_value(a + b); } void pic_init_add(pic_state *pic) { pic_deflibrary (pic, "(picrin add)") { pic_defun(pic, "add", pic_add); } } After recompiling the interpreter, the library "(picrin add)" is available in the REPL, which library provides a funciton "add". User-data vs GC ^^^^^^^^^^^^^^^ When you use dynamic memory allocation inside C APIs, you must be caseful about Picrin's GC. Fortunately, we provides a set of wrapper functions for complete abstraction of GC. In the case below, the memory (de)allocators *create_foo* and *finalize_foo* are wrapped in pic_data object, so that when an instance of foo losts all references from others to it picrin can automatically finalize the orphan object. .. sourcecode:: c /** foo.c **/ #include #include "picrin.h" #include "picrin/data.h" /* * C-side API */ struct foo { // blah blah blah }; struct foo * create_foo () { return malloc(sizeof(struct foo)); } void finalize_foo (void *foo) { struct foo *f = foo; free(f); } /* * picrin-side FFI interface */ static const pic_data_type foo_type = { "foo", finalize_foo }; static pic_value pic_create_foo(pic_state *pic) { struct foo *f; struct pic_data *dat; pic_get_args(pic, ""); // no args here f = create_foo(); data = pic_data_alloc(pic, &foo_type, md); return pic_obj_value(data); } void pic_init_foo(pic_state *pic) { pic_defun(pic, "create-foo", pic_create_foo); // (create-foo) }