1 parent
d654724fef
commit
1ba8c2cfa6
12 files changed
+265
-97
No files matched your search
@@ -8,6 +8,7 @@
|
||||
#include "compile.h"
|
||||
#include "jq_parser.h"
|
||||
#include "bytecode.h"
|
||||
#include "linker.h"
|
||||
#include "locfile.h"
|
||||
#include "jv_unicode.h"
|
||||
|
||||
@@ -812,6 +813,8 @@ static jv f_getpath(jq_state *jq, jv a, jv b) { return jv_getpath(a, b); }
|
||||
static jv f_delpaths(jq_state *jq, jv a, jv b) { return jv_delpaths(a, b); }
|
||||
static jv f_has(jq_state *jq, jv a, jv b) { return jv_has(a, b); }
|
||||
|
||||
static jv f_modulemeta(jq_state *jq, jv a) { return load_module_meta(jq, a); }
|
||||
|
||||
#define LIBM_DD(name) \
|
||||
{(cfunction_ptr)f_ ## name, "_" #name, 1},
|
||||
|
||||
@@ -859,6 +862,7 @@ static const struct cfunction function_list[] = {
|
||||
{(cfunction_ptr)f_format, "format", 2},
|
||||
{(cfunction_ptr)f_env, "env", 1},
|
||||
{(cfunction_ptr)f_match, "_match_impl", 4},
|
||||
{(cfunction_ptr)f_modulemeta, "modulemeta", 1},
|
||||
};
|
||||
#undef LIBM_DD
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ block block_join(block a, block b) {
|
||||
int block_has_only_binders_and_imports(block binders, int bindflags) {
|
||||
bindflags |= OP_HAS_BINDING;
|
||||
for (inst* curr = binders.first; curr; curr = curr->next) {
|
||||
if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != DEPS) {
|
||||
if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != DEPS && curr->op != MODULEMETA) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ int block_has_only_binders_and_imports(block binders, int bindflags) {
|
||||
int block_has_only_binders(block binders, int bindflags) {
|
||||
bindflags |= OP_HAS_BINDING;
|
||||
for (inst* curr = binders.first; curr; curr = curr->next) {
|
||||
if ((opcode_describe(curr->op)->flags & bindflags) != bindflags) {
|
||||
if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != MODULEMETA) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -341,10 +341,13 @@ block block_bind_library(block binder, block body, int bindflags, const char* li
|
||||
assert(block_has_only_binders(binder, bindflags));
|
||||
bindflags |= OP_HAS_BINDING;
|
||||
int nrefs = 0;
|
||||
int matchlen = strlen(libname)+2;
|
||||
char* matchname = malloc(matchlen+1);
|
||||
strcpy(matchname,libname);
|
||||
strcpy(matchname+matchlen-2,"::");
|
||||
int matchlen = strlen(libname);
|
||||
char* matchname = calloc(1,matchlen+2+1);
|
||||
if (libname[0] != '\0') {
|
||||
strcpy(matchname,libname);
|
||||
strcpy(matchname+matchlen,"::");
|
||||
matchlen += 2;
|
||||
}
|
||||
for (inst *curr = binder.first; curr; curr = curr->next) {
|
||||
char* cname = curr->symbol;
|
||||
char* tname = malloc(strlen(curr->symbol)+matchlen+1);
|
||||
@@ -425,11 +428,13 @@ jv block_take_imports(block* body) {
|
||||
if (body->first->op == TOP) {
|
||||
top = block_take(body);
|
||||
}
|
||||
while (body->first && body->first->op == DEPS) {
|
||||
while (body->first && (body->first->op == MODULEMETA || body->first->op == DEPS)) {
|
||||
inst* dep = block_take(body);
|
||||
jv opts = jv_copy(dep->imm.constant);
|
||||
opts = jv_object_set(opts,jv_string("name"),jv_string(dep->symbol));
|
||||
imports = jv_array_append(imports, opts);
|
||||
if (dep->op == DEPS) {
|
||||
jv opts = jv_copy(dep->imm.constant);
|
||||
opts = jv_object_set(opts,jv_string("name"),jv_string(dep->symbol));
|
||||
imports = jv_array_append(imports, opts);
|
||||
}
|
||||
inst_free(dep);
|
||||
}
|
||||
if (top) {
|
||||
@@ -438,15 +443,36 @@ jv block_take_imports(block* body) {
|
||||
return imports;
|
||||
}
|
||||
|
||||
block gen_import(const char* name, const char* as, const char* search) {
|
||||
block gen_module(const char* name, block metadata) {
|
||||
inst* i = inst_new(MODULEMETA);
|
||||
i->symbol = strdup(name);
|
||||
i->imm.constant = block_const(metadata);
|
||||
if (jv_get_kind(i->imm.constant) != JV_KIND_OBJECT)
|
||||
i->imm.constant = jv_object_set(jv_object(), jv_string("metadata"), i->imm.constant);
|
||||
i->imm.constant = jv_object_set(i->imm.constant, jv_string("name"), jv_string(name));
|
||||
block_free(metadata);
|
||||
return inst_block(i);
|
||||
}
|
||||
|
||||
jv block_module_meta(block b) {
|
||||
if (b.first != NULL && b.first->op == MODULEMETA)
|
||||
return jv_copy(b.first->imm.constant);
|
||||
return jv_null();
|
||||
}
|
||||
|
||||
block gen_import(const char* name, block metadata, const char* as) {
|
||||
assert(metadata.first == NULL || block_is_const(metadata));
|
||||
inst* i = inst_new(DEPS);
|
||||
i->symbol = strdup(name);
|
||||
jv opts = jv_object();
|
||||
jv meta;
|
||||
if (block_is_const(metadata))
|
||||
meta = block_const(metadata);
|
||||
else
|
||||
meta = jv_object();
|
||||
if (as)
|
||||
opts = jv_object_set(opts, jv_string("as"), jv_string(as));
|
||||
if (search)
|
||||
opts = jv_object_set(opts, jv_string("search"), jv_string(search));
|
||||
i->imm.constant = opts;
|
||||
meta = jv_object_set(meta, jv_string("as"), jv_string(as));
|
||||
i->imm.constant = meta;
|
||||
block_free(metadata);
|
||||
return inst_block(i);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@ block gen_op_unbound(opcode op, const char* name);
|
||||
block gen_op_bound(opcode op, block binder);
|
||||
block gen_op_var_fresh(opcode op, const char* name);
|
||||
|
||||
block gen_import(const char* name, const char *as, const char *search);
|
||||
block gen_module(const char* name, block metadata);
|
||||
jv block_module_meta(block b);
|
||||
block gen_import(const char* name, block metadata, const char *as);
|
||||
block gen_function(const char* name, block formals, block body);
|
||||
block gen_param_regular(const char* name);
|
||||
block gen_param(const char* name);
|
||||
|
||||
@@ -984,38 +984,34 @@ int jq_compile(jq_state *jq, const char* str) {
|
||||
return jq_compile_args(jq, str, jv_array());
|
||||
}
|
||||
|
||||
void jq_set_lib_origin(jq_state *jq, jv origin) {
|
||||
assert(jq);
|
||||
assert(jv_get_kind(origin) == JV_KIND_STRING);
|
||||
jq_set_attr(jq, jv_string("ORIGIN"), origin);
|
||||
}
|
||||
jv jq_get_lib_origin(jq_state *jq) {
|
||||
assert(jq);
|
||||
return jq_get_attr(jq, jv_string("ORIGIN"));
|
||||
return jq_get_attr(jq, jv_string("ORIGIN"));
|
||||
}
|
||||
|
||||
void jq_set_lib_dirs(jq_state *jq, jv dirs) {
|
||||
assert(jq);
|
||||
assert(jv_get_kind(dirs) == JV_KIND_ARRAY);
|
||||
jq_set_attr(jq, jv_string("LIB_DIRS"), dirs);
|
||||
}
|
||||
jv jq_get_lib_dirs(jq_state *jq) {
|
||||
assert(jq);
|
||||
return jq_get_attr(jq, jv_string("LIB_DIRS"));
|
||||
return jq_get_attr(jq, jv_string("LIB_DIRS"));
|
||||
}
|
||||
|
||||
jv jq_get_version_dir(jq_state *jq) {
|
||||
jv d = jq_get_attr(jq, jv_string("VERSION_DIR"));
|
||||
assert(jv_is_valid(d));
|
||||
return d;
|
||||
}
|
||||
|
||||
void jq_set_attrs(jq_state *jq, jv attrs) {
|
||||
assert(jv_get_kind(attrs) == JV_KIND_OBJECT);
|
||||
jv_free(jq->attrs);
|
||||
jq->attrs = attrs;
|
||||
}
|
||||
|
||||
void jq_set_attr(jq_state *jq, jv attr, jv val) {
|
||||
assert(jq);
|
||||
assert(jv_get_kind(attr) == JV_KIND_STRING);
|
||||
assert(jv_is_valid(val));
|
||||
jq->attrs = jv_object_set(jq->attrs, attr, val);
|
||||
jq->attrs = jv_object_set(jq->attrs, attr, val);
|
||||
}
|
||||
|
||||
jv jq_get_attr(jq_state *jq, jv attr) {
|
||||
assert(jq);
|
||||
assert(jv_get_kind(attr) == JV_KIND_STRING);
|
||||
return jv_object_get(jv_copy(jq->attrs), attr);
|
||||
return jv_object_get(jv_copy(jq->attrs), attr);
|
||||
}
|
||||
|
||||
void jq_dump_disassembly(jq_state *jq, int indent) {
|
||||
dump_disassembly(indent, jq->bc);
|
||||
}
|
||||
@@ -15,17 +15,18 @@ void jq_get_error_cb(jq_state *, jq_err_cb *, void **);
|
||||
void jq_set_nomem_handler(jq_state *, void (*)(void *), void *);
|
||||
jv jq_format_error(jv msg);
|
||||
void jq_report_error(jq_state *, jv);
|
||||
int jq_compile(jq_state *, const char* str);
|
||||
int jq_compile_args(jq_state *, const char* str, jv args);
|
||||
int jq_compile(jq_state *, const char*);
|
||||
int jq_compile_args(jq_state *, const char*, jv);
|
||||
void jq_dump_disassembly(jq_state *, int);
|
||||
void jq_start(jq_state *, jv value, int flags);
|
||||
void jq_start(jq_state *, jv value, int);
|
||||
jv jq_next(jq_state *);
|
||||
void jq_teardown(jq_state **);
|
||||
|
||||
void jq_set_lib_origin(jq_state *, jv origin);
|
||||
void jq_set_attrs(jq_state *, jv);
|
||||
jv jq_get_attrs(jq_state *);
|
||||
jv jq_get_lib_origin(jq_state *);
|
||||
void jq_set_lib_dirs(jq_state *, jv dirs);
|
||||
jv jq_get_lib_dirs(jq_state *);
|
||||
void jq_set_attr(jq_state *, jv attr, jv val);
|
||||
jv jq_get_attr(jq_state *, jv attr);
|
||||
jv jq_get_version_dir(jq_state *);
|
||||
void jq_set_attr(jq_state *, jv, jv);
|
||||
jv jq_get_attr(jq_state *, jv);
|
||||
#endif /* !_JQ_H_ */
|
||||
@@ -42,8 +42,8 @@ struct lexer_param;
|
||||
"!=" { return NEQ; }
|
||||
"==" { return EQ; }
|
||||
"as" { return AS; }
|
||||
"search" { return SEARCH; }
|
||||
"import" { return IMPORT; }
|
||||
"module" { return MODULE; }
|
||||
"def" { return DEF; }
|
||||
"if" { return IF; }
|
||||
"then" { return THEN; }
|
||||
@@ -115,8 +115,7 @@ struct lexer_param;
|
||||
}
|
||||
|
||||
|
||||
[a-zA-Z_][a-zA-Z_0-9]* { yylval->literal = jv_string(yytext); return IDENT;}
|
||||
[a-zA-Z_][a-zA-Z_0-9]*::[a-zA-Z_][a-zA-Z_0-9]* { yylval->literal = jv_string(yytext); return IDENT;}
|
||||
([a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]* { yylval->literal = jv_string(yytext); return IDENT;}
|
||||
\.[a-zA-Z_][a-zA-Z_0-9]* { yylval->literal = jv_string(yytext+1); return FIELD;}
|
||||
|
||||
[ \n\t]+ {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@@ -54,35 +55,95 @@ jv build_lib_search_chain(jq_state *jq, jv lib_path) {
|
||||
return out_paths;
|
||||
}
|
||||
|
||||
static jv find_lib(jq_state *jq, jv lib_name, jv lib_search_path) {
|
||||
static jv name2relpath(jv name) {
|
||||
jv components = jv_string_split(jv_copy(name), jv_string("::"));
|
||||
jv rp = jv_array_get(jv_copy(components), 0);
|
||||
components = jv_array_slice(components, 1, jv_array_length(jv_copy(components)));
|
||||
jv_array_foreach(components, i, x) {
|
||||
if (i > 0 && jv_equal(jv_copy(x), jv_array_get(jv_copy(components), i - 1))) {
|
||||
jv_free(x);
|
||||
jv_free(rp);
|
||||
jv_free(components);
|
||||
jv res = jv_invalid_with_msg(jv_string_fmt("module names must not have equal consecutive components: %s",
|
||||
jv_string_value(name)));
|
||||
jv_free(name);
|
||||
return res;
|
||||
}
|
||||
rp = jv_string_concat(rp, jv_string_concat(jv_string("/"), x));
|
||||
}
|
||||
jv_free(components);
|
||||
jv_free(name);
|
||||
return rp;
|
||||
}
|
||||
|
||||
static jv find_lib(jq_state *jq, jv lib_name, jv lib_search_path, int use_vers_dir) {
|
||||
assert(jv_get_kind(lib_search_path) == JV_KIND_STRING);
|
||||
assert(jv_get_kind(lib_name) == JV_KIND_STRING);
|
||||
|
||||
lib_search_path = expand_path(lib_search_path);
|
||||
jv rel_path = name2relpath(jv_copy(lib_name));
|
||||
if (!jv_is_valid(rel_path)) {
|
||||
jv_free(lib_name);
|
||||
return rel_path;
|
||||
}
|
||||
|
||||
jv version_dirs;
|
||||
if (use_vers_dir) {
|
||||
version_dirs = JV_ARRAY(jv_string("any/"),
|
||||
jv_string_concat(jq_get_version_dir(jq),
|
||||
jv_string("/")));
|
||||
} else {
|
||||
version_dirs = JV_ARRAY(jv_string(""));
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
jv lib_search_paths = build_lib_search_chain(jq, lib_search_path);
|
||||
jv lib_search_paths = build_lib_search_chain(jq, expand_path(lib_search_path));
|
||||
|
||||
jv_array_foreach(lib_search_paths, i, spath) {
|
||||
jv testpath = jq_realpath(jv_string_fmt("%s/%s.jq",jv_string_value(spath),jv_string_value(lib_name)));
|
||||
|
||||
jv_free(spath);
|
||||
ret = stat(jv_string_value(testpath),&st);
|
||||
if (ret == 0) {
|
||||
jv_free(lib_name);
|
||||
jv_free(lib_search_paths);
|
||||
return testpath;
|
||||
jv vds = jv_copy(version_dirs);
|
||||
jv_array_foreach(vds, k, vd) {
|
||||
jv testpath = jq_realpath(jv_string_fmt("%s/%s%s.jq",
|
||||
jv_string_value(spath),
|
||||
jv_string_value(vd),
|
||||
jv_string_value(rel_path)));
|
||||
ret = stat(jv_string_value(testpath),&st);
|
||||
if (ret == -1 && errno == ENOENT) {
|
||||
jv_free(testpath);
|
||||
testpath = jq_realpath(jv_string_fmt("%s/%s%s/%s.jq",
|
||||
jv_string_value(spath),
|
||||
jv_string_value(vd),
|
||||
jv_string_value(rel_path),
|
||||
jv_string_value(lib_name)));
|
||||
ret = stat(jv_string_value(testpath),&st);
|
||||
}
|
||||
jv_free(vd);
|
||||
if (ret == 0) {
|
||||
jv_free(spath);
|
||||
jv_free(vds);
|
||||
jv_free(version_dirs);
|
||||
jv_free(rel_path);
|
||||
jv_free(lib_name);
|
||||
jv_free(lib_search_paths);
|
||||
return testpath;
|
||||
}
|
||||
jv_free(testpath);
|
||||
}
|
||||
jv_free(testpath);
|
||||
jv_free(vds);
|
||||
jv_free(spath);
|
||||
}
|
||||
jv output = jv_invalid_with_msg(jv_string_fmt("could not find library: %s", jv_string_value(lib_name)));
|
||||
jv output = jv_invalid_with_msg(jv_string_fmt("module not found: %s", jv_string_value(lib_name)));
|
||||
jv_free(version_dirs);
|
||||
jv_free(rel_path);
|
||||
jv_free(lib_name);
|
||||
jv_free(lib_search_paths);
|
||||
return output;
|
||||
}
|
||||
|
||||
static int version_matches(jq_state *jq, block importer, block module) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_dependencies(jq_state *jq, jv lib_origin, block *src_block, struct lib_loading_state *lib_state) {
|
||||
jv deps = block_take_imports(src_block);
|
||||
block bk = *src_block;
|
||||
@@ -93,19 +154,20 @@ static int process_dependencies(jq_state *jq, jv lib_origin, block *src_block, s
|
||||
jv as = jv_object_get(jv_copy(dep), jv_string("as"));
|
||||
if (!jv_is_valid(as)) {
|
||||
jv_free(as);
|
||||
as = jv_copy(name);
|
||||
as = jv_string("");
|
||||
}
|
||||
jv search = jv_object_get(dep, jv_string("search"));
|
||||
if (!jv_is_valid(search)) {
|
||||
jv_free(search);
|
||||
search = jv_string("");
|
||||
}
|
||||
if (strncmp("$ORIGIN/",jv_string_value(search),8) == 0) {
|
||||
int has_origin = (strncmp("$ORIGIN/",jv_string_value(search),8) == 0);
|
||||
if (has_origin) {
|
||||
jv tsearch = jv_string_fmt("%s/%s",jv_string_value(lib_origin),jv_string_value(search)+8);
|
||||
jv_free(search);
|
||||
search = tsearch;
|
||||
}
|
||||
jv lib_path = find_lib(jq, name, search);
|
||||
jv lib_path = find_lib(jq, name, search, !has_origin);
|
||||
if (!jv_is_valid(lib_path)) {
|
||||
jv emsg = jv_invalid_get_msg(lib_path);
|
||||
jq_report_error(jq, jv_string_fmt("jq: error: %s\n",jv_string_value(emsg)));
|
||||
@@ -121,13 +183,23 @@ static int process_dependencies(jq_state *jq, jv lib_origin, block *src_block, s
|
||||
break;
|
||||
}
|
||||
if (state_idx < lib_state->ct) { // Found
|
||||
bk = block_bind_library(lib_state->defs[state_idx], bk, OP_IS_CALL_PSEUDO, jv_string_value(as));
|
||||
// XXX Check version matching here!
|
||||
if (version_matches(jq, bk, lib_state->defs[state_idx]))
|
||||
bk = block_bind_library(lib_state->defs[state_idx], bk, OP_IS_CALL_PSEUDO, jv_string_value(as));
|
||||
else
|
||||
// XXX Would be nice to have the dependent's name here too
|
||||
jq_report_error(jq, jv_string_fmt("jq: error: version mismatch for %s", jv_string_value(name)));
|
||||
jv_free(lib_path);
|
||||
} else { // Not found. Add it to the table before binding.
|
||||
block dep_def_block = gen_noop();
|
||||
nerrors += load_library(jq, lib_path, &dep_def_block, lib_state);
|
||||
if (nerrors == 0)
|
||||
bk = block_bind_library(dep_def_block, bk, OP_IS_CALL_PSEUDO, jv_string_value(as));
|
||||
if (nerrors == 0) {
|
||||
// XXX Check version matching here!
|
||||
if (version_matches(jq, bk, dep_def_block))
|
||||
bk = block_bind_library(dep_def_block, bk, OP_IS_CALL_PSEUDO, jv_string_value(as));
|
||||
else
|
||||
jq_report_error(jq, jv_string_fmt("jq: error: version mismatch for %s", jv_string_value(name)));
|
||||
}
|
||||
}
|
||||
jv_free(as);
|
||||
}
|
||||
@@ -165,6 +237,28 @@ static int load_library(jq_state *jq, jv lib_path, block *out_block, struct lib_
|
||||
return nerrors;
|
||||
}
|
||||
|
||||
jv load_module_meta(jq_state *jq, jv modname) {
|
||||
jv lib_path = find_lib(jq, modname, jv_string(""), 1);
|
||||
jv meta = jv_null();
|
||||
jv data = jv_load_file(jv_string_value(lib_path), 1);
|
||||
if (jv_is_valid(data)) {
|
||||
block program;
|
||||
struct locfile* src = locfile_init(jq, jv_string_value(data), jv_string_length_bytes(jv_copy(data)));
|
||||
int nerrors = jq_parse_library(src, &program);
|
||||
if (nerrors == 0) {
|
||||
meta = block_module_meta(program);
|
||||
if (jv_get_kind(meta) == JV_KIND_NULL)
|
||||
meta = jv_object();
|
||||
meta = jv_object_set(meta, jv_string("deps"), block_take_imports(&program));
|
||||
}
|
||||
locfile_free(src);
|
||||
block_free(program);
|
||||
}
|
||||
jv_free(lib_path);
|
||||
jv_free(data);
|
||||
return meta;
|
||||
}
|
||||
|
||||
int load_program(jq_state *jq, struct locfile* src, block *out_block) {
|
||||
int nerrors = 0;
|
||||
block program;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#define LINKER_H
|
||||
|
||||
int load_program(jq_state *jq, struct locfile* src, block *out_block);
|
||||
|
||||
|
||||
|
||||
jv load_module_meta(jq_state *jq, jv modname);
|
||||
|
||||
#endif
|
||||
@@ -352,16 +352,21 @@ int main(int argc, char* argv[]) {
|
||||
lib_search_paths = jv_array_concat(lib_search_paths,jv_string_split(jv_string(penv),jv_string(PATH_ENV_SEPARATOR)));
|
||||
#undef PATH_ENV_SEPARATOR
|
||||
}
|
||||
jq_set_lib_dirs(jq,lib_search_paths);
|
||||
jq_set_attr(jq, jv_string("LIB_DIRS"), lib_search_paths);
|
||||
|
||||
char *origin = strdup(argv[0]);
|
||||
if (origin == NULL) {
|
||||
fprintf(stderr, "Error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
jq_set_lib_origin(jq,jv_string(dirname(origin)));
|
||||
jq_set_attr(jq, jv_string("ORIGIN"), jv_string(dirname(origin)));
|
||||
free(origin);
|
||||
|
||||
if (strchr(JQ_VERSION, '-') == NULL)
|
||||
jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string(JQ_VERSION));
|
||||
else
|
||||
jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string("next"));
|
||||
|
||||
#if (!defined(WIN32) && defined(HAVE_ISATTY)) || defined(HAVE__ISATTY)
|
||||
|
||||
#if defined(HAVE__ISATTY) && defined(isatty)
|
||||
|
||||
@@ -38,3 +38,4 @@ OP(CLOSURE_CREATE_C, DEFINITION, 0, 0)
|
||||
OP(TOP, NONE, 0, 0)
|
||||
OP(CLOSURE_PARAM_REGULAR, DEFINITION, 0, 0)
|
||||
OP(DEPS, CONSTANT, 0, 0)
|
||||
OP(MODULEMETA, CONSTANT, 0, 0)
|
||||
@@ -56,8 +56,8 @@ struct lexer_param;
|
||||
%token NEQ "!="
|
||||
%token DEFINEDOR "//"
|
||||
%token AS "as"
|
||||
%token SEARCH "search"
|
||||
%token DEF "def"
|
||||
%token MODULE "module"
|
||||
%token IMPORT "import"
|
||||
%token IF "if"
|
||||
%token THEN "then"
|
||||
@@ -104,7 +104,7 @@ struct lexer_param;
|
||||
|
||||
%type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString
|
||||
%type <blk> FuncDef FuncDefs String Import Imports Param Params
|
||||
%type <blk> Arg Args
|
||||
%type <blk> Arg Args Module
|
||||
%{
|
||||
#include "lexer.h"
|
||||
struct lexer_param {
|
||||
@@ -263,13 +263,27 @@ static block gen_update(block object, block val, int optype) {
|
||||
|
||||
%%
|
||||
TopLevel:
|
||||
Imports Exp {
|
||||
*answer = BLOCK($1, gen_op_simple(TOP), $2);
|
||||
Module Imports Exp {
|
||||
*answer = BLOCK($1, $2, gen_op_simple(TOP), $3);
|
||||
} |
|
||||
Imports FuncDefs {
|
||||
*answer = BLOCK($1, $2);
|
||||
Module Imports FuncDefs {
|
||||
*answer = BLOCK($1, $2, $3);
|
||||
}
|
||||
|
||||
Module:
|
||||
%empty {
|
||||
$$ = gen_noop();
|
||||
} |
|
||||
"module" IDENT Exp ';' {
|
||||
if (!block_is_const($3)) {
|
||||
FAIL(@$, "Module metadata must be constant.");
|
||||
$$ = gen_noop();
|
||||
} else {
|
||||
$$ = gen_module(jv_string_value($2), $3);
|
||||
}
|
||||
jv_free($2);
|
||||
}
|
||||
|
||||
Imports:
|
||||
%empty {
|
||||
$$ = gen_noop();
|
||||
@@ -447,24 +461,32 @@ Term {
|
||||
|
||||
Import:
|
||||
"import" IDENT ';' {
|
||||
$$ = gen_import(jv_string_value($2), NULL, NULL);
|
||||
$$ = gen_import(jv_string_value($2), gen_noop(), NULL);
|
||||
jv_free($2);
|
||||
} |
|
||||
"import" IDENT Exp ';' {
|
||||
if (!block_is_const($3)) {
|
||||
FAIL(@$, "Module metadata must be constant.");
|
||||
$$ = gen_noop();
|
||||
} else {
|
||||
$$ = gen_import(jv_string_value($2), $3, NULL);
|
||||
}
|
||||
jv_free($2);
|
||||
} |
|
||||
"import" IDENT "as" IDENT ';' {
|
||||
$$ = gen_import(jv_string_value($2), jv_string_value($4), NULL);
|
||||
$$ = gen_import(jv_string_value($2), gen_noop(), jv_string_value($4));
|
||||
jv_free($2);
|
||||
jv_free($4);
|
||||
} |
|
||||
"import" IDENT "as" IDENT "search" QQSTRING_START QQSTRING_TEXT QQSTRING_END ';' {
|
||||
$$ = gen_import(jv_string_value($2), jv_string_value($4), jv_string_value($7));
|
||||
"import" IDENT "as" IDENT Exp ';' {
|
||||
if (!block_is_const($5)) {
|
||||
FAIL(@$, "Module metadata must be constant.");
|
||||
$$ = gen_noop();
|
||||
} else {
|
||||
$$ = gen_import(jv_string_value($2), $5, jv_string_value($4));
|
||||
}
|
||||
jv_free($2);
|
||||
jv_free($4);
|
||||
jv_free($7);
|
||||
} |
|
||||
"import" IDENT "search" QQSTRING_START QQSTRING_TEXT QQSTRING_END ';' {
|
||||
$$ = gen_import(jv_string_value($2), NULL, jv_string_value($5));
|
||||
jv_free($2);
|
||||
jv_free($5);
|
||||
}
|
||||
|
||||
FuncDef:
|
||||
|
||||
@@ -71,6 +71,12 @@ if [ $n -ne 5 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
v=`scripts/version`
|
||||
case "$v" in
|
||||
*-*) v=next;;
|
||||
*) true;;
|
||||
esac
|
||||
|
||||
## Test library/module system
|
||||
|
||||
cat > "$d/.jq" <<EOF
|
||||
@@ -81,22 +87,31 @@ def g: "bar";
|
||||
def fg: f+g;
|
||||
EOF
|
||||
|
||||
cat > "$d/a.jq" <<EOF
|
||||
mkdir -p "$d/$v/b" "$d/any/c" "$d/any/syntaxerror"
|
||||
|
||||
cat > "$d/$v/a.jq" <<EOF
|
||||
module a {version:1.7};
|
||||
def a: "a";
|
||||
EOF
|
||||
|
||||
cat > "$d/b.jq" <<EOF
|
||||
cat > "$d/$v/b/b.jq" <<EOF
|
||||
def a: "b";
|
||||
def b: "c";
|
||||
EOF
|
||||
|
||||
cat > "$d/c.jq" <<EOF
|
||||
import a as foo;
|
||||
def a: 0;
|
||||
def c: foo::a + "c";
|
||||
cat > "$d/any/c/d.jq" <<EOF
|
||||
def meh: "meh";
|
||||
EOF
|
||||
|
||||
cat > "$d/syntaxerror.jq" <<EOF
|
||||
cat > "$d/any/c/c.jq" <<"EOF"
|
||||
module c {whatever:null};
|
||||
import a as foo;
|
||||
import d as d {search:"$ORIGIN/"};
|
||||
def a: 0;
|
||||
def c: foo::a + "c" + d::meh;
|
||||
EOF
|
||||
|
||||
cat > "$d/any/syntaxerror/syntaxerror.jq" <<EOF
|
||||
wat;
|
||||
EOF
|
||||
|
||||
@@ -110,16 +125,21 @@ if [ `HOME=$d $VALGRIND $Q ./jq --debug-dump-disasm -n fg | grep '^[a-z]' | wc -
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! $VALGRIND $Q ./jq -ner -L $d 'import a as foo; import b as bar; import a as foobar; def fooa: foo::a; [fooa, bar::a, bar::b, foo::a, foobar::a] | . == ["a","b","c","a","a"]' > /dev/null; then
|
||||
if ! $VALGRIND $Q ./jq -ner -L $d 'import a as foo; import b as bar; import a; def fooa: foo::a; [fooa, bar::a, bar::b, foo::a, a] | . == ["a","b","c","a","a"]' > /dev/null; then
|
||||
echo "Module system appears to be broken" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! $VALGRIND $Q ./jq -ner -L $d 'import c as foo; [foo::a, foo::c] | . == [0,"ac"]' > /dev/null; then
|
||||
if ! $VALGRIND $Q ./jq -ner -L $d 'import c as foo; [foo::a, foo::c] | . == [0,"acmeh"]' > /dev/null; then
|
||||
echo "Module system appears to be broken" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "`$VALGRIND $Q ./jq -cner -L $d '\"c\" | modulemeta'`" != '{"whatever":null,"name":"c","deps":[{"as":"foo","name":"a"},{"search":"$ORIGIN/","as":"d","name":"d"}]}' ]; then
|
||||
echo "modulemeta builtin appears to be broken" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if $VALGRIND ./jq -ner -L $d 'import syntaxerror; .' > $d/out 2>&1; then
|
||||
echo "Module system appears to be broken" 1>&2
|
||||
exit 1
|
||||
|
||||
Reference in new issue
Block a user