diff options
author | Nicolas Williams <nico@cryptonector.com> | 2014-08-10 16:52:03 -0500 |
---|---|---|
committer | Nicolas Williams <nico@cryptonector.com> | 2014-08-14 03:26:26 -0500 |
commit | 1ba8c2cfa649300becae21876d3613362c219a37 (patch) | |
tree | 30ebb15e1bdd56927c09f9d74b573b019a260994 | |
parent | d654724fefab7a24ffa8e718f56028cff32971b9 (diff) |
Add `module` directive, `modulemeta` builtin
Fix #425.
-rw-r--r-- | builtin.c | 4 | ||||
-rw-r--r-- | compile.c | 58 | ||||
-rw-r--r-- | compile.h | 4 | ||||
-rw-r--r-- | execute.c | 38 | ||||
-rw-r--r-- | jq.h | 15 | ||||
-rw-r--r-- | lexer.l | 5 | ||||
-rw-r--r-- | linker.c | 132 | ||||
-rw-r--r-- | linker.h | 4 | ||||
-rw-r--r-- | main.c | 9 | ||||
-rw-r--r-- | opcode_list.h | 1 | ||||
-rw-r--r-- | parser.y | 54 | ||||
-rwxr-xr-x | tests/run | 34 |
12 files changed, 263 insertions, 95 deletions
@@ -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) diff --git a/opcode_list.h b/opcode_list.h index 119a70d3..db9242f9 100644 --- a/opcode_list.h +++ b/opcode_list.h @@ -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 "as" IDENT ';' { - $$ = gen_import(jv_string_value($2), jv_string_value($4), NULL); +"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); - 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 ';' { + $$ = gen_import(jv_string_value($2), gen_noop(), 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)); +"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($5); + jv_free($4); } 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 +cat > "$d/any/c/d.jq" <<EOF +def meh: "meh"; +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"; +def c: foo::a + "c" + d::meh; EOF -cat > "$d/syntaxerror.jq" <<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 |