summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2014-08-10 16:52:03 -0500
committerNicolas Williams <nico@cryptonector.com>2014-08-14 03:26:26 -0500
commit1ba8c2cfa649300becae21876d3613362c219a37 (patch)
tree30ebb15e1bdd56927c09f9d74b573b019a260994
parentd654724fefab7a24ffa8e718f56028cff32971b9 (diff)
Add `module` directive, `modulemeta` builtin
Fix #425.
-rw-r--r--builtin.c4
-rw-r--r--compile.c58
-rw-r--r--compile.h4
-rw-r--r--execute.c38
-rw-r--r--jq.h15
-rw-r--r--lexer.l5
-rw-r--r--linker.c132
-rw-r--r--linker.h4
-rw-r--r--main.c9
-rw-r--r--opcode_list.h1
-rw-r--r--parser.y54
-rwxr-xr-xtests/run34
12 files changed, 263 insertions, 95 deletions
diff --git a/builtin.c b/builtin.c
index 698ad403..711bc473 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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
diff --git a/compile.c b/compile.c
index 92189687..57a26d54 100644
--- a/compile.c
+++ b/compile.c
@@ -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);
}
diff --git a/compile.h b/compile.h
index b0162ae2..f9cd238c 100644
--- a/compile.h
+++ b/compile.h
@@ -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);
diff --git a/execute.c b/execute.c
index 53b67c18..97b33d3d 100644
--- a/execute.c
+++ b/execute.c
@@ -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);
}
diff --git a/jq.h b/jq.h
index 1849f661..b517c529 100644
--- a/jq.h
+++ b/jq.h
@@ -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_ */
diff --git a/lexer.l b/lexer.l
index 8205e69e..7813850f 100644
--- a/lexer.l
+++ b/lexer.l
@@ -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]+ {}
diff --git a/linker.c b/linker.c
index 016870d5..6aaa7d79 100644
--- a/linker.c
+++ b/linker.c
@@ -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;
diff --git a/linker.h b/linker.h
index 4e9f2adf..3f682ca2 100644
--- a/linker.h
+++ b/linker.h
@@ -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
diff --git a/main.c b/main.c
index 5008f8b2..dec1f9f0 100644
--- a/main.c
+++ b/main.c
@@ -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)
diff --git a/parser.y b/parser.y
index c2b1b478..44ae0096 100644
--- a/parser.y
+++ b/parser.y
@@ -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:
diff --git a/tests/run b/tests/run
index 878128de..8a4ef0e7 100755
--- a/tests/run
+++ b/tests/run
@@ -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