mirror of
https://github.com/janet-lang/janet
synced 2024-12-27 17:00:27 +00:00
Add macro mechanism for defining C source information for functions.
This wil let us track source code for C functions more easily.
This commit is contained in:
parent
6f1695ecd4
commit
7fba44ccce
@ -942,8 +942,12 @@ Janet janet_disasm(JanetFuncDef *def) {
|
||||
return janet_wrap_struct(janet_table_to_struct(ret));
|
||||
}
|
||||
|
||||
/* C Function for assembly */
|
||||
static Janet cfun_asm(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_asm,
|
||||
"(asm assembly)",
|
||||
"Returns a new function that is the compiled result of the assembly.\n"
|
||||
"The syntax for the assembly can be found on the Janet website, and should correspond\n"
|
||||
"to the return value of disasm. Will throw an\n"
|
||||
"error on invalid assembly.") {
|
||||
janet_fixarity(argc, 1);
|
||||
JanetAssembleResult res;
|
||||
res = janet_asm(argv[0], 0);
|
||||
@ -953,7 +957,24 @@ static Janet cfun_asm(int32_t argc, Janet *argv) {
|
||||
return janet_wrap_function(janet_thunk(res.funcdef));
|
||||
}
|
||||
|
||||
static Janet cfun_disasm(int32_t argc, Janet *argv) {
|
||||
JANET_CORE_FN(cfun_disasm,
|
||||
"(disasm func &opt field)",
|
||||
"Returns assembly that could be used to compile the given function. "
|
||||
"func must be a function, not a c function. Will throw on error on a badly "
|
||||
"typed argument. If given a field name, will only return that part of the function assembly. "
|
||||
"Possible fields are:\n\n"
|
||||
"* :arity - number of required and optional arguments.\n"
|
||||
"* :min-arity - minimum number of arguments function can be called with.\n"
|
||||
"* :max-arity - maximum number of arguments function can be called with.\n"
|
||||
"* :vararg - true if function can take a variable number of arguments.\n"
|
||||
"* :bytecode - array of parsed bytecode instructions. Each instruction is a tuple.\n"
|
||||
"* :source - name of source file that this function was compiled from.\n"
|
||||
"* :name - name of function.\n"
|
||||
"* :slotcount - how many virtual registers, or slots, this function uses. Corresponds to stack space used by function.\n"
|
||||
"* :constants - an array of constants referenced by this function.\n"
|
||||
"* :sourcemap - a mapping of each bytecode instruction to a line and column in the source file.\n"
|
||||
"* :environments - an internal mapping of which enclosing functions are referenced for bindings.\n"
|
||||
"* :defs - other function definitions that this function may instantiate.\n") {
|
||||
janet_arity(argc, 1, 2);
|
||||
JanetFunction *f = janet_getfunction(argv, 0);
|
||||
if (argc == 2) {
|
||||
@ -976,41 +997,14 @@ static Janet cfun_disasm(int32_t argc, Janet *argv) {
|
||||
}
|
||||
}
|
||||
|
||||
static const JanetReg asm_cfuns[] = {
|
||||
{
|
||||
"asm", cfun_asm,
|
||||
JDOC("(asm assembly)\n\n"
|
||||
"Returns a new function that is the compiled result of the assembly.\n"
|
||||
"The syntax for the assembly can be found on the Janet website, and should correspond\n"
|
||||
"to the return value of disasm. Will throw an\n"
|
||||
"error on invalid assembly.")
|
||||
},
|
||||
{
|
||||
"disasm", cfun_disasm,
|
||||
JDOC("(disasm func &opt field)\n\n"
|
||||
"Returns assembly that could be used to compile the given function.\n"
|
||||
"func must be a function, not a c function. Will throw on error on a badly\n"
|
||||
"typed argument. If given a field name, will only return that part of the function assembly.\n"
|
||||
"Possible fields are:\n\n"
|
||||
"* :arity - number of required and optional arguments.\n\n"
|
||||
"* :min-arity - minimum number of arguments function can be called with.\n\n"
|
||||
"* :max-arity - maximum number of arguments function can be called with.\n\n"
|
||||
"* :vararg - true if function can take a variable number of arguments.\n\n"
|
||||
"* :bytecode - array of parsed bytecode instructions. Each instruction is a tuple.\n\n"
|
||||
"* :source - name of source file that this function was compiled from.\n\n"
|
||||
"* :name - name of function.\n\n"
|
||||
"* :slotcount - how many virtual registers, or slots, this function uses. Corresponds to stack space used by function.\n\n"
|
||||
"* :constants - an array of constants referenced by this function.\n\n"
|
||||
"* :sourcemap - a mapping of each bytecode instruction to a line and column in the source file.\n\n"
|
||||
"* :environments - an internal mapping of which enclosing functions are referenced for bindings.\n\n"
|
||||
"* :defs - other function definitions that this function may instantiate.\n")
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Load the library */
|
||||
void janet_lib_asm(JanetTable *env) {
|
||||
janet_core_cfuns(env, NULL, asm_cfuns);
|
||||
JanetRegExt asm_cfuns[] = {
|
||||
JANET_CORE_REG("asm", cfun_asm),
|
||||
JANET_CORE_REG("disasm", cfun_disasm),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, asm_cfuns);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
176
src/core/util.c
176
src/core/util.c
@ -369,82 +369,148 @@ void janet_register(const char *name, JanetCFunction cfun) {
|
||||
janet_table_put(janet_vm.registry, key, value);
|
||||
}
|
||||
|
||||
/* Add sourcemapping and documentation to a binding table */
|
||||
static void janet_add_meta(JanetTable *table, const char *doc, const char *source_file, int32_t source_line) {
|
||||
if (doc) {
|
||||
janet_table_put(table, janet_ckeywordv("doc"), janet_cstringv(doc));
|
||||
}
|
||||
if (source_file && source_line) {
|
||||
Janet triple[3];
|
||||
triple[0] = janet_cstringv(source_file);
|
||||
triple[1] = janet_wrap_integer(source_line);
|
||||
triple[2] = janet_wrap_integer(1);
|
||||
Janet value = janet_wrap_tuple(janet_tuple_n(triple, 3));
|
||||
janet_table_put(table, janet_ckeywordv("source-map"), value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a def to an environment */
|
||||
void janet_def(JanetTable *env, const char *name, Janet val, const char *doc) {
|
||||
void janet_def_sm(JanetTable *env, const char *name, Janet val, const char *doc, const char *source_file, int32_t source_line) {
|
||||
JanetTable *subt = janet_table(2);
|
||||
janet_table_put(subt, janet_ckeywordv("value"), val);
|
||||
if (doc)
|
||||
janet_table_put(subt, janet_ckeywordv("doc"), janet_cstringv(doc));
|
||||
janet_add_meta(subt, doc, source_file, source_line);
|
||||
janet_table_put(env, janet_csymbolv(name), janet_wrap_table(subt));
|
||||
}
|
||||
void janet_def(JanetTable *env, const char *name, Janet value, const char *doc) {
|
||||
janet_def_sm(env, name, value, doc, NULL, 0);
|
||||
}
|
||||
|
||||
/* Add a var to the environment */
|
||||
void janet_var(JanetTable *env, const char *name, Janet val, const char *doc) {
|
||||
void janet_var_sm(JanetTable *env, const char *name, Janet val, const char *doc, const char *source_file, int32_t source_line) {
|
||||
JanetArray *array = janet_array(1);
|
||||
JanetTable *subt = janet_table(2);
|
||||
janet_array_push(array, val);
|
||||
janet_table_put(subt, janet_ckeywordv("ref"), janet_wrap_array(array));
|
||||
if (doc)
|
||||
janet_table_put(subt, janet_ckeywordv("doc"), janet_cstringv(doc));
|
||||
janet_add_meta(subt, doc, source_file, source_line);
|
||||
janet_table_put(env, janet_csymbolv(name), janet_wrap_table(subt));
|
||||
}
|
||||
void janet_var(JanetTable *env, const char *name, Janet val, const char *doc) {
|
||||
janet_var_sm(env, name, val, doc, NULL, 0);
|
||||
}
|
||||
|
||||
/* Load many cfunctions at once */
|
||||
static void _janet_cfuns_prefix(JanetTable *env, const char *regprefix, const JanetReg *cfuns, int defprefix) {
|
||||
uint8_t *longname_buffer = NULL;
|
||||
size_t prefixlen = 0;
|
||||
size_t bufsize = 0;
|
||||
typedef struct {
|
||||
uint8_t *longname_buffer;
|
||||
size_t prefixlen;
|
||||
size_t bufsize;
|
||||
} JanetNameBuffer;
|
||||
|
||||
static void cfuns_namebuf_init(JanetNameBuffer *nb, const char *regprefix) {
|
||||
nb->longname_buffer = NULL;
|
||||
nb->prefixlen = 0;
|
||||
nb->bufsize = 0;
|
||||
if (NULL != regprefix) {
|
||||
prefixlen = strlen(regprefix);
|
||||
bufsize = prefixlen + 256;
|
||||
longname_buffer = janet_malloc(bufsize);
|
||||
if (NULL == longname_buffer) {
|
||||
nb->prefixlen = strlen(regprefix);
|
||||
nb->bufsize = nb->prefixlen + 256;
|
||||
nb->longname_buffer = janet_malloc(nb->bufsize);
|
||||
if (NULL == nb->longname_buffer) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
safe_memcpy(longname_buffer, regprefix, prefixlen);
|
||||
longname_buffer[prefixlen] = '/';
|
||||
prefixlen++;
|
||||
safe_memcpy(nb->longname_buffer, regprefix, nb->prefixlen);
|
||||
nb->longname_buffer[nb->prefixlen] = '/';
|
||||
nb->prefixlen++;
|
||||
}
|
||||
while (cfuns->name) {
|
||||
Janet name;
|
||||
if (NULL != regprefix) {
|
||||
int32_t nmlen = 0;
|
||||
while (cfuns->name[nmlen]) nmlen++;
|
||||
int32_t totallen = (int32_t) prefixlen + nmlen;
|
||||
if ((size_t) totallen > bufsize) {
|
||||
bufsize = (size_t)(totallen) + 128;
|
||||
longname_buffer = janet_realloc(longname_buffer, bufsize);
|
||||
if (NULL == longname_buffer) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
static Janet cfuns_namebuf_getname(JanetNameBuffer *nb, const char *suffix) {
|
||||
if (nb->prefixlen) {
|
||||
int32_t nmlen = 0;
|
||||
while (suffix[nmlen]) nmlen++;
|
||||
int32_t totallen = (int32_t) nb->prefixlen + nmlen;
|
||||
if ((size_t) totallen > nb->bufsize) {
|
||||
nb->bufsize = (size_t)(totallen) + 128;
|
||||
nb->longname_buffer = janet_realloc(nb->longname_buffer, nb->bufsize);
|
||||
if (NULL == nb->longname_buffer) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
safe_memcpy(longname_buffer + prefixlen, cfuns->name, nmlen);
|
||||
name = janet_wrap_symbol(janet_symbol(longname_buffer, totallen));
|
||||
} else {
|
||||
name = janet_csymbolv(cfuns->name);
|
||||
}
|
||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||
if (defprefix) {
|
||||
JanetTable *subt = janet_table(2);
|
||||
janet_table_put(subt, janet_ckeywordv("value"), fun);
|
||||
if (cfuns->documentation)
|
||||
janet_table_put(subt, janet_ckeywordv("doc"), janet_cstringv(cfuns->documentation));
|
||||
janet_table_put(env, name, janet_wrap_table(subt));
|
||||
} else {
|
||||
janet_def(env, cfuns->name, fun, cfuns->documentation);
|
||||
}
|
||||
janet_table_put(janet_vm.registry, fun, name);
|
||||
cfuns++;
|
||||
safe_memcpy(nb->longname_buffer + nb->prefixlen, suffix, nmlen);
|
||||
return janet_wrap_symbol(janet_symbol(nb->longname_buffer, totallen));
|
||||
} else {
|
||||
return janet_csymbolv(suffix);
|
||||
}
|
||||
(janet_free)(longname_buffer);
|
||||
}
|
||||
|
||||
static void cfuns_namebuf_deinit(JanetNameBuffer *nb) {
|
||||
janet_free(nb->longname_buffer);
|
||||
}
|
||||
|
||||
void janet_cfuns_prefix(JanetTable *env, const char *regprefix, const JanetReg *cfuns) {
|
||||
_janet_cfuns_prefix(env, regprefix, cfuns, 1);
|
||||
JanetNameBuffer nb;
|
||||
cfuns_namebuf_init(&nb, regprefix);
|
||||
while (cfuns->name) {
|
||||
Janet name = cfuns_namebuf_getname(&nb, cfuns->name);
|
||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||
janet_def(env, cfuns->name, fun, cfuns->documentation);
|
||||
janet_table_put(janet_vm.registry, fun, name);
|
||||
cfuns++;
|
||||
}
|
||||
cfuns_namebuf_deinit(&nb);
|
||||
}
|
||||
|
||||
void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns) {
|
||||
_janet_cfuns_prefix(env, regprefix, cfuns, 0);
|
||||
JanetNameBuffer nb;
|
||||
cfuns_namebuf_init(&nb, regprefix);
|
||||
while (cfuns->name) {
|
||||
Janet name = cfuns_namebuf_getname(&nb, cfuns->name);
|
||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||
JanetTable *subt = janet_table(2);
|
||||
janet_table_put(subt, janet_ckeywordv("value"), fun);
|
||||
janet_add_meta(subt, cfuns->documentation, NULL, 0);
|
||||
janet_table_put(env, name, janet_wrap_table(subt));
|
||||
janet_table_put(janet_vm.registry, fun, name);
|
||||
cfuns++;
|
||||
}
|
||||
cfuns_namebuf_deinit(&nb);
|
||||
}
|
||||
|
||||
void janet_cfuns_ext(JanetTable *env, const char *regprefix, const JanetRegExt *cfuns) {
|
||||
JanetNameBuffer nb;
|
||||
cfuns_namebuf_init(&nb, regprefix);
|
||||
while (cfuns->name) {
|
||||
Janet name = cfuns_namebuf_getname(&nb, cfuns->name);
|
||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||
janet_def_sm(env, cfuns->name, fun, cfuns->documentation, cfuns->source_file, cfuns->source_line);
|
||||
janet_table_put(janet_vm.registry, fun, name);
|
||||
cfuns++;
|
||||
}
|
||||
cfuns_namebuf_deinit(&nb);
|
||||
}
|
||||
|
||||
void janet_cfuns_ext_prefix(JanetTable *env, const char *regprefix, const JanetRegExt *cfuns) {
|
||||
JanetNameBuffer nb;
|
||||
cfuns_namebuf_init(&nb, regprefix);
|
||||
while (cfuns->name) {
|
||||
Janet name = cfuns_namebuf_getname(&nb, cfuns->name);
|
||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||
JanetTable *subt = janet_table(2);
|
||||
janet_table_put(subt, janet_ckeywordv("value"), fun);
|
||||
janet_add_meta(subt, cfuns->documentation, cfuns->source_file, cfuns->source_line);
|
||||
janet_table_put(env, name, janet_wrap_table(subt));
|
||||
janet_table_put(janet_vm.registry, fun, name);
|
||||
cfuns++;
|
||||
}
|
||||
cfuns_namebuf_deinit(&nb);
|
||||
}
|
||||
|
||||
/* Abstract type introspection */
|
||||
@ -485,6 +551,20 @@ void janet_core_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cf
|
||||
cfuns++;
|
||||
}
|
||||
}
|
||||
|
||||
void janet_core_def_sm(JanetTable *env, const char *name, Janet x, const void *p, const void *sf, int32_t sl) {
|
||||
(void) sf, sl;
|
||||
janet_core_def(env, name, x, p);
|
||||
}
|
||||
|
||||
void janet_core_cfuns_ext(JanetTable *env, const char *regprefix, const JanetRegExt *cfuns) {
|
||||
(void) regprefix;
|
||||
while (cfuns->name) {
|
||||
Janet fun = janet_wrap_cfunction(cfuns->cfun);
|
||||
janet_core_def(env, cfuns->name, fun, cfuns->documentation);
|
||||
cfuns++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JanetBinding janet_resolve_ext(JanetTable *env, const uint8_t *sym) {
|
||||
|
@ -90,11 +90,19 @@ Janet janet_next_impl(Janet ds, Janet key, int is_interpreter);
|
||||
/* Inside the janet core, defining globals is different
|
||||
* at bootstrap time and normal runtime */
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
#define JANET_CORE_REG JANET_REG
|
||||
#define JANET_CORE_FN JANET_FN
|
||||
#define janet_core_def janet_def
|
||||
#define janet_core_cfuns janet_cfuns
|
||||
#define janet_core_def_sm janet_def_sm
|
||||
#define janet_core_cfuns_ext janet_cfuns_ext
|
||||
#else
|
||||
#define JANET_CORE_REG JANET_REG_
|
||||
#define JANET_CORE_FN JANET_FN_
|
||||
void janet_core_def(JanetTable *env, const char *name, Janet x, const void *p);
|
||||
void janet_core_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns);
|
||||
void janet_core_def_sm(JanetTable *env, const char *name, Janet x, const void *p, const void *sf, int32_t sl);
|
||||
void janet_core_cfuns_ext(JanetTable *env, const char *regprefix, const JanetRegExt *cfuns);
|
||||
#endif
|
||||
|
||||
/* Clock gettime */
|
||||
|
@ -403,6 +403,7 @@ typedef struct JanetKV JanetKV;
|
||||
typedef struct JanetStackFrame JanetStackFrame;
|
||||
typedef struct JanetAbstractType JanetAbstractType;
|
||||
typedef struct JanetReg JanetReg;
|
||||
typedef struct JanetRegExt JanetRegExt;
|
||||
typedef struct JanetMethod JanetMethod;
|
||||
typedef struct JanetSourceMapping JanetSourceMapping;
|
||||
typedef struct JanetView JanetView;
|
||||
@ -1093,6 +1094,14 @@ struct JanetReg {
|
||||
const char *documentation;
|
||||
};
|
||||
|
||||
struct JanetRegExt {
|
||||
const char *name;
|
||||
JanetCFunction cfun;
|
||||
const char *documentation;
|
||||
const char *source_file;
|
||||
int32_t source_line;
|
||||
};
|
||||
|
||||
struct JanetMethod {
|
||||
const char *name;
|
||||
JanetCFunction cfun;
|
||||
@ -1750,6 +1759,54 @@ JANET_API Janet janet_resolve_core(const char *name);
|
||||
/* Shorthand for janet C function declarations */
|
||||
#define JANET_CFUN(name) Janet name (int32_t argc, Janet *argv)
|
||||
|
||||
/* Declare a C function with documentation and source mapping */
|
||||
#define JANET_REG_END {NULL, NULL, NULL, NULL, 0}
|
||||
|
||||
/* no docstrings or sourcemaps */
|
||||
#define JANET_REG_(JNAME, CNAME) {JNAME, CNAME, NULL, NULL, 0}
|
||||
#define JANET_FN_(CNAME, USAGE, DOCSTRING) \
|
||||
static Janet CNAME (int32_t argc, Janet *argv)
|
||||
|
||||
/* sourcemaps only */
|
||||
#define JANET_REG_S(JNAME, CNAME) {JNAME, CNAME, NULL, __FILE__, CNAME##_sourceline_}
|
||||
#define JANET_FN_S(CNAME, USAGE, DOCSTRING) \
|
||||
static int32_t CNAME##_sourceline_ = __LINE__; \
|
||||
static Janet CNAME (int32_t argc, Janet *argv)
|
||||
|
||||
/* docstring only */
|
||||
#define JANET_REG_D(JNAME, CNAME) {JNAME, CNAME, CNAME##_docstring_, NULL, 0}
|
||||
#define JANET_FN_D(CNAME, USAGE, DOCSTRING) \
|
||||
static const char CNAME##_docstring_[] = USAGE "\n\n" DOCSTRING; \
|
||||
static Janet CNAME (int32_t argc, Janet *argv)
|
||||
|
||||
/* sourcemaps and docstrings */
|
||||
#define JANET_REG_SD(JNAME, CNAME) {JNAME, CNAME, CNAME##_docstring_, __FILE__, CNAME##_sourceline_}
|
||||
#define JANET_FN_SD(CNAME, USAGE, DOCSTRING) \
|
||||
static int32_t CNAME##_sourceline_ = __LINE__; \
|
||||
static const char CNAME##_docstring_[] = USAGE "\n\n" DOCSTRING; \
|
||||
static Janet CNAME (int32_t argc, Janet *argv)
|
||||
|
||||
/* Choose defaults for source mapping and docstring based on config defs */
|
||||
#if defined(JANET_NO_SOURCEMAPS) && defined(JANET_NO_DOCSTRINGS)
|
||||
#define JANET_REG JANET_REG_
|
||||
#define JANET_FN JANET_FN_
|
||||
#elif defined(JANET_NO_SOURCEMAPS) && !defined(JANET_NO_DOCSTRINGS)
|
||||
#define JANET_REG JANET_REG_D
|
||||
#define JANET_FN JANET_FN_D
|
||||
#elif !defined(JANET_NO_SOURCEMAPS) && defined(JANET_NO_DOCSTRINGS)
|
||||
#define JANET_REG JANET_REG_S
|
||||
#define JANET_FN JANET_FN_S
|
||||
#elif !defined(JANET_NO_SOURCEMAPS) && !defined(JANET_NO_DOCSTRINGS)
|
||||
#define JANET_REG JANET_REG_SD
|
||||
#define JANET_FN JANET_FN_SD
|
||||
#endif
|
||||
|
||||
/* Define things with source mapping information */
|
||||
JANET_API void janet_cfuns_ext(JanetTable *env, const char *regprefix, const JanetRegExt *cfuns);
|
||||
JANET_API void janet_cfuns_ext_prefix(JanetTable *env, const char *regprefix, const JanetRegExt *cfuns);
|
||||
JANET_API void janet_def_sm(JanetTable *env, const char *name, Janet val, const char *documentation, const char *source_file, int32_t source_line);
|
||||
JANET_API void janet_var_sm(JanetTable *env, const char *name, Janet val, const char *documentation, const char *source_file, int32_t source_line);
|
||||
|
||||
/* Allow setting entry name for static libraries */
|
||||
#ifdef __cplusplus
|
||||
#define JANET_MODULE_PREFIX extern "C"
|
||||
|
Loading…
Reference in New Issue
Block a user