#include #include "builtin.h" #include "compile.h" #include "parser.h" #include "locfile.h" enum { CMP_OP_LESS, CMP_OP_GREATER, CMP_OP_LESSEQ, CMP_OP_GREATEREQ } _cmp_op; static void f_plus(jv input[], jv output[]) { jv_free(input[0]); jv a = input[2]; jv b = input[1]; if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { output[0] = jv_number(jv_number_value(a) + jv_number_value(b)); } else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) { output[0] = jv_string_concat(a, b); } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { output[0] = jv_array_concat(a, b); } else if (jv_get_kind(a) == JV_KIND_OBJECT && jv_get_kind(b) == JV_KIND_OBJECT) { output[0] = jv_object_merge(a, b); } else { output[0] = jv_invalid_with_msg(jv_string_fmt("Attempted to add %s and %s", jv_kind_name(jv_get_kind(a)), jv_kind_name(jv_get_kind(b)))); jv_free(a); jv_free(b); } } static void f_minus(jv input[], jv output[]) { jv_free(input[0]); jv a = input[2]; jv b = input[1]; if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { output[0] = jv_number(jv_number_value(a) - jv_number_value(b)); } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { jv out = jv_array(); for (int i=0; i= db) || (op == CMP_OP_GREATER && da > db)); } else { output[0] = jv_invalid_with_msg(jv_string_fmt("Attempted to compare order of %s wrt %s", jv_kind_name(jv_get_kind(a)), jv_kind_name(jv_get_kind(b)))); jv_free(a); jv_free(b); } } static void f_less(jv input[], jv output[]) { order_cmp(input, output, CMP_OP_LESS); } static void f_greater(jv input[], jv output[]) { order_cmp(input, output, CMP_OP_GREATER); } static void f_lesseq(jv input[], jv output[]) { order_cmp(input, output, CMP_OP_LESSEQ); } static void f_greatereq(jv input[], jv output[]) { order_cmp(input, output, CMP_OP_GREATEREQ); } static void f_contains(jv input[], jv output[]) { jv_free(input[0]); jv a = input[2]; jv b = input[1]; jv_kind akind = jv_get_kind(a); if (akind == jv_get_kind(b)) { output[0] = jv_bool(jv_contains(a, b)); } else { output[0] = jv_invalid_with_msg(jv_string_fmt("Can only check containment of values of the same type.")); jv_free(a); jv_free(b); } } static void f_tonumber(jv input[], jv output[]) { if (jv_get_kind(input[0]) == JV_KIND_NUMBER) { output[0] = input[0]; } else if (jv_get_kind(input[0]) == JV_KIND_STRING) { jv parsed = jv_parse(jv_string_value(input[0])); if (!jv_is_valid(parsed)) { jv_free(input[0]); output[0] = parsed; } else if (jv_get_kind(parsed) != JV_KIND_NUMBER) { output[0] = jv_invalid_with_msg(jv_string_fmt("'%s' is not a number", jv_string_value(input[0]))); jv_free(input[0]); } else { jv_free(input[0]); output[0] = parsed; } } else { output[0] = jv_invalid_with_msg(jv_string_fmt("Cannot parse %s as a number", jv_kind_name(jv_get_kind(input[0])))); jv_free(input[0]); return; } } static void f_length(jv input[], jv output[]) { if (jv_get_kind(input[0]) == JV_KIND_ARRAY) { output[0] = jv_number(jv_array_length(input[0])); } else if (jv_get_kind(input[0]) == JV_KIND_OBJECT) { output[0] = jv_number(jv_object_length(input[0])); } else if (jv_get_kind(input[0]) == JV_KIND_STRING) { output[0] = jv_number(jv_string_length(input[0])); } else { output[0] = jv_invalid_with_msg(jv_string_fmt("Cannot get the length of %s", jv_kind_name(jv_get_kind(input[0])))); jv_free(input[0]); } } static void f_tostring(jv input[], jv output[]) { if (jv_get_kind(input[0]) == JV_KIND_STRING) { output[0] = input[0]; } else { output[0] = jv_dump_string(input[0], 0); } } static int string_cmp(const void* pa, const void* pb){ const jv* a = pa; const jv* b = pb; int lena = jv_string_length(jv_copy(*a)); int lenb = jv_string_length(jv_copy(*b)); int minlen = lena < lenb ? lena : lenb; int r = memcmp(jv_string_value(*a), jv_string_value(*b), minlen); if (r == 0) r = lena - lenb; return r; } static void f_keys(jv input[], jv output[]) { if (jv_get_kind(input[0]) == JV_KIND_OBJECT) { int nkeys = jv_object_length(jv_copy(input[0])); jv* keys = malloc(sizeof(jv) * nkeys); int kidx = 0; jv_object_foreach(i, input[0]) { keys[kidx++] = jv_object_iter_key(input[0], i); } qsort(keys, nkeys, sizeof(jv), string_cmp); output[0] = jv_array_sized(nkeys); for (int i = 0; i=0; i--) { struct locfile src; locfile_init(&src, jq_builtins[i], strlen(jq_builtins[i])); block funcs; int nerrors = jq_parse_library(&src, &funcs); assert(!nerrors); b = block_bind(funcs, b, OP_IS_CALL_PSEUDO); locfile_free(&src); } block builtins = gen_noop(); for (unsigned i=0; i