diff --git a/Makefile.am b/Makefile.am index 9ff75274b4..0c9e8dcb93 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,14 +5,14 @@ LIBJQ_INCS = src/builtin.h src/bytecode.h src/compile.h \ src/exec_stack.h src/jq_parser.h src/jv_alloc.h src/jv_dtoa.h \ src/jv_unicode.h src/jv_utf8_tables.h src/lexer.l src/libm.h \ src/linker.h src/locfile.h src/opcode_list.h src/parser.y \ - src/util.h + src/util.h src/builtin_modules.h LIBJQ_SRC = src/builtin.c src/bytecode.c src/compile.c src/execute.c \ src/jq_test.c src/jv.c src/jv_alloc.c src/jv_aux.c \ src/jv_dtoa.c src/jv_file.c src/jv_parse.c src/jv_print.c \ src/jv_unicode.c src/linker.c src/locfile.c src/util.c \ src/decNumber/decContext.c src/decNumber/decNumber.c \ - src/jv_dtoa_tsd.c \ + src/jv_dtoa_tsd.c src/builtin_modules.c \ ${LIBJQ_INCS} ### C build options @@ -57,11 +57,11 @@ libjq_la_LIBADD = -lm libjq_la_LDFLAGS = $(onig_LDFLAGS) -export-symbols-regex '^j[qv]_' -version-info 1:4:0 if WIN32 -libjq_la_LIBADD += -lshlwapi +libjq_la_LIBADD += -lshlwapi -lbcrypt libjq_la_LDFLAGS += -no-undefined endif -include_HEADERS = src/jv.h src/jq.h +include_HEADERS = src/jv.h src/jq.h src/jq_plugin.h if ENABLE_UBSAN AM_CFLAGS += -fsanitize=undefined @@ -137,6 +137,11 @@ TESTS = tests/optionaltest tests/jqtest tests/onigtest tests/shtest tests/utf8te endif TESTS_ENVIRONMENT = NO_VALGRIND=$(NO_VALGRIND) +lib_LTLIBRARIES += somod.la +somod_la_SOURCES = tests/modules/somod/somod.c +somod_la_CFLAGS = -DJQ_PLUGIN +somod_la_LIBADD = +somod_la_LDFLAGS = -module ### Building the manpage @@ -185,6 +190,7 @@ EXTRA_DIST = $(DOC_FILES) $(man_MANS) $(TESTS) $(TEST_LOG_COMPILER) \ tests/modules/lib/jq/e/e.jq tests/modules/lib/jq/f.jq \ tests/modules/shadow1.jq tests/modules/shadow2.jq \ tests/modules/syntaxerror/syntaxerror.jq \ + tests/modules/somod/somod.jq tests/modules/somod/somod.c \ tests/modules/test_bind_order.jq \ tests/modules/test_bind_order0.jq \ tests/modules/test_bind_order1.jq \ diff --git a/README.plugins.md b/README.plugins.md new file mode 100644 index 0000000000..b0004976a8 --- /dev/null +++ b/README.plugins.md @@ -0,0 +1,107 @@ +jq FFI +====== + +jq now has an FFI. You can create a module with C-coded builtins. + +A jq module's jq source can say: + + module {"cfunctions":true}; + +to cause a shared object or DLL of the same name to be loaded. + +An alternative shared object or DLL name can be specified instead: + + module {"cfunctions":"my_shared_object"}; + +The shared object or DLL must export a function named `jq_plugin_init`, +or else it must list an alternative name for that function it its module +meta: + + module {"cfunctions":true,"plugin_init_function":"my_plugin_init"}; + +The module's C sources must `#define JQ_PLUGIN` and must `#include` all +of ``, ``, and ``. + +The init function has the following prototype: + + typedef int (*jq_plugin_init_f) + (int, /* jq plugin min supported ABI version */ + int, /* jq plugin max supported ABI version */ + struct jq_state *, + const char **, /* error string */ + const char **, /* jq-coded module contents */ + size_t *, /* jq-coded module contents size */ + struct cfunction **, /* array of C-coded function descriptors */ + size_t *); + +and must return 0 on success. On failure, it should output an error +string via the fourth argument. + +The plugin must check that two jq ABI integers include the +`JQ_CURRENT_ABI` that the plugin was compiled against. + +The plugin can output a replacement for its jq-coded part via the fifth +and sixth arguments. If the fifth argument is not `NULL` and the sixth +is `0`, then the string output in the fifth argument must be a C string +(i.e., `NUL`-terminated). + +The plugin can output C-coded functions via the seventh and eigth init +function arguments. + +Each C-coded function must have one the following prototypes: + + jv my_func(struct jq_state *jq, jv input); + jv my_func(struct jq_state *jq, jv input, jv arg); + jv my_func(struct jq_state *jq, jv input, jv a0, jv a1); + .. + jv my_func(struct jq_state *jq, jv input, jv a0, jv a1, jv a2, jv a3, jv a4, jv a5); + +and must have an entry in the `struct cfunction` array output by the +module's init function. + +`struct cfunction` is: + + typedef void (*cfunction_ptr)(); + struct cfunction { + cfunction_ptr fptr; /* function pointer */ + const char* name; /* jq function name */ + int nargs; /* number of arguments; must be at least 1 */ + unsigned int pure:1; /* 1 if pure, 0 if impure */ + unsigned int exported:1; /* 1 if exported, 0 if not */ + }; + + +jq plugins and DLL hell +======================= + +All `jv` and `jq` functions in a plugin are replaced with macros of this +form: + + #define jv_fname ((*(struct jq_plugin_vtable **)jq)->jv_fname) + +Here `jq` should be the `struct jq_state *` argument to the C-coded +builtin functions and the module's init function. + +This means that plugins can only call `jv` and `jq` functions in contexts +where a `jq` variable is visible (and of type `struct jq_state *jq`). + +Since the plugin's init function and all its C-coded functions receive a +`struct jq_state *jq` argument, a `struct jq_state *jq` should always be +available for calling `jv` and `jq` functions. + +This way, plugins do not need to be linked with `libjq`. This is quite +important, as it limits DLL hell. Essentially plugins "link" with +`libjq` dynamically at run-time without having to rely on the system's +RTLD to provide that functionality. + +This means that one can use the same plugin object in applications that +use different versions of `libjq`, provided that the jq ABIs of the two +`libjq` versions are sufficiently compatible (meaning, the layout of +`jv` is the same, both provide all the functions needed by the plugin, +and so on). + +Depending on the platform and how `libjq` or its callers are built +(e.g., with versioned symbols or direct binding) it should even be +possible even to have two different versions of `libjq` loaded in the +*same process* and loading the same plugins, and the plugins will always +use the `libjq` functions of the version of `libjq` calling them. diff --git a/configure.ac b/configure.ac index 68097b9133..20f39468c7 100644 --- a/configure.ac +++ b/configure.ac @@ -87,6 +87,10 @@ dnl Enable building all static AC_ARG_ENABLE([all-static], AC_HELP_STRING([--enable-all-static], [link jq with static libraries only])) +if test "x$enable_all_static" != xyes; then + AC_FIND_FUNC([dlopen], [dl], [#include ], [0, 0]) +fi + AS_IF([test "x$enable_docs" = "xyes"],[ AC_CHECK_PROGS(pipenv_cmd, pipenv) @@ -129,6 +133,8 @@ AM_CONDITIONAL([ENABLE_ALL_STATIC], [test "x$enable_all_static" = xyes]) AC_FUNC_ALLOCA +AC_FIND_FUNC([getline], [c], [#define _POSIX_C_SOURCE 200809L +#include ], [0, 0, 0]) AC_FIND_FUNC([isatty], [c], [#include ], [0]) AC_FIND_FUNC([_isatty], [c], [#include ], [0]) AC_FIND_FUNC([strptime], [c], [#include ], [0, 0, 0]) diff --git a/docs/content/manual/manual.yml b/docs/content/manual/manual.yml index d4af555a30..7a3de27a46 100644 --- a/docs/content/manual/manual.yml +++ b/docs/content/manual/manual.yml @@ -1053,7 +1053,7 @@ sections: values. examples: - - program: 'try error("\($__loc__)") catch .' + - program: 'try(error("\($__loc__)"); .)' input: 'null' output: ['"{\"file\":\"\",\"line\":1}"'] @@ -2159,25 +2159,35 @@ sections: input: '{}' output: [42] - - title: try-catch + - title: try-catch-finally body: | - Errors can be caught by using `try EXP catch EXP`. The first - expression is executed, and if it fails then the second is - executed with the error message. The output of the handler, - if any, is output as if it had been the output of the - expression to try. + Errors can be caught and handled by using any of `EXP?`, + `try(EXP)`, `try(EXP; EXP)`, or `try(EXP; EXP; EXP)`. - The `try EXP` form uses `empty` as the exception handler. + In the second and third forms, the second `EXP` is a handler + that will run when an error is handled. + + In the first two forms errors are suppressed, as if `empty` + had been used as the handler in the second or third forms. + + In the third form, the third `EXP` runs once in all cases, + after the first `EXP` is exhausted and the handler has run if + an error was produced. The input to the third, "finally" + expression will be `true` if no error was caught, or an array + containing the error if an error was caught. + + The older `try Exp catch Exp` syntax was problematic and is + now obsolete, and may be removed in future versions of jq. examples: - - program: 'try .a catch ". is not an object"' + - program: 'try(.a; ". is not an object")' input: 'true' output: ['". is not an object"'] - - program: '[.[]|try .a]' + - program: '[.[]|try(.a)]' input: '[{}, true, {"a":1}]' output: ['[null, 1]'] - - program: 'try error("some exception") catch .' + - program: 'try(error("some exception"); .)' input: 'true' output: ['"some exception"'] @@ -2192,7 +2202,7 @@ sections: # Repeat an expression until it raises "break" as an # error, then stop repeating without re-raising the error. # But if the error caught is not "break" then re-raise it. - try repeat(exp) catch .=="break" then empty else error; + try(repeat(exp); if .=="break" then empty else error end); jq has a syntax for named lexical labels to "break" or "go (back) to": @@ -2868,27 +2878,62 @@ sections: See your system's manual for more information on each of these. + - title: 'Random numbers' + body: | + + Three builtins provide access to entropy on systems that support + CNG (Windows) or /dev/urandom (Unix), `random` (outputs a random + number), `randombytes` (outputs an array of as many integer byte + values as its input number indicates), and `randomstring` (outputs + a string of as many Unicode codepoints between `NUL` and `U+FFFF` + as its input number indicates). Note well that `randomstring` may + not yield a meaningful, printable string! + - title: 'I/O' body: | - At this time jq has minimal support for I/O, mostly in the - form of control over when inputs are read. Two builtins functions - are provided for this, `input` and `inputs`, that read from the - same sources (e.g., `stdin`, files named on the command-line) as - jq itself. These two builtins, and jq's own reading actions, can - be interleaved with each other. - - Two builtins provide minimal output capabilities, `debug`, and - `stderr`. (Recall that a jq program's output values are always - output as JSON texts on `stdout`.) The `debug` builtin can have - application-specific behavior, such as for executables that use - the libjq C API but aren't the jq executable itself. The `stderr` - builtin outputs its input in raw mode to stder with no additional - decoration, not even a newline. + By default, jq has minimal support for I/O, mostly in the form of + control over when inputs are read. + + Adding the `-I` / `--io` command-line option enables more advanced + I/O builtins. + + More fine-grained control over what I/O actions a jq program may + execute can be gained using `--io-policy POLICY`, where `POLICY` + is a jq program that either outputs policy data, or consumes an + I/O action description and outputs `true` or `false` or an error. + The input to the `POLICY` is an object with a field named + `io_request` whose value is an object with `kind`, `name`, and + `mode` fields, all of which are string-valued. Thus to open a + file named "/tmp/foo" for reading the request would be + `{"io_request":{"kind":"file","name":"/tmp/foo","mode":"r"}}` (the + `name` will be a real path, with no `.` or `..` components). The + default `POLICY` accepts an array of objects with `kind`, `name` + or `prefix`, and `mode` fields, all of which are strings except + for `mode` which is an array of strings. + + Two builtin functions are available, by default, `input` and + `inputs`, that read from the same sources (e.g., `stdin`, files + named on the command-line) as jq itself. These two builtins, and + jq's own reading actions, can be interleaved with each other -- + this can be confusing, so use the `-n` command-line option when + using `inputs` to avoid this. + + Two builtins, available by default, provide minimal output + capabilities, `debug`, and `stderr`. (Recall that a jq program's + output values are always output as JSON texts on `stdout`.) The + `debug` builtin can have application-specific behavior, such as + for executables that use the libjq C API but aren't the jq + executable itself. The `stderr` builtin outputs its input in raw + mode to stder with no additional decoration, not even a newline. + + If the `-I` / `--io` command-line option is provided, then one can + `include "jq/io"` and then also have available builtin functions + that permit reading from or writing to arbitrary files. Most jq builtins are referentially transparent, and yield constant and repeatable value streams when applied to constant inputs. - This is not true of I/O builtins. + This is clearly not true of I/O builtins. entries: - title: "`input`" @@ -2930,6 +2975,141 @@ sections: Returns the line number of the input currently being filtered. + - title: "`unwind(protect) | rest`" + body: | + + Executes `protect|empty` when the `rest` produces no further + outputs, or when the `rest` raises an error, or `break`s out. + + The input to `protect` will be `true` as input if no error was + raised, else with the error produced by `rest`, wrapped in an + array, as input. + + This is useful for, for example, writing a footer to a file + after writing its contents. + + - title: "`streamfile` `slurpfile`" + body: | + + Read and parse JSON tests from the file named by `.`. + + `slurpfile` outputs an array of all the values in the file + named by `.`. + + These builtins are provided by the `"jq/io"` module. Prefix + `include "jq/io"` to your jq program, and use the `-I` / + `--io` command-line option to use it. + + - title: "`streamfile(name; options)` `slurpfile(name; options)`" + body: | + + Like `streamfile` and `slurpfile`. + + The `options` argument should be an array of any of the + following strings, `"raw"` (do not parse inputs, do not + JSON-encode strings on output), `"input_raw_lines"`, + `"input_stream"` (use the streaming JSON parser), `"compact"`, + `"tab"`, `"color"`, `"ascii"`, `"unbuffered"`, + `"output_raw_lines"` (do not JSON-encode strings on output, + print a newline between top-level values), `"output_raw"` (do + not print newlines between top-level values), `"output_seq"` + (output `application/json-seq`). These correspond to many of + the jq command-line options for input/output. + + These builtins are provided by the `"jq/io"` module. Prefix + `include "jq/io"` to your jq program, and use the `-I` / + `--io` command-line option to use it. + + - title: "`writefile(contents)`, `appendfile(contents)`" + body: | + + Write (or append) `contents` to the file named by `.`. + + These builtins are provided by the `"jq/io"` module. Prefix + `include "jq/io"` to your jq program, and use the `-I` / + `--io` command-line option to use it. + + - title: "`fhopen(fn; mode)` `fhopen(fn; mode; options)`" + body: | + + Opens the file named `fn` with the given `mode`, both of which + must be strings. + + Modes are the same as in `fopen(3)`. + + The `options` argument should be an array of any of the + following strings, `"raw"` (do not parse inputs, do not + JSON-encode strings on output), `"input_raw_lines"`, + `"input_stream"` (use the streaming JSON parser), `"compact"`, + `"tab"`, `"color"`, `"ascii"`, `"unbuffered"`, + `"output_raw_lines"` (do not JSON-encode strings on output, + print a newline between top-level values), `"output_raw"` (do + not print newlines between top-level values), `"output_seq"` + (output `application/json-seq`). These correspond to many of + the jq command-line options for input/output. + + The output is a file handle which will be closed + automatically when the scope calling `fhopen` exits. + + These builtins are provided by the `"jq/io"` module. Prefix + `include "jq/io"` to your jq program, and use the `-I` / + `--io` command-line option to use it. + + - title: "`fhopen(fn)`" + body: | + + Like `fhopen/2`, but opens the file named `fn` for reading. + + - title: "`fhopen`" + body: | + + Like `fhopen/1`, but opens its input filename for reading. + + - title: "`fhclose`" + body: | + + Closes the file handle given on input. + + Note that file handles are closed automatically, so there is + no need to call this. Accidentally referring to a file handle + after it has been closed yields an error. + + - title: "`fhread`" + body: | + + Reads the next value in the input file handle. + + - title: "`fhwrite(fh; output)`" + body: | + + Writes the given `output` as a JSON text to the given `fh` if + it is open for writing. + + - title: "`fhfeof`" + body: | + + Outputs `true` if the input file handle is at EOF, else + `false`. + + - title: "`fhinterleave`" + body: | + + Interleaves reads of every handle in the input array. + + - title: "`fhinterleave_repeat`" + body: | + + Interleaves reads of every handle in the input array, + resetting each as they reach EOF. If the file handles are for + plain files, then this will repeat forever. + + - title: "`fhinterleave_pad($pad)`" + body: | + + Interleaves reads of every handle in the input array, + using $pad when each handle reaches EOF, stopping when all + file handles read EOF. + - title: 'Streaming' body: | @@ -3154,6 +3334,121 @@ sections: (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] + - title: Eval + body: | + + The `eval/0` and `eval/3` builtins allow one to compile and + evaluate jq programs. + + entries: + - title: "`eval`" + body: | + + This builtin evaluates the input program. + + examples: + - program: 'eval' + input: '"1 + 2"' + output: ['3'] + + - title: "`eval(program; arguments; options)`" + body: | + + This builtin evaluates the given program, with the given + arguments, and the given options. The `program` must be a + string. + + `arguments` must be an object with a key for every global + `$binding` that the `program` may refer to. + + The `options` argument must be `null`, or an object that may + have a key `"ALLOW_IO"` whose value is a boolean. + + - title: "`eval`" + body: | + + This builtin is like `eval/3`, but it outputs an open handle + that can be read from using `fhread`. + + examples: + - program: '[coeval|label $out | repeat(fhread // break $out)]' + input: '"range(5)"' + output: ['[0,1,2,3,4]'] + + - title: "`coeval(program; arguments; options)`" + body: | + + This builtin is like `eval/3`, but it creates a co-routine to + evalue the program, and outputs an open handle that can be + read from using `fhread`. + + - title: Co-expressions + body: | + + jq has co-routines, called co-expressions. These can be used to, + for example, interleave the results of two generator expressions. + This is useful for building breadth-first search algorithms. + + We call these co-expressions because the expression to run as a + co-routine can have lexical bindings -- that is, it can see the + same variables and functions that the caller of `coexp/1` can see. + + The `inputs` builtin in a co-expression produces the last value + written to the co-expression via `fhwrite`. + + entries: + - title: "`codef ($)name: body; ...`" + body: | + + This form creates a co-routine to run `body`, creates a + function named `name` that extracts one output from the + co-routine, and a variable named `$name` that holds an open + handle for the co-routine. The handle can be written to + with `fhwrite`, with values written to it made available to + the co-routine body if it calls `input` or `inputs`. + + - title: "`coexp(expr)`" + body: | + + The `coexp(expr)` builtin produces the handle to a co-routine + that evaluates `expr` -- a co-expression. This handle will be + closed automatically. A jq program can read from a co-routine + handle using `fhread`. Once `expr` runs out of values, the + co-routine will be cleaned up. + + Note that `expr` is not a program string to be compiled and + evaluated! Instead, `expr` is a jq expression of arbitrary + complexity. To evaluate a string as a jq program, use `eval` + or `coeval`. + + - title: "`while(expr)`" + body: | + + Repeats `expr` while it's not empty. This is useful when + `expr` refers to one or more co-expressions. + + examples: + - program: 'codef ($)foo: 1,2,3; codef ($)bar: "a","b","c","d","e"; [while(foo?,bar?)]' + input: 'null' + output: ['[1,"a",2,"b",3,"c","d","e"]'] + + - title: "`def f(@@a0; a1; @@a2): body;`" + body: | + + This is syntactic sugar equivalent to `def f(a0; a1; a2): + codef ($)co0: a0; codef ($)co2: a2; body;`. + + This is useful for creating control structures. + + examples: + - program: 'def comingle(@@a; @@b): while(a, b); [comingle(1,2,3; "a","b","c")]' + input: 'null' + output: ['[1,"a",2,"b",3,"c"]'] + + - program: 'def f(@@a; @@b): a, b, b, a, b, a; [f(1,2,3; "a","b","c")]' + input: 'null' + output: ['[1,"a","b",2,"c",3]'] + - title: Modules body: | diff --git a/scripts/dwarf2h b/scripts/dwarf2h new file mode 100755 index 0000000000..b5d8f81aeb --- /dev/null +++ b/scripts/dwarf2h @@ -0,0 +1,281 @@ +#!/bin/bash + +PROG=${0##*/} + +function usage { + ((${1:-1})) && exec 1>&2 + cat <&2 'EOF\n' + eof=true + return 1 + fi + $debug && printf 2>&2 'READ: a=%s, b=%s\n' "$a" "$b" + return 0 +} + +function finish_function { + if $skip; then + printf 'WARNING: Excluding function with function-valued return type or argument, %s()\n' "$fname" 1>&2 + return 0 + fi + [[ -n ${fnames[$fname]} ]] && return 0 # probably static inline + $exported || return 0 # static + if ((${#pats[@]})); then + match=false + for pat in "${pats[@]}"; do + if [[ $fname = $pat ]]; then + match=true + break + fi + done + $match || return 0 + fi + if ((${#xpats[@]})); then + match=false + for pat in "${xpats[@]}"; do + if [[ $fname = $pat ]]; then + match=true + break + fi + done + $match && return 0 + fi + [[ -z $fname ]] && return 0 + [[ -n ${exclude[$fname]} ]] && return 0 + fnames[$fname]=$fname + IFS=, + $typedefs && printf 'typedef %s (*%s_f)(%s);\n' "$rettype" "$fname" "${argtypes[*]}" + $prototypes && $include_arg_names && + printf '%s %s(%s);\n' "$rettype" "$fname" "${args[*]}" + $prototypes && ! $include_arg_names && + printf '%s %s(%s);\n' "$rettype" "$fname" "${argtypes[*]}" + $stubs && printf '%s\n%s(%s)\n{\n}\n' "$rettype" "$fname" "${args[*]}" + if $typedefs; then + fields+=("${fname}_f ${fname}") + else + fields+=("$rettype (*${fname})(${argtypes[*]})") + fi + IFS=$OIFS +} + +function parse_function { + local skip=$skip + + args=() + argnames=() + argtypes=() + + [[ $a = 0x* && $b = DW_TAG_subprogram ]] || exit 5 + fname= + rettype=void + exported=false + + # Extract function name and type + while read1; do + # Functions with no arguments do not get a NULL to terminate their + # DWARF dump. In this case we will recurse. Hope we don't blow + # the stack. + if [[ $a = 0x* && $b = DW_TAG_subprogram ]]; then + $skip || finish_function + parse_function + $skip || finish_function + return $? + fi + + [[ $a = 0x* ]] && break + case "$a" in + DW_AT_external) [[ $b = *true* ]] && exported=true;; + DW_AT_name) + b=${b%\"*} + fname=${b#*\"};; + DW_AT_type) + b=${b%\"*} + rettype=${b#*\"} + [[ $rettype = [*]* ]] && rettype="void $rettype";; + *) true;; + esac + done + skip=false + [[ $rettype = *subroutine* ]] && skip=true + if [[ $b = DW_TAG_unspecified_parameters ]]; then + argtypes+=(...) + continue + fi + while [[ $b = DW_TAG_formal_parameter || $b = DW_TAG_unspecified_parameters ]]; do + argname= + argtype=void + while read1; do + if [[ $a = 0x* && $b = DW_TAG_subprogram ]]; then + $skip || finish_function + parse_function + $skip || finish_function + return $? + fi + [[ $a = 0x* ]] && break + case "$a" in + DW_AT_name) + b=${b%\"*} + argname=${b#*\"} + argnames+=("$argname");; + DW_AT_type) + b=${b%\"*} + argtype=${b#*\"} + [[ $argtype = [*]* ]] && argtype="void $argtype" + [[ $argtype = va_list ]] && argtype=... + [[ $argtype = __va_list_tag\* ]] && argtype=va_list + [[ $argtype = *subroutine* ]] && skip=true + argtypes+=("$argtype");; + *) true;; + esac + done + args+=("$argtype $argname") + done + if ! $eof; then + while [[ $a != 0x* || $b != NULL || $b != DW_TAG_subprogram ]]; do + read1 || break + if [[ $a = 0x* && $b = DW_TAG_subprogram ]]; then + finish_function + parse_function + return $? + fi + done + fi + finish_function +} + +declare -A fnames +fields=() +OIFS=$IFS +a= +b= +while read1; do + [[ $a = 0x* && $b = DW_TAG_subprogram ]] || continue + parse_function +done < <(if [[ -n $dwarf_in ]]; then cat "$dwarf_in"; else llvm-dwarfdump-6.0 "$@"; fi) + +if $struct; then + printf 'struct %s {\n' "$struct_name" + if ((${#exclude[@]} == 0)); then + printf ' %s;\n' "${fields[@]}" + else + # Print only fields for functions not listed in the FILE given via -f FILE. + # + # The developer will have to edit that file and add the new fields (and + # typedefs) themselves. + for field in "${fields[@]}"; do + fname=$(echo "$field" | grep '^\([^ ]*\)_f \1' | cut -d' ' -f2 | cut -d';' -f1; + echo "$field" | grep ')(' | cut -d'(' -f2 | cut -d'*' -f2 | cut -d')' -f1) + [[ -n ${exclude[$fname]} ]] && continue + printf ' %s;\n' "$field" + done + fi + printf '};\n' +fi + +if $macros; then + for fname in "${!fnames[@]}"; do + [[ -n ${exclude[$fname]} ]] && continue + printf '#define %s ((*(struct %s **)jq)->%s)\n' "$fname" "$struct_name" "$fname" + done +fi + +if $initializers; then + for fname in "${!fnames[@]}"; do + printf 'vtable->%s = %s;\n' "$fname" "$fname" + done +fi diff --git a/src/builtin.c b/src/builtin.c index 139bdfe68a..ea8d528831 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -1079,7 +1079,12 @@ static jv f_error(jq_state *jq, jv input) { // FIXME Should autoconf check for this! #ifndef WIN32 -extern char **environ; +# ifdef __APPLE__ +# include +# define environ (*_NSGetEnviron()) +# else + extern char ** environ; +# endif #endif static jv f_env(jq_state *jq, jv input) { @@ -1604,6 +1609,96 @@ static jv f_now(jq_state *jq, jv a) { } #endif +static jv f_vmid(jq_state *jq, jv a) { + jv_free(a); + return jq_get_vmid(jq); +} + +static jv coreset(jq_state *parent, jv input, void *vchild) { + jq_state *child = vchild; + jq_start(child, jv_null(), 0); + jv_free(input); + return jv_true(); +} + +static jv coinput_cb(jq_state *child, void *vjv) { + jv *jvp = vjv; + jv ret; + + if (jv_is_valid(*jvp) || jv_invalid_has_msg(jv_copy(*jvp))) { + ret = *jvp; + *jvp = jv_invalid(); + return ret; + } + return jv_invalid(); +} + +static jv cowrite(jq_state *parent, jv handle, void *vchild, jv v) { + jq_state *child = vchild; + jq_input_cb junk; + jv *jvp; + jq_get_input_cb(child, &junk, (void **)&jvp); + jv_free(*jvp); + *jvp = jv_copy(v); + jv_free(handle); + return v; +} + +static jv coread(jq_state *parent, jv handle, void *vchild) { + jq_state *child = vchild; + jv_free(handle); + if (child == parent) + return jv_invalid_with_msg(jv_string("Co-routines cannot call themselves")); + if (jq_finished(child)) + return jv_invalid(); + return jq_next(child); +} + +static jv coeof(jq_state *parent, jv handle, void *vchild) { + jq_state *child = vchild; + jv_free(handle); + return jq_finished(child) ? jv_true() : jv_false(); +} + +static jv coclose(jq_state *parent, jv handle, void *vchild) { + jq_state *child = vchild; + if (child) + jq_teardown(&child); + jv_free(handle); + return jv_true(); +} + +struct jq_io_table jq__covt = { + .kind = "coroutine", + .fhclose = coclose, + .fhreset = coreset, + .fhwrite = cowrite, + .fhread = coread, + .fhstat = 0, + .fheof = coeof, +}; + +static jv f_random_int(jq_state *jq, jv a) { + jv_free(a); + return jv_number_random_int(); +} + +static jv f_random_bytes(jq_state *jq, jv a) { + if (jv_get_kind(a) != JV_KIND_NUMBER) + return jv_invalid_with_msg(jv_string("randombytes needs an integer input")); + size_t n = jv_number_value(a); + jv_free(a); + return jv_number_random_bytes(n); +} + +static jv f_random_string(jq_state *jq, jv a) { + if (jv_get_kind(a) != JV_KIND_NUMBER) + return jv_invalid_with_msg(jv_string("randomstring needs an integer input")); + size_t n = jv_number_value(a); + jv_free(a); + return jv_number_random_string(n); +} + static jv f_current_filename(jq_state *jq, jv a) { jv_free(a); @@ -1619,96 +1714,107 @@ static jv f_current_line(jq_state *jq, jv a) { } #define LIBM_DD(name) \ - {(cfunction_ptr)f_ ## name, #name, 1}, + {(cfunction_ptr)f_ ## name, #name, 1, 1, 1}, #define LIBM_DD_NO(name) #define LIBM_DDD(name) \ - {(cfunction_ptr)f_ ## name, #name, 3}, + {(cfunction_ptr)f_ ## name, #name, 3, 1, 1}, #define LIBM_DDD_NO(name) #define LIBM_DDDD(name) \ - {(cfunction_ptr)f_ ## name, #name, 4}, + {(cfunction_ptr)f_ ## name, #name, 4, 1, 1}, #define LIBM_DDDD_NO(name) static const struct cfunction function_list[] = { #include "libm.h" #ifdef HAVE_FREXP - {(cfunction_ptr)f_frexp,"frexp", 1}, + {(cfunction_ptr)f_frexp,"frexp", 1, 1, 1}, #endif #ifdef HAVE_MODF - {(cfunction_ptr)f_modf,"modf", 1}, + {(cfunction_ptr)f_modf,"modf", 1, 1, 1}, #endif #ifdef HAVE_LGAMMA_R - {(cfunction_ptr)f_lgamma_r,"lgamma_r", 1}, + {(cfunction_ptr)f_lgamma_r,"lgamma_r", 1, 1, 1}, #endif - {(cfunction_ptr)f_plus, "_plus", 3}, - {(cfunction_ptr)f_negate, "_negate", 1}, - {(cfunction_ptr)f_minus, "_minus", 3}, - {(cfunction_ptr)f_multiply, "_multiply", 3}, - {(cfunction_ptr)f_divide, "_divide", 3}, - {(cfunction_ptr)f_mod, "_mod", 3}, - {(cfunction_ptr)f_dump, "tojson", 1}, - {(cfunction_ptr)f_json_parse, "fromjson", 1}, - {(cfunction_ptr)f_tonumber, "tonumber", 1}, - {(cfunction_ptr)f_tostring, "tostring", 1}, - {(cfunction_ptr)f_keys, "keys", 1}, - {(cfunction_ptr)f_keys_unsorted, "keys_unsorted", 1}, - {(cfunction_ptr)f_startswith, "startswith", 2}, - {(cfunction_ptr)f_endswith, "endswith", 2}, - {(cfunction_ptr)f_ltrimstr, "ltrimstr", 2}, - {(cfunction_ptr)f_rtrimstr, "rtrimstr", 2}, - {(cfunction_ptr)f_string_split, "split", 2}, - {(cfunction_ptr)f_string_explode, "explode", 1}, - {(cfunction_ptr)f_string_implode, "implode", 1}, - {(cfunction_ptr)f_string_indexes, "_strindices", 2}, - {(cfunction_ptr)f_setpath, "setpath", 3}, // FIXME typechecking - {(cfunction_ptr)f_getpath, "getpath", 2}, - {(cfunction_ptr)f_delpaths, "delpaths", 2}, - {(cfunction_ptr)f_has, "has", 2}, - {(cfunction_ptr)f_equal, "_equal", 3}, - {(cfunction_ptr)f_notequal, "_notequal", 3}, - {(cfunction_ptr)f_less, "_less", 3}, - {(cfunction_ptr)f_greater, "_greater", 3}, - {(cfunction_ptr)f_lesseq, "_lesseq", 3}, - {(cfunction_ptr)f_greatereq, "_greatereq", 3}, - {(cfunction_ptr)f_contains, "contains", 2}, - {(cfunction_ptr)f_length, "length", 1}, - {(cfunction_ptr)f_utf8bytelength, "utf8bytelength", 1}, - {(cfunction_ptr)f_type, "type", 1}, - {(cfunction_ptr)f_isinfinite, "isinfinite", 1}, - {(cfunction_ptr)f_isnan, "isnan", 1}, - {(cfunction_ptr)f_isnormal, "isnormal", 1}, - {(cfunction_ptr)f_infinite, "infinite", 1}, - {(cfunction_ptr)f_nan, "nan", 1}, - {(cfunction_ptr)f_sort, "sort", 1}, - {(cfunction_ptr)f_sort_by_impl, "_sort_by_impl", 2}, - {(cfunction_ptr)f_group_by_impl, "_group_by_impl", 2}, - {(cfunction_ptr)f_min, "min", 1}, - {(cfunction_ptr)f_max, "max", 1}, - {(cfunction_ptr)f_min_by_impl, "_min_by_impl", 2}, - {(cfunction_ptr)f_max_by_impl, "_max_by_impl", 2}, - {(cfunction_ptr)f_error, "error", 1}, - {(cfunction_ptr)f_format, "format", 2}, - {(cfunction_ptr)f_env, "env", 1}, - {(cfunction_ptr)f_halt, "halt", 1}, - {(cfunction_ptr)f_halt_error, "halt_error", 2}, - {(cfunction_ptr)f_get_search_list, "get_search_list", 1}, - {(cfunction_ptr)f_get_prog_origin, "get_prog_origin", 1}, - {(cfunction_ptr)f_get_jq_origin, "get_jq_origin", 1}, - {(cfunction_ptr)f_match, "_match_impl", 4}, - {(cfunction_ptr)f_modulemeta, "modulemeta", 1}, - {(cfunction_ptr)f_input, "input", 1}, - {(cfunction_ptr)f_debug, "debug", 1}, - {(cfunction_ptr)f_stderr, "stderr", 1}, - {(cfunction_ptr)f_strptime, "strptime", 2}, - {(cfunction_ptr)f_strftime, "strftime", 2}, - {(cfunction_ptr)f_strflocaltime, "strflocaltime", 2}, - {(cfunction_ptr)f_mktime, "mktime", 1}, - {(cfunction_ptr)f_gmtime, "gmtime", 1}, - {(cfunction_ptr)f_localtime, "localtime", 1}, - {(cfunction_ptr)f_now, "now", 1}, - {(cfunction_ptr)f_current_filename, "input_filename", 1}, - {(cfunction_ptr)f_current_line, "input_line_number", 1}, + {(cfunction_ptr)f_plus, "_plus", 3, 1, 1}, + {(cfunction_ptr)f_negate, "_negate", 1, 1, 1}, + {(cfunction_ptr)f_minus, "_minus", 3, 1, 1}, + {(cfunction_ptr)f_multiply, "_multiply", 3, 1, 1}, + {(cfunction_ptr)f_divide, "_divide", 3, 1, 1}, + {(cfunction_ptr)f_mod, "_mod", 3, 1, 1}, + {(cfunction_ptr)f_dump, "tojson", 1, 1, 1}, + {(cfunction_ptr)f_json_parse, "fromjson", 1, 1, 1}, + {(cfunction_ptr)f_tonumber, "tonumber", 1, 1, 1}, + {(cfunction_ptr)f_tostring, "tostring", 1, 1, 1}, + {(cfunction_ptr)f_keys, "keys", 1, 1, 1}, + {(cfunction_ptr)f_keys_unsorted, "keys_unsorted", 1, 1, 1}, + {(cfunction_ptr)f_startswith, "startswith", 2, 1, 1}, + {(cfunction_ptr)f_endswith, "endswith", 2, 1, 1}, + {(cfunction_ptr)f_ltrimstr, "ltrimstr", 2, 1, 1}, + {(cfunction_ptr)f_rtrimstr, "rtrimstr", 2, 1, 1}, + {(cfunction_ptr)f_string_split, "split", 2, 1, 1}, + {(cfunction_ptr)f_string_explode, "explode", 1, 1, 1}, + {(cfunction_ptr)f_string_implode, "implode", 1, 1, 1}, + {(cfunction_ptr)f_string_indexes, "_strindices", 2, 1, 1}, + {(cfunction_ptr)f_setpath, "setpath", 3, 1, 1}, // FIXME typechecking + {(cfunction_ptr)f_getpath, "getpath", 2, 1, 1}, + {(cfunction_ptr)f_delpaths, "delpaths", 2, 1, 1}, + {(cfunction_ptr)f_has, "has", 2, 1, 1}, + {(cfunction_ptr)f_equal, "_equal", 3, 1, 1}, + {(cfunction_ptr)f_notequal, "_notequal", 3, 1, 1}, + {(cfunction_ptr)f_less, "_less", 3, 1, 1}, + {(cfunction_ptr)f_greater, "_greater", 3, 1, 1}, + {(cfunction_ptr)f_lesseq, "_lesseq", 3, 1, 1}, + {(cfunction_ptr)f_greatereq, "_greatereq", 3, 1, 1}, + {(cfunction_ptr)f_contains, "contains", 2, 1, 1}, + {(cfunction_ptr)f_length, "length", 1, 1, 1}, + {(cfunction_ptr)f_utf8bytelength, "utf8bytelength", 1, 1, 1}, + {(cfunction_ptr)f_type, "type", 1, 1, 1}, + {(cfunction_ptr)f_isinfinite, "isinfinite", 1, 1, 1}, + {(cfunction_ptr)f_isnan, "isnan", 1, 1, 1}, + {(cfunction_ptr)f_isnormal, "isnormal", 1, 1, 1}, + {(cfunction_ptr)f_infinite, "infinite", 1, 1, 1}, + {(cfunction_ptr)f_nan, "nan", 1, 1, 1}, + {(cfunction_ptr)f_sort, "sort", 1, 1, 1}, + {(cfunction_ptr)f_sort_by_impl, "_sort_by_impl", 2, 1, 1}, + {(cfunction_ptr)f_group_by_impl, "_group_by_impl", 2, 1, 1}, + {(cfunction_ptr)f_min, "min", 1, 1, 1}, + {(cfunction_ptr)f_max, "max", 1, 1, 1}, + {(cfunction_ptr)f_min_by_impl, "_min_by_impl", 2, 1, 1}, + {(cfunction_ptr)f_max_by_impl, "_max_by_impl", 2, 1, 1}, + {(cfunction_ptr)f_error, "error", 1, 0, 1}, + {(cfunction_ptr)f_format, "format", 2, 1, 1}, + {(cfunction_ptr)f_env, "env", 1, 0, 1}, + {(cfunction_ptr)f_halt, "halt", 1, 0, 1}, + {(cfunction_ptr)f_halt_error, "halt_error", 2, 0, 1}, + {(cfunction_ptr)f_get_search_list, "get_search_list", 1, 0, 1}, + {(cfunction_ptr)f_get_prog_origin, "get_prog_origin", 1, 0, 1}, + {(cfunction_ptr)f_get_jq_origin, "get_jq_origin", 1, 0, 1}, + {(cfunction_ptr)f_match, "_match_impl", 4, 1, 1}, + {(cfunction_ptr)f_modulemeta, "modulemeta", 1, 0, 1}, + {(cfunction_ptr)f_input, "input", 1, 0, 1}, + {(cfunction_ptr)f_debug, "debug", 1, 0, 1}, + {(cfunction_ptr)f_stderr, "stderr", 1, 0, 1}, + {(cfunction_ptr)f_strptime, "strptime", 2, 1, 1}, + {(cfunction_ptr)f_strftime, "strftime", 2, 1, 1}, + {(cfunction_ptr)f_strflocaltime, "strflocaltime", 2, 1, 1}, + {(cfunction_ptr)f_mktime, "mktime", 1, 1, 1}, + {(cfunction_ptr)f_gmtime, "gmtime", 1, 1, 1}, + {(cfunction_ptr)f_localtime, "localtime", 1, 1, 1}, + {(cfunction_ptr)f_now, "now", 1, 0, 1}, + {(cfunction_ptr)f_vmid, "vmid", 1, 0, 1}, + {(cfunction_ptr)f_random_int, "random", 1, 0, 1}, + {(cfunction_ptr)f_random_bytes, "randombytes", 1, 0, 1}, + {(cfunction_ptr)f_random_string, "randomstring", 1, 0, 1}, + {(cfunction_ptr)f_current_filename, "input_filename", 1, 0, 1}, + {(cfunction_ptr)f_current_line, "input_line_number", 1, 0, 1}, + {(cfunction_ptr)jq_handle_get_kind, "fhkind", 1, 0, 1}, + {(cfunction_ptr)jq_handle_close, "fhclose", 1, 0, 1}, + {(cfunction_ptr)jq_handle_reset, "fhreset", 1, 0, 1}, + {(cfunction_ptr)jq_handle_write, "fhwrite", 2, 0, 1}, + {(cfunction_ptr)jq_handle_read, "fhread", 1, 0, 1}, + {(cfunction_ptr)jq_handle_stat, "fhstat", 1, 0, 1}, + {(cfunction_ptr)jq_handle_eof, "fheof", 1, 0, 1}, }; #undef LIBM_DDDD_NO #undef LIBM_DDD_NO @@ -1717,20 +1823,91 @@ static const struct cfunction function_list[] = { #undef LIBM_DDD #undef LIBM_DD + struct bytecoded_builtin { const char* name; block code; }; -static block bind_bytecoded_builtins(block b) { +static block private_inlines(void) { block builtins = gen_noop(); + /* + * The following are all special bytecoded builtins that only jq-coded + * builtins should be able to use. User programs should not be able to use + * them, otherwise they could corrupt jq VMs. + * + * We'll inline these. + */ + { + struct bytecoded_builtin builtin_defs[] = { + {"coeval", gen_op_simple(COEVAL)}, + }; + for (unsigned i=0; i", jq_builtins, sizeof(jq_builtins)-1); int nerrors = jq_parse_library(src, &builtins); assert(!nerrors); locfile_free(src); + in_pub = public_inlines(); + in_priv = private_inlines(); + builtins = bind_bytecoded_builtins(builtins); builtins = gen_cbinding(function_list, sizeof(function_list)/sizeof(function_list[0]), builtins); - builtins = gen_builtin_list(builtins); + builtins = gen_builtin_list(builtins, in_pub); + + // private inlines are just for usage inside builtins + block_inline(in_priv, builtins); + + // inline the publics before binding the user code, which may have + // its own definitions of the same functions (not our problem) + // here we make sure that at least our own builtins use the correc inlines + block_inline(in_pub, builtins); *bb = block_bind_referenced(builtins, *bb, OP_IS_CALL_PSEUDO); + + // now inline whatever publics are still unbound and matching in the user code + block_inline(in_pub, *bb); + + block_free(in_pub); + block_free(in_priv); + return nerrors; } diff --git a/src/builtin.jq b/src/builtin.jq index ee78017609..605a34a769 100644 --- a/src/builtin.jq +++ b/src/builtin.jq @@ -1,3 +1,4 @@ +def fhwrite($fh; $output): $fh|fhwrite($output); def halt_error: halt_error(5); def error(msg): msg|error; def map(f): [.[] | f]; @@ -143,6 +144,13 @@ def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; +def while(exp): + label $out | + def _while: + foreach . as $nothing (null; (exp|[.])//break $out; + .[0]), + _while; + _while; def until(cond; next): def _until: if cond then . else (next|_until) end; @@ -261,6 +269,17 @@ def walk(f): else f end; +# Run `protect` no matter what when backtracking through a call to this +# function. `protect` gets called with `true` if no error was raised, +# else with the error (wrapped in an array) that was raised. +def _unwind(protect): + . as $dot | + unwinding | + if .==false then $dot + else protect + end; +def unwind(protect): _unwind(protect|empty); + # SQL-ish operators here: def INDEX(stream; idx_expr): reduce stream as $row ({}; .[$row|idx_expr|tostring] = $row); @@ -273,3 +292,129 @@ def JOIN($idx; stream; idx_expr; join_expr): stream | [., $idx[idx_expr]] | join_expr; def IN(s): any(s == .; .); def IN(src; s): any(src == s; .); + +def _try_finally(e; h; f): + . as $dot | + unwinding | + if .==false then $dot|try(e; h) + else f + end; + +# Default I/O policy evaluator. +# +# Input must be of form {io_request:,io_policy:}, +# where is: +# +# {kind:"",name:""} +# {kind:"",name:"",mode:""} +# +# is one of: +# +# [,...] +# {kinds:{"":{"":}}} +# {kind:"",name:"",mode:[,...]} +# {kind:"",prefix:"",mode:[,...]} +# +# is one of "file", "popen", "system", or "spawn" +# is the a file path or command +# is a string prefix of a file path ('/' gets no special treatment) +def default_io_policy_check: + select(.!=null) | + .io_request as $req | + + def check_file: + (.kind==$req.kind) and + (.mode|select(.!=null)|any(. == ($req.mode))) and + ((.name == $req.name) or + ((.prefix|type) == "string" and .prefix as $prefix | ($req.name|startswith($prefix)))); + + def check_cmd: + (.kind==$req.kind) and + (.mode|select(.!=null)|any(. == ($req.mode))) and + .name == $req.name; + + def check: + if $req.kind=="file" then check_file + elif $req.kind=="popen" then check_cmd + elif $req.kind=="system" then check_cmd + # Note that file actions for spawn are checked separately, though + # we could also check them here. + elif $req.kind=="spawn" then check_cmd + else false end; + + .io_policy as $policy | + if $policy == true then + true + elif ($policy|type) == "array" then + $policy|any(check) + elif ($policy|type) == "object" then + ($policy.kinds[$req.kind//""][$req.name//""]|(.kind=$req.kind)|(.name=$req.name)|check) or ($policy|check) + else + false + end; + +def coeval(program; args; options): [program, ., args, options] | coeval; +def eval(program; args; options): + coeval(program; args; options) | fhread; +def eval: . as $dot | null | eval($dot; {}; {}); +def coeval: . as $program | null | coeval($program; {}; {}); + +def fhinterleave: + label $out | repeat(.[] | try [fhread] | if length==1 then .[0] else break $out end); + +def fhinterleave_repeat: + repeat(.[] | . as $fh | (fhread // (fhreset | $fh | fhread))); + +def fhinterleave_pad($pad): + . as $all | + label $out | repeat( + .[] | [fhread] | + if length==1 then + .[] + elif $all|all(fheof) then $pad, break $out + elif fheof + then $pad + else empty end); + +## We could really use vararg support here: +#def comingle(a; b): +# coexp(a) as $a | coexp(b) as $b | [$a, $b] | fhinterleave; +#def comingle(a; b; c): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | [$a, $b, $c] | fhinterleave; +#def comingle(a; b; c; d): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | [$a, $b, $c, $d] | fhinterleave; +#def comingle(a; b; c; d; e): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | coexp(e) as $e | [$a, $b, $c, $d, $e] | fhinterleave; +#def comingle(a; b; c; d; e; f): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | coexp(e) as $e | coexp(f) as $f | [$a, $b, $c, $d, $e, $f] | fhinterleave; +# +#def comingle_repeat(a; b): +# coexp(a) as $a | coexp(b) as $b | [$a, $b] | fhinterleave_repeat; +#def comingle_repeat(a; b; c): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | [$a, $b, $c] | fhinterleave_repeat; +#def comingle_repeat(a; b; c; d): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | [$a, $b, $c, $d] | fhinterleave_repeat; +#def comingle_repeat(a; b; c; d; e): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | coexp(e) as $e | [$a, $b, $c, $d, $e] | fhinterleave_repeat; +#def comingle_repeat(a; b; c; d; e; f): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | coexp(e) as $e | coexp(f) as $f | [$a, $b, $c, $d, $e, $f] | fhinterleave_repeat; +# +#def comingle_pad($pad; a; b): +# coexp(a) as $a | coexp(b) as $b | [$a, $b] | fhinterleave_pad($pad); +#def comingle_pad($pad; a; b; c): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | [$a, $b, $c] | fhinterleave_pad($pad); +#def comingle_pad($pad; a; b; c; d): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | [$a, $b, $c, $d] | fhinterleave_pad($pad); +#def comingle_pad($pad; a; b; c; d; e): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | coexp(e) as $e | [$a, $b, $c, $d, $e] | fhinterleave_pad($pad); +#def comingle_pad($pad; a; b; c; d; e; f): +# coexp(a) as $a | coexp(b) as $b | coexp(c) as $c | +# coexp(d) as $d | coexp(e) as $e | coexp(f) as $f | [$a, $b, $c, $d, $e, $f] | fhinterleave_pad($pad); diff --git a/src/builtin_modules.c b/src/builtin_modules.c new file mode 100644 index 0000000000..bc056adf56 --- /dev/null +++ b/src/builtin_modules.c @@ -0,0 +1,962 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#endif + +#include "jv.h" +#include "jv_unicode.h" +#include "jq.h" +#include "jq_plugin.h" +#include "jv_alloc.h" +#include "linker.h" +#include "util.h" +#include "builtin_modules.h" + +/* + * This file defines builtin modules that can be imported or included by + * jq programs or jq modules. + * + * TBD: + * + * - XXX make sure to relapth all paths always! + * - finish the spawn module for WIN32 + * - add a POSIX filesystem module (non-stdio open, stat, rename, link, symlink, ...) + * - add a WIN32 filesystem module (non-stdio open/CreateFile, ...) + * - add an HTTP client module (maybe using curl) + * - add a PostgreSQL module (maybe including a sandbox / private / ephemeral + * postgres server option) + * - add crypto modules (at least hash functions) + * - add a proper jq/math module and move libm bindings there, with a default + * implied include of that module into jq programs for backwards-compat? + */ + +/* + * I/O module + */ + +struct io_handle { + FILE *f; + jv_parser *parser; + jv fn; + jv cmd; + jv spawnspec; + jv mode; + enum jv_parse_flags in_options; + enum jv_print_flags out_options; + char buf[4096 - (sizeof(FILE *) + sizeof(jv_parser *) + sizeof(jv))]; +}; + +static jv allow_io(jq_state *jq, const char *what, jv req, jv s) { + jv ret = jq_io_policy_check(jq, req); + + if (jv_get_kind(ret) == JV_KIND_TRUE) + return ret; + + const char *reason = ""; + jv junk = jv_null(); + + if (jv_get_kind(ret) == JV_KIND_INVALID && jv_invalid_has_msg(jv_copy(ret))) { + junk = jv_invalid_get_msg(jv_copy(ret)); + if (jv_get_kind(junk) == JV_KIND_STRING) + reason = jv_string_value(junk); + } + jv_free(ret); + ret = jv_invalid_with_msg(jv_string_fmt("%s: Use of %s rejected by policy: %s", what, + jv_string_value(s), reason)); + jv_free(junk); + return ret; +} + +static jv f_close(jq_state *jq, jv handle, void *d) { + struct io_handle *h = d; + jv ret = jv_invalid(); + + if (!h) { + jv_free(handle); + return ret; + } + if (h->f && h->f != stdin && h->f != stdout && h->f != stderr) + ret = jv_number(fclose(h->f)); + if (h->parser) + jv_parser_free(h->parser); + jv_free(h->mode); + jv_free(h->fn); + jv_free(h->cmd); + jv_free(handle); + free(h); + return jv_is_valid(ret) ? ret : jv_number(0); +} + +static jv builtin_jq_fhclose(jq_state *jq, jv input) { + return jq_handle_close(jq, input); +} + +static jv f_reset(jq_state *jq, jv handle, void *vh) { + struct io_handle *h = vh; + if (!h || !h->f) + return jv_invalid_with_msg(jv_string("No such file handle")); + clearerr(h->f); + fseek(h->f, 0, SEEK_SET); + jv_free(handle); + return jv_true(); +} + +#ifndef HAVE_GETLINE +#ifdef getline +#undef getline +#endif +#define getline my_getline +static ssize_t getline(char **lp, size_t *np, FILE *f) { + size_t len = 0; + int save_errno = errno; + + if (*lp == 0 && *np == 0) + *lp = jv_mem_calloc(1, (*np = 128)); + + while (strchr((*lp) + len, '\n') == 0) { + if (len == (*np) - 1) { + size_t addition = (*np >> 1) + 32; + *lp = jv_mem_realloc(*lp, (*np) + addition); + *np += addition; + memset((*lp) + len, 0, addition); + } + if (*np > INT_MAX) { + errno = ERANGE; + return -1; + } + if (fgets((*lp) + len, (*np) - len, f)) { + len += strlen((*lp) + len); + if ((*lp)[len - 1] == '\n') + break; + continue; + } + if (errno || ferror(f)) + return -1; + /* EOF */ + if (len == 0) + return -1; + break; + } + errno = save_errno; + return len; +} +#endif + +static jv f_getline(jq_state *jq, struct io_handle *h) { + if (!h || !h->f) + return jv_invalid_with_msg(jv_string("No such file handle")); + + char *s = 0; + size_t n = 0; + ssize_t bytes; + int save_errno = errno; + + errno = 0; + if ((bytes = getline(&s, &n, h->f)) < 0) { + free(s); + if (feof(h->f)) + return jv_invalid(); + if (errno) + return jv_invalid_with_msg(jv_string(strerror(errno))); + return jv_invalid_with_msg(jv_string("Unspecified I/O error")); + } + if (bytes > 1 && s[bytes-2] == '\r' && s[bytes-1] == '\n') + s[bytes-2] = '\0'; + else if (bytes > 0 && s[bytes-1] == '\n') + s[bytes-1] = '\0'; + errno = save_errno; + jv ret = jv_string(s); + free(s); + return ret; +} + +static jv f_read(jq_state *jq, jv input, void *vh) { + struct io_handle *h = vh; + jv_free(input); + if (!h || !h->f) + return jv_invalid_with_msg(jv_string("No such file handle")); + if (!h->parser) + return f_getline(jq, h); + + jv v = jv_parser_next(h->parser); + if (jv_is_valid(v) || jv_invalid_has_msg(jv_copy(v))) + return v; + + /* Need to read more */ + + // To avoid mangling UTF-8 multi-byte sequences that cross the end of our read + // buffer, we need to be able to read the remainder of a sequence and add that + // before appending. + const int max_utf8_len = 4; + while (!feof(h->f) && !ferror(h->f)) { + h->buf[0] = 0; + fgets(h->buf, sizeof(h->buf) - max_utf8_len, h->f); + size_t n = strlen(h->buf); + if (n == 0) + continue; /* breaks anyways bc EOF or error */ + + int missing = 0; + if (jvp_utf8_backtrack(h->buf+(n-1), h->buf, &missing) && missing > 0 && + !feof(h->f) && !ferror(h->f)) { + off_t off = ftello(h->f); + n += fread(h->buf+n, 1, missing, h->f); + /* Check that we got what we needed! */ + jvp_utf8_backtrack(h->buf+(n-1), h->buf, &missing); + if (missing) + return jv_invalid_with_msg(jv_string_fmt("File contents appears truncated in %s at offset %lld", + jv_string_value(h->fn), (long long)off)); + } + jv_parser_set_buf(h->parser, h->buf, n, !feof(h->f)); + if (jv_is_valid((v = jv_parser_next(h->parser))) || jv_invalid_has_msg(jv_copy(v))) + return v; + } + return jv_invalid(); +} + +static jv f_write(jq_state *jq, jv input, void *vh, jv output) { + struct io_handle *h = vh; + + if (!h->f) { + jv_free(output); + return jv_invalid_with_msg(jv_string("fhwrite: no such file handle")); + } + if (!jv_is_valid(output)) { + jv_free(output); + return jv_invalid_with_msg(jv_string("fhwrite: invalid output")); + } + + jv actual_output; + if (jv_get_kind(output) == JV_KIND_STRING && + (h->out_options & JV_PRINT_RAW)) + actual_output = jv_copy(output); + else + actual_output = jv_dump_string(jv_copy(output), h->out_options); + + size_t bytes; + int len = jv_string_length_bytes(jv_copy(actual_output)); + const char *p = jv_string_value(actual_output); + while (len > 0) { + if ((bytes = fwrite(p, 1, len, h->f)) > 0) { + len -= bytes; + p += bytes; + } + } + if (len == 0 && !(h->out_options & JV_PRINT_NOLF)) { + if ((bytes = fwrite("\n", 1, 1, h->f)) == 0) + len = 1; + } + + jv ret = len > 0 ? jv_invalid_with_msg(jv_string("Partial write")) : + jv_copy(output); + jv_free(actual_output); + jv_free(output); + return ret; +} + +static jv f_eof(jq_state *jq, jv input, void *vh) { + struct io_handle *h = vh; + jv_free(input); + if (!h || !h->f) + return jv_invalid_with_msg(jv_string("No such file handle")); + return feof(h->f) ? jv_true() : jv_false(); +} + +static jv builtin_jq_fhname(jq_state *jq, jv fh) { + struct io_handle *h = jq_handle_get(jq, fh); + + if (h && jv_is_valid(h->fn)) + return jv_copy(h->fn); + return jv_invalid_with_msg(jv_string("filename for filehandle not known")); +} + +struct jq_io_table f_iovt = { + .kind = "FILE", + .fhclose = f_close, + .fhreset = f_reset, + .fhwrite = f_write, + .fhread = f_read, + .fhstat = 0, + .fheof = f_eof, +}; + +static jv make_f_handle(jq_state *jq, FILE *f, jv fn, jv cmd, jv spawnspec, jv mode, jv in_opts, jv out_opts) { + struct io_handle *h = jv_mem_alloc(sizeof(*h)); + h->f = f; + h->fn = fn; + h->cmd = cmd; + h->spawnspec = spawnspec; + h->mode = mode; + h->in_options = jv_number_value(in_opts); + h->out_options = jv_number_value(out_opts); + jv_free(in_opts); + jv_free(out_opts); + if (h->in_options & JV_PARSE_RAW) + h->parser = 0; + else + h->parser = jv_parser_new(0); + return jq_handle_new(jq, "FILE", &f_iovt, h); +} + +static jv builtin_jq_fopen(jq_state *jq, jv input, jv fn, jv mode, jv in_opts, jv out_opts) { + jv_free(input); + jv ret = jv_true(); + + if (jv_get_kind(fn) != JV_KIND_STRING) + ret = jv_invalid_with_msg(jv_string("fopen: filename must be a string")); + if (jv_is_valid(ret) && jv_get_kind(mode) != JV_KIND_STRING) + ret = jv_invalid_with_msg(jv_string("fopen: mode must be a string")); + if (jv_is_valid(ret) && !jv_is_valid((in_opts = jv_parse_options(in_opts)))) + ret = jv_invalid_with_msg(jv_string("fopen: invalid input options")); + if (jv_is_valid(ret) && !jv_is_valid((out_opts = jv_dump_options(out_opts)))) + ret = jv_invalid_with_msg(jv_string("fopen: invalid output options")); + if (jv_is_valid(ret)) { + ret = allow_io(jq, "fopen", + JV_OBJECT(jv_string("kind"), jv_string("file"), + jv_string("name"), jv_copy(fn), + jv_string("mode"), jv_copy(mode)), + fn); + } + if (!jv_is_valid(ret)) + goto out; + + FILE *f = 0; + /* + * On some systems calling fopen("/dev/stdin","r") when stdin is a + * pipe can fail! Besides, this lets us support these three "devices" + * on Windows. And we avoid the Linux /dev/fd semantics. + */ + if (strcmp(jv_string_value(fn), "/dev/stdin") == 0) + f = stdin; + else if (strcmp(jv_string_value(fn), "/dev/stdout") == 0) + f = stdout; + else if (strcmp(jv_string_value(fn), "/dev/stderr") == 0) + f = stderr; + else + f = fopen(jv_string_value(fn), jv_string_value(mode)); + if (f) { + ret = make_f_handle(jq, f, jv_copy(fn), jv_invalid(), jv_invalid(), + jv_copy(mode), jv_copy(in_opts), jv_copy(out_opts)); + } else { + ret = jv_invalid_with_msg(jv_string_fmt("fopen: Failed to open %s: %s", jv_string_value(fn), strerror(errno))); + } + +out: + jv_free(out_opts); + jv_free(in_opts); + jv_free(mode); + jv_free(fn); + return ret; +} + + +static jv builtin_jq_fhcmd(jq_state *jq, jv fh) { + struct io_handle *h = jq_handle_get(jq, fh); + + if (h && jv_is_valid(h->cmd)) + return jv_copy(h->cmd); + return jv_invalid_with_msg(jv_string("command for filehandle not known")); +} + +static jv builtin_jq_popen(jq_state *jq, jv input, jv cmd, jv mode, jv opts) { + jv_free(input); + + jv ret = jv_null(); + if (jv_get_kind(cmd) != JV_KIND_STRING) + ret = jv_invalid_with_msg(jv_string("popen: filename must be a string")); + if (jv_is_valid(ret) && jv_get_kind(mode) != JV_KIND_STRING) + ret = jv_invalid_with_msg(jv_string("popen: mode must be a string")); + + char type = 0; + if (jv_is_valid(ret)) { + type = jv_string_value(mode)[0]; + if (type != 'r' && type != 'w') + ret = jv_invalid_with_msg(jv_string("popen: mode must be \"r\" or \"w\"")); + } + if (type == 'r' && !jv_is_valid((opts = jv_parse_options(opts)))) + ret = jv_invalid_with_msg(jv_string("popen: invalid input options")); + else if (type == 'w' && !jv_is_valid((opts = jv_dump_options(opts)))) + ret = jv_invalid_with_msg(jv_string("popen: invalid output options")); + if (jv_is_valid(ret)) { + ret = allow_io(jq, "popen", + JV_OBJECT(jv_string("kind"), jv_string("popen"), + jv_string("name"), jv_copy(cmd), + jv_string("mode"), jv_copy(mode)), + cmd); + } + if (!jv_is_valid(ret)) + goto out; + + FILE *f = 0; + f = popen(jv_string_value(cmd), jv_string_value(mode)); + if (f) { + ret = make_f_handle(jq, f, jv_invalid(), jv_copy(cmd), jv_invalid(), + jv_copy(mode), + (type == 'r') ? jv_copy(opts) : jv_number(0), + (type == 'r') ? jv_copy(opts) : jv_number(0)); + } else { + ret = jv_invalid_with_msg(jv_string_fmt("popen: Failed to execute %s: %s", jv_string_value(cmd), strerror(errno))); + } + +out: + jv_free(opts); + jv_free(mode); + jv_free(cmd); + return ret; +} + +static jv builtin_jq_system(jq_state *jq, jv cmd) { + if (jv_get_kind(cmd) != JV_KIND_STRING) { + jv_free(cmd); + return jv_invalid_with_msg(jv_string("system: input must be a string")); + } + jv ret = allow_io(jq, "popen", + JV_OBJECT(jv_string("kind"), jv_string("system"), + jv_string("name"), jv_copy(cmd)), + cmd); + if (jv_is_valid(ret)) + ret = jv_number(system(jv_string_value(cmd))); + jv_free(cmd); + return ret; +} + +#ifdef WIN32 +typedef HANDLE jv_pid_t; +#else +typedef pid_t jv_pid_t; +#endif + +struct proc_handle { + jv_pid_t proc; + jv spawnspec; + char buf[4096 - (sizeof(jv_pid_t) + sizeof(jv))]; +}; + +static jv p_close(jq_state *jq, jv handle, void *d) { + struct proc_handle *h = d; + jv ret = jv_false(); + + if (!h) { + jv_free(handle); + return ret; + } +#ifdef WIN32 + WORD code; + if (h->proc != NULL && + (WaitForSingleObject(h->proc, INFINITE) == WAIT_OBJECT_0 || + GetExitCodeProcess(h->proc, &code) == 0)) + ret = jv_string("wait failed"); + else + ret = jv_number(code); +#else + int status; + if (h->proc != (pid_t)-1 && waitpid(h->proc, &status, 0) == -1) { + ret = jv_string_fmt("wait failed: %s", strerror(errno)); + } else { + if (WIFEXITED(status)) + ret = jv_number(WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + ret = jv_number(-WTERMSIG(status)); + else + ret = jv_number(0); // can't happen + } +#endif + jv_free(h->spawnspec); + jv_free(handle); + free(h); + return jv_is_valid(ret) ? ret : jv_number(0); +} + +static jv p_reset(jq_state *jq, jv handle, void *vh) { + //nothing to do... + jv_free(handle); + return jv_true(); +} + +/* Kill */ +static jv p_write(jq_state *jq, jv input, void *vh, jv sig) { + struct proc_handle *h = vh; + +#ifdef WIN32 + if (h->proc == NULL) + return jv_false(); + + if (jv_get_kind(sig) == JV_KIND_STRING) { + jv_free(sig); + sig = jv_number(1); + } +#else + if (h->proc == (pid_t)-1) + return jv_false(); + + if (jv_get_kind(sig) == JV_KIND_STRING) { + const char *s = jv_string_value(sig); + +#define sig1(name) \ + do { if (strcmp(s, #name) == 0) { jv_free(sig); sig = jv_number(name); goto gotone; } } while (0) + sig1(SIGHUP); + sig1(SIGINT); + sig1(SIGQUIT); + sig1(SIGILL); + sig1(SIGTRAP); +#ifdef SIGIOT + sig1(SIGIOT); +#endif + sig1(SIGBUS); + sig1(SIGFPE); + sig1(SIGKILL); + sig1(SIGUSR1); + sig1(SIGSEGV); + sig1(SIGUSR2); + sig1(SIGPIPE); + sig1(SIGALRM); + sig1(SIGTERM); +#ifdef SIGSTKFLT + sig1(SIGSTKFLT); +#endif + sig1(SIGCHLD); + sig1(SIGCONT); + sig1(SIGSTOP); + sig1(SIGTSTP); + sig1(SIGTTIN); + sig1(SIGTTOU); + sig1(SIGURG); +#ifdef SIGSTKFLT + sig1(SIGXCPU); +#endif +#ifdef SIGXFSZ + sig1(SIGXFSZ); +#endif +#ifdef SIGVTALRM + sig1(SIGVTALRM); +#endif +#ifdef SIGPROF + sig1(SIGPROF); +#endif +#ifdef SIGWINCH + sig1(SIGWINCH); +#endif +#ifdef SIGPOLL + sig1(SIGPOLL); +#endif +#ifdef SIGPWR + sig1(SIGPWR); +#endif +#ifdef SIGSYS + sig1(SIGSYS); +#endif + return jv_invalid_with_msg(jv_string("fhwrite: invalid signal")); + } +gotone: +#endif + + if (jv_get_kind(sig) != JV_KIND_NUMBER) { + jv_free(sig); + return jv_invalid_with_msg(jv_string("fhwrite: invalid signal")); + } +#ifdef WIN32 + if (TerminateProcess(h->proc, 1)) { + jv_free(sig); + return jv_true(); + } + jv_free(sig); + return jv_false(); +#else + if (kill(h->proc, jv_number_value(sig)) == 0) { + jv_free(sig); + return jv_true(); + } + jv_free(sig); + return jv_invalid_with_msg(jv_string_fmt("fhwrite: could not kill process: %s", strerror(errno))); +#endif +} + +static jv p_stat(jq_state *jq, jv input, void *vh) { + struct proc_handle *h = vh; + + if (!h) + return jv_invalid_with_msg(jv_string("invalid process handle")); + +#ifdef WIN32 + if (h->proc != NULL) + return jv_true(); +#else + int status; + if (h->proc == (pid_t)-1) + return jv_false(); + pid_t pid = waitpid(h->proc, &status, WNOHANG); + if (pid == 0) + return jv_true(); + if (pid == (pid_t)-1) + return jv_invalid_with_msg(jv_string_fmt("waitpid error: %s", strerror(errno))); + h->proc = (pid_t)-1; + if (WIFEXITED(status)) + return jv_number(WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + return jv_number(-WTERMSIG(status)); + return jv_number(0); // can't happen +#endif +} + +static jv p_read(jq_state *jq, jv input, void *vh) { + struct proc_handle *h = vh; + jv ret = jv_false(); + + if (!h) + return jv_invalid_with_msg(jv_string("invalid process handle")); + +#ifdef WIN32 + WORD code; + if (h->proc != NULL && + (WaitForSingleObject(h->proc, INFINITE) == WAIT_OBJECT_0 || + GetExitCodeProcess(h->proc, &code) == 0)) + ret = jv_invalid_with_msg(jv_string("wait failed")); + else + ret = jv_number(code); + h->proc = NULL; +#else + int status; + if (h->proc != (pid_t)-1 && waitpid(h->proc, &status, 0) == -1) { + ret = jv_invalid_with_msg(jv_string_fmt("wait failed: %s", strerror(errno))); + } else { + if (WIFEXITED(status)) + ret = jv_number(WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + ret = jv_number(-WTERMSIG(status)); + else + ret = jv_number(0); // can't happen + } + h->proc = (pid_t)-1; +#endif + + return ret; +} + +static jv p_eof(jq_state *jq, jv input, void *vh) { + return jv_invalid_with_msg(jv_string("Reading a process handle is currently not supported")); +} + +struct jq_io_table p_iovt = { + .kind = "PROCESS", + .fhclose = p_close, + .fhreset = p_reset, + .fhwrite = p_write, + .fhread = p_read, + .fhstat = p_stat, + .fheof = p_eof, +}; + +static jv make_p_handle(jq_state *jq, jv_pid_t proc, jv spawnspec) { + struct proc_handle *h = jv_mem_alloc(sizeof(*h)); + h->proc = proc; + h->spawnspec = spawnspec; + return jq_handle_new(jq, "PROCESS", &p_iovt, h); +} + +static int jv2fd(jv f) { + int fd = -1; + + if (jv_get_kind(f) == JV_KIND_NUMBER) { + fd = jv_number_value(f); + } else if (jv_get_kind(f) == JV_KIND_STRING) { + const char *s = jv_string_value(f); + + if (strcmp(s, "stdin") == 0) fd = STDIN_FILENO; + else if (strcmp(s, "stdout") == 0) fd = STDOUT_FILENO; + else if (strcmp(s, "stderr") == 0) fd = STDERR_FILENO; + } + return fd; +} + +/* XXX Maybe this should be in src/util.c and be called from jq_spawn_process()... */ +static jv allow_spawn(jq_state *jq, jv file, jv file_actions, jv argv) { + jv ret = jv_true(); + + if (jv_get_kind(file_actions) == JV_KIND_ARRAY) { + jv_array_foreach(file_actions, i, action) { + if (jv_get_kind(action) != JV_KIND_OBJECT) { + jv_free(action); + continue; + } + int fd = jv2fd(jv_object_get(jv_copy(action), jv_string("f"))); + jv target = jv_object_get(action, jv_string("target")); + if (jv_get_kind(target) != JV_KIND_STRING || fd < 0) { + jv_free(target); + continue; + } + ret = allow_io(jq, "file", + JV_OBJECT(jv_string("kind"), jv_string("file"), + jv_string("name"), jv_copy(target)), + jv_copy(target)); + jv_free(target); + break; + } + } + if (jv_is_valid(ret)) { + ret = allow_io(jq, "spawn", + JV_OBJECT(jv_string("kind"), jv_string("spawn"), + jv_string("name"), jv_copy(file), + jv_string("argv"), jv_copy(argv), + jv_string("file_actions"), jv_copy(file_actions)), + jv_copy(file)); + } + jv_free(file_actions); + jv_free(file); + jv_free(argv); + return ret; +} + +static jv builtin_jq_spawn(jq_state *jq, jv input) { + jv file = jv_array_get(jv_copy(input), 0); + jv file_actions = jv_array_get(jv_copy(input), 1); + jv attrs = jv_array_get(jv_copy(input), 2); + jv argv = jv_array_get(jv_copy(input), 3); + jv env = jv_array_get(jv_copy(input), 4); + jv inopts = jv_parse_options(jv_array_get(jv_copy(input), 5)); + jv outopts = jv_parse_options(jv_array_get(jv_copy(input), 6)); + jv spawnspec = input; + jv res = jq_spawn_process(jq, file, file_actions, attrs, argv, env); + if (!jv_is_valid(res)) { + jv_free(spawnspec); + return res; + } + +#ifdef WIN32 +#error "implement this" +#else + jv pid = jv_object_get(jv_copy(res), jv_string("pid")); + jv handle = make_p_handle(jq, jv_number_value(pid), jv_copy(spawnspec)); + jv_free(pid); + res = jv_object_set(res, jv_string("proc_handle"), handle); +#endif + + FILE *f = NULL; + int fd; + jv junk; + jv v; + + if (jv_is_valid((v = jv_object_get(jv_copy(res), jv_string("stdin"))))) { + fd = jv_number_value((junk = jv_array_get(jv_object_get(jv_copy(res), jv_string("stdin")), 1))); + jv_free(junk); + if ((f = fdopen(fd, "a")) == NULL) { + res = jv_object_set(res, jv_string("error"), + jv_string(strerror(errno))); + return res; + } + (void) close(jv_number_value((junk = jv_array_get(jv_object_get(jv_copy(res), jv_string("stdin")), 0)))); + jv_free(junk); + res = jv_object_set(res, jv_string("stdin_handle"), + make_f_handle(jq, f, jv_string(""), jv_invalid(), jv_copy(spawnspec), jv_string("a"), + inopts, outopts)); + } + + if (jv_is_valid((v = jv_object_get(jv_copy(res), jv_string("stdout"))))) { + fd = jv_number_value((junk = jv_array_get(jv_object_get(jv_copy(res), jv_string("stdout")), 0))); + jv_free(junk); + if ((f = fdopen(fd, "r")) == NULL) { + res = jv_object_set(res, jv_string("error"), + jv_string(strerror(errno))); + return res; + } + (void) close(jv_number_value((junk = jv_array_get(jv_object_get(jv_copy(res), jv_string("stdout")), 1)))); + jv_free(junk); + res = jv_object_set(res, jv_string("stdout_handle"), + make_f_handle(jq, f, jv_string(""), jv_invalid(), jv_copy(spawnspec), jv_string("r"), + inopts, outopts)); + } + + if (jv_is_valid((v = jv_object_get(jv_copy(res), jv_string("stderr"))))) { + fd = jv_number_value(jv_array_get(jv_object_get(jv_copy(res), jv_string("stderr")), 0)); + jv_free(junk); + if ((f = fdopen(fd, "r")) == NULL) { + res = jv_object_set(res, jv_string("error"), + jv_string(strerror(errno))); + return res; + } + (void) close(jv_number_value((junk = jv_array_get(jv_object_get(jv_copy(res), jv_string("stderr")), 1)))); + jv_free(junk); + res = jv_object_set(res, jv_string("stderr_handle"), + make_f_handle(jq, f, jv_string(""), jv_invalid(), jv_copy(spawnspec), jv_string("r"), + inopts, outopts)); + } + + return res; +} + +JQ_BUILTIN_INIT_FUN(builtin_jq_io_init, + "def fopen($fn; $mode; $inopts; $outopts): \n" + " _fopen($fn; $mode; $inopts; $outopts)\n" + " | . as $fh | unwind($fh|fhclose?);\n" + "def fopen($fn; $mode): fopen($fn; $mode; null; null);\n" + "def fopen($fn): fopen($fn; \"r\");\n" + "def fopen: fopen(.; \"r\");\n" + "def streamfile($fn; $opts):\n" + " label $out |\n" + " fopen($fn; \"r\"; $opts; null)|\n" + " repeat(try fhread catch if .==\"EOF\" then break $out else error end);\n" + "def streamfile: streamfile(.; null);\n" + "def slurpfile($fn; $opts): [streamfile($fn; $opts)];\n" + "def slurpfile: [streamfile];\n" + "def appendfile($fn; $opts; contents):\n" + " fhwrite(fopen($fn; \"a\"; null; $opts); contents);\n" + "def appendfile(contents): appendfile(.; null; contents);\n" + "def writefile($fn; $opts; contents):\n" + " fhwrite(fopen($fn; \"w\"; null; $opts); contents);\n" + "def writefile(contents): writefile(.; null; contents);\n", + { + .fptr = (cfunction_ptr)builtin_jq_fopen, + .name = "_fopen", + .nargs = 5, + .pure = 0, + .exported = 0 + }, + { + .fptr = (cfunction_ptr)builtin_jq_fhname, + .name = "_fhname", + .nargs = 1, + .pure = 0, + .exported = 1 + }, + ) + +JQ_BUILTIN_INIT_FUN(builtin_jq_spawn_init, + /* + * XXX What about non-stdio handles? + * + * XXX Add a spawn attribute for "kill/wait on unwind"? Or + * let the app do it? + * + * Anyways, programs that spawn w/o stdout/stderr pipes should + * read from the process handle, while ones that do should + * read from the stdout/stderr handles until EOF, then from + * the process handle. (Note the lack of non-blocking I/O in + * the whole system.) + * + * XXX Make sure to fetch posix_spawn attributes like pgroup + * IDs so that one could build a shell out of jq that spawns + * one process to get a pgroup ID then spawns others in a + * pipeline in the same pgroup. + * + * With all this one could write a Unix shell in jq! A toy + * shell, naturally, unless we add some functionality to + * support job control, ttys, etc. Still, no async I/O + * needed, mostly. For async I/O we will need to ditch stdio. + * Stdio is a handy crutch, but a crutch nonetheless. + * + * For async I/O we'll need jq varargs, too, as we'll need to + * be able to use that as a proxy for first-class function + * values (which jq will never have). + */ + "def _spawn:\n" + " __spawn\n" + " | . as $res\n" + " | unwind( $res\n" + " | ((.stdin_handle|fhclose?),\n" + " (.stdout_handle|fhclose?),\n" + " (.stderr_handle|fhclose?),\n" + " (.proc_handle|fhclose?)));\n" + "def spawn(f; actions; attrs; argv; env; inopts; outopts):\n" + " [f, actions, attrs, argv, env, inopts, outopts]|_spawn;\n" + "def spawn(f; actions; attrs; argv; env):\n" + " [f, actions, attrs, argv, env]|_spawn;\n" + "def spawn: if type==\"string\" then [.,[],[],[.],null]|_spawn\n" + " else [.[0],[],[],.,null]|_spawn end;\n", + { + .fptr = (cfunction_ptr)builtin_jq_spawn, + .name = "__spawn", + .nargs = 1, + .pure = 0, + .exported = 0 + }, + ) + +JQ_BUILTIN_INIT_FUN(builtin_jq_proc_init, + "def popen($fn; $mode; $opts): \n" + " _popen($fn; $mode; $opts)\n" + " | . as $fh | unwind($fh|fhclose?);\n" + "def popen($fn; $mode): popen($fn; $mode; null);\n" + "def popen($fn): popen($fn; \"r\");\n" + "def popen: popen(.; \"r\");\n" + "def streamcmd($fn; $opts):\n" + " label $out |\n" + " popen($fn; \"r\"; $opts)|\n" + " repeat(try fhread catch if .==\"EOF\" then break $out else error end);\n" + "def streamcmd: streamcmd(.; null);\n" + "def slurpcmd($fn; $opts): [streamcmd($fn; $opts)];\n" + "def slurpcmd: [streamcmd];\n" + "def writecmd($fn; $opts; contents):\n" + " fhwrite(popen($fn; \"w\"; $opts); contents);\n" + "def writecmd(contents): writecmd(.; null; contents);\n", + { + .fptr = (cfunction_ptr)builtin_jq_popen, + .name = "_popen", + .nargs = 4, + .pure = 0, + .exported = 0 + }, + { + .fptr = (cfunction_ptr)builtin_jq_system, + .name = "system", + .nargs = 1, + .pure = 0, + .exported = 1 + }, + { + .fptr = (cfunction_ptr)builtin_jq_fhcmd, + .name = "_fhcmd", + .nargs = 1, + .pure = 0, + .exported = 1 + }, + ) + +/* Builtin module "files" */ +static struct jq_builtin_module builtin_modules[] = { + { + .name = "jq" JQ_PATH_SEP "io.jq", + .contents = "module {cfunctions:\"io\"};", + .init = 0, + }, + { + .name = "jq" JQ_PATH_SEP "io" JQ_DLL_EXT, + .contents = 0, + .init = builtin_jq_io_init, + }, + { + .name = "jq" JQ_PATH_SEP "spawn.jq", + .contents = "module {cfunctions:\"spawn\"};", + .init = 0, + }, + { + .name = "jq" JQ_PATH_SEP "spawn" JQ_DLL_EXT, + .contents = 0, + .init = builtin_jq_spawn_init, + }, + { + .name = "jq" JQ_PATH_SEP "proc.jq", + .contents = "module {cfunctions:\"proc\"};", + .init = 0, + }, + { + .name = "jq" JQ_PATH_SEP "proc" JQ_DLL_EXT, + .contents = 0, + .init = builtin_jq_proc_init, + }, +}; + +struct jq_builtin_module *jq_builtin_modules = builtin_modules; +size_t jq_builtin_nmodules = sizeof(builtin_modules) / sizeof(builtin_modules[0]); diff --git a/src/builtin_modules.h b/src/builtin_modules.h new file mode 100644 index 0000000000..ba3db9f6a9 --- /dev/null +++ b/src/builtin_modules.h @@ -0,0 +1,26 @@ +#ifndef JQ_BUILTIN_MODULES +#define JQ_BUILTIN_MODULES + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jv.h" +#include "jq.h" + +/* Builtin module "files" */ +struct jq_builtin_module { + const char *name; + const char *contents; + jq_plugin_init_f init; +}; +extern struct jq_builtin_module *jq_builtin_modules; +extern size_t jq_builtin_nmodules; + +#endif /* JQ_BUILTIN_MODULES */ diff --git a/src/bytecode.c b/src/bytecode.c index 0ef154b826..1013332a12 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -6,7 +6,9 @@ #include "jv_alloc.h" // flags, length +#define MARKER 0, 0 #define NONE 0, 1 +#define BACKTRACKING OP_BACKTRACKS, 1 #define CONSTANT OP_HAS_CONSTANT, 2 #define VARIABLE (OP_HAS_VARIABLE | OP_HAS_BINDING), 3 #define GLOBAL (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING | OP_IS_CALL_PSEUDO), 4 diff --git a/src/bytecode.h b/src/bytecode.h index 6cb49f7ab0..44e21e6baa 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -3,8 +3,10 @@ #include #include "jv.h" +#include "jq.h" +#include "jq_plugin.h" -typedef enum { +typedef enum opcode { #define OP(name, imm, in, out) name, #include "opcode_list.h" #undef OP @@ -17,14 +19,15 @@ enum { #undef OP }; -enum { - OP_HAS_CONSTANT = 2, - OP_HAS_VARIABLE = 4, - OP_HAS_BRANCH = 8, - OP_HAS_CFUNC = 32, - OP_HAS_UFUNC = 64, - OP_IS_CALL_PSEUDO = 128, - OP_HAS_BINDING = 1024, +enum op_flag { + OP_HAS_CONSTANT = 1 << 1, + OP_HAS_VARIABLE = 1 << 2, + OP_HAS_BRANCH = 1 << 3, + OP_HAS_CFUNC = 1 << 4, + OP_HAS_UFUNC = 1 << 5, + OP_IS_CALL_PSEUDO = 1 << 6, + OP_HAS_BINDING = 1 << 7, + OP_BACKTRACKS = 1 << 8, // NOTE: Not actually part of any op -- a pseudo-op flag for special // handling of `break`. OP_BIND_WILDCARD = 2048, @@ -43,15 +46,6 @@ struct opcode_description { const struct opcode_description* opcode_describe(opcode op); - -#define MAX_CFUNCTION_ARGS 10 -typedef void (*cfunction_ptr)(); -struct cfunction { - cfunction_ptr fptr; - const char* name; - int nargs; -}; - struct symbol_table { struct cfunction* cfunctions; int ncfunctions; diff --git a/src/compile.c b/src/compile.c index 05478ab8e8..748eb0c61b 100644 --- a/src/compile.c +++ b/src/compile.c @@ -66,6 +66,18 @@ struct inst { struct bytecode* compiled; int bytecode_pos; // position just after this insn + unsigned int hidden:1; + + // if this instruction is copied, + // the info about the copy is saved here + // this allows for post processing to rebind targets or such + // the context is used as versioning to identify + // instructions which were copied whithin a particular context + // POLICY: assign (don't free either target or dest!) + struct { + void* context; + inst* dest; + } copy; }; static inst* inst_new(opcode op) { @@ -83,6 +95,9 @@ static inst* inst_new(opcode op) { i->arglist = gen_noop(); i->source = UNKNOWN_LOCATION; i->locfile = 0; + i->hidden = 0; + i->copy.context = 0; + i->copy.dest = 0; return i; } @@ -98,6 +113,51 @@ static void inst_free(struct inst* i) { jv_mem_free(i); } +static block block_copy(block b, void* copy_context); + +static inst* inst_copy_to(struct inst* o, struct inst* i, void* copy_context) { + memcpy(o, i, sizeof(inst)); + + if (opcode_describe(i->op)->flags & OP_HAS_CONSTANT) { + o->imm.constant = jv_copy(i->imm.constant); + } + if(i->locfile) { + o->locfile = locfile_retain(i->locfile); + } + o->arglist = block_copy(i->arglist, copy_context); + o->subfn = block_copy(i->subfn, copy_context); + o->symbol = i->symbol ? jv_mem_strdup(i->symbol) : 0; + + // thank me later :) + i->copy.context = copy_context; + i->copy.dest = o; + + return o; +} + +static block block_copy(block b, void * copy_context) { + block bo = {0,0}; + struct inst *lasto = 0; + // this covers the case when block has last instruction with a non-zero next element + for (struct inst * i = b.first; i && (i->prev != b.last); i = i->next) { + struct inst * o = jv_mem_alloc(sizeof(inst)); + inst_copy_to(o, i, copy_context); + o->prev = lasto; + if(lasto) { + lasto->next = o; + } else { + bo.first = o; + bo.first->prev = 0; + } + lasto = o; + } + if(lasto) { + lasto->next = 0; + } + bo.last = lasto; + return bo; +} + static block inst_block(inst* i) { block b = {i,i}; return b; @@ -121,6 +181,18 @@ static inst* block_take(block* b) { return i; } +block block_take_block(block *b) { + return inst_block(block_take(b)); +} + +block block_hide(block b) { + for (inst* i = b.first; i; i = i->next) { + if (i->op == CLOSURE_CREATE_C && !i->imm.cfunc->exported) + i->hidden = 1; + } + return b; +} + block gen_location(location loc, struct locfile* l, block b) { for (inst* i = b.first; i; i = i->next) { if (i->source.start == UNKNOWN_LOCATION.start && @@ -141,6 +213,11 @@ int block_is_noop(block b) { return (b.first == 0 && b.last == 0); } +block gen_marker(opcode op) { + assert(opcode_describe(op)->length == 0); + return inst_block(inst_new(op)); +} + block gen_op_simple(opcode op) { assert(opcode_describe(op)->length == 1); return inst_block(inst_new(op)); @@ -321,6 +398,7 @@ static int block_bind_subblock_inner(int* any_unbound, block binder, block body, int flags = opcode_describe(i->op)->flags; if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by == 0 && + !binder.first->hidden && (!strcmp(i->symbol, binder.first->symbol) || // Check for break/break2/break3; see parser.y ((bindflags & OP_BIND_WILDCARD) && i->symbol[0] == '*' && @@ -420,6 +498,104 @@ static inst* block_take_last(block* b) { return i; } +void block_inline(block inlines, block body) { + + inst *i; + inst *b; + + for (i = inlines.first; i && body.first; i = i->next) { + for (b = body.first; b; b = b->next) { + if (b->op == CALL_JQ && !b->bound_by && strcmp(b->symbol, i->symbol) == 0 && + b->nactuals == i->nformals) { + + void* ctx = (void*)random(); + + // save the call's arglist for the mapping below + block call_arglist = b->arglist; + // save the prev and next + inst* prev = b->prev; + inst* next = b->next; + + // first, copy all instructions but the last one + // in case it's a single instruction block then just noop + block subfun_no_last = { 0, 0 }; + if (!block_is_single(i->subfn)){ + subfun_no_last.first = i->subfn.first; + subfun_no_last.last = i->subfn.last->prev; + } + block copy = block_copy(subfun_no_last, ctx); + + // now, reuse the current call instruction + // as the holder for the last instruction in the new inlined body + // this handles the case if any other instruction in the code + // had this call as the branch target. + // searching for such instruction would mean + // that we needed to scan full code (every time) and we don't want it + inst_copy_to(b, i->subfn.last, ctx); + b->prev = 0; // for a valid inst block + block_append(©, inst_block(b)); + + // now, do the parameter mapping and target remapping + // CALL_JQ already has all its arguments prepared and wrapped in + // CLOSURE_CREATE or like, so all we need to do + // is to find instructions of the inlined function bound by params + // and rebind them to the corresponding args from the arglist + + for(inst* ii = copy.first; ii; ii = ii->next) { + if (opcode_describe(ii->op)->flags & OP_HAS_BRANCH) { + assert(ii->imm.target && "branching instruction without a target"); + // in case the instruction had a branch to one of the other + // copied instructions, we need to remap it + if (ii->imm.target->copy.context == ctx) { + // context matches, means we've just copied it + // just remap it to the copy dest + ii->imm.target = ii->imm.target->copy.dest; + } + } + + if (ii->bound_by && ii->bound_by->op == CLOSURE_PARAM) { + // find the matching param and the corresponding argument + int index = 0; + inst *arg = call_arglist.first; + inst *par = i->arglist.first; + while(index < i->nformals && par != ii->bound_by && par && arg) { + par = par->next; + arg = arg->next; + index ++; + } + assert(index < i->nformals && par && arg && "couldn't identify matching param"); + + // the magic happens here + ii->bound_by = arg; + } + } + + // now, copy the arglist from the CALL_JQ instruction + // to have the subfunctions stay + copy = block_join(call_arglist, copy); + + // inject the inlined code + // instead of the call instruction + copy.first->prev = prev; + copy.last->next = next; + + if(prev) { + prev->next = copy.first; + } + + // we've reused the call instruction as the last one + // so the next is already pointing to the correct inst. + + // we've reused the call instruction + // so no need to free anything + } else { + block_inline(inlines, b->arglist); + block_inline(inlines, b->subfn); + } + } + } +} + // Binds a sequence of binders, which *must not* alrady be bound to each other, // to body, throwing away unreferenced defs block block_bind_referenced(block binder, block body, int bindflags) { @@ -557,6 +733,11 @@ block gen_function(const char* name, block formals, block body) { if (i->op == CLOSURE_PARAM_REGULAR) { i->op = CLOSURE_PARAM; body = gen_var_binding(gen_call(i->symbol, gen_noop()), i->symbol, body); + } else if (i->op == CLOSURE_PARAM_COEXPR) { + i->op = CLOSURE_PARAM; + block coexp = gen_function(i->symbol, gen_noop(), BLOCK(gen_op_unbound(LOADV,i->symbol), gen_call("fhread", gen_noop()))); + block_bind_subblock(coexp, body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); + body = gen_var_binding(gen_call("coexp", gen_lambda(gen_call(i->symbol, gen_noop()))), i->symbol, BLOCK(coexp, body)); } block_bind_subblock(inst_block(i), body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); } @@ -570,6 +751,10 @@ block gen_function(const char* name, block formals, block body) { return b; } +block gen_param_coexpr(const char* name) { + return gen_op_unbound(CLOSURE_PARAM_COEXPR, name); +} + block gen_param_regular(const char* name) { return gen_op_unbound(CLOSURE_PARAM_REGULAR, name); } @@ -889,6 +1074,14 @@ block gen_foreach(block source, block matcher, block init, block update, block e return foreach; } +block gen_coexpression_with_param_name(const char* param) { + block cobody = BLOCK(gen_op_simple(START), + gen_call(param, gen_noop()), + gen_op_simple(TAIL_OUT)); + block cocreate = gen_op_target(COCREATE, cobody); + return BLOCK(cocreate, cobody); +} + block gen_definedor(block a, block b) { // var found := false block found_var = gen_op_var_fresh(STOREV, "found"); @@ -1033,43 +1226,40 @@ block gen_cond(block cond, block iftrue, block iffalse) { BLOCK(gen_op_simple(POP), iffalse))); } -block gen_try_handler(block handler) { - // Quite a pain just to hide jq's internal errors. - return gen_cond(// `if type=="object" and .__jq - gen_and(gen_call("_equal", - BLOCK(gen_lambda(gen_const(jv_string("object"))), - gen_lambda(gen_call("type", gen_noop())))), - BLOCK(gen_subexp(gen_const(jv_string("__jq"))), - gen_noop(), - gen_op_simple(INDEX))), - // `then error` - gen_call("error", gen_noop()), - // `else HANDLER end` - handler); -} - block gen_try(block exp, block handler) { /* - * Produce something like: - * FORK_OPT
+ * Produce: + * + * TRY_BEGIN handler * - * JUMP - * + * TRY_END + * JUMP past_handler + * handler: + * past_handler: * - * If this is not an internal try/catch, then catch and re-raise - * internal errors to prevent them from leaking. + * If backtracks then TRY_BEGIN will backtrack. * - * The handler will only execute if we backtrack to the FORK_OPT with - * an error (exception). If produces no value then FORK_OPT - * will backtrack (propagate the `empty`, as it were. If - * produces a value then we'll execute whatever bytecode follows this - * sequence. + * If produces a value then we'll execute whatever bytecode follows + * this sequence. If that code raises an exception, then TRY_END will wrap + * and re-raise that exception, and TRY_BEGIN will unwrap and re-raise the + * exception (see jq_next()). + * + * If raises then the TRY_BEGIN will see a non-wrapped exception and + * will jump to the handler (note the TRY_END will not execute in this case), + * and if the handler produces any values, then we'll execute whatever + * bytecode follows this sequence. Note that TRY_END will not execute in + * this case, so if the handler raises an exception, or code past the handler + * raises an exception, then that exception won't be wrapped and re-raised, + * and the TRY_BEGIN will not catch it because it does not stack_save() when + * it branches to the handler. */ - if (!handler.first && !handler.last) - // A hack to deal with `.` as the handler; we could use a real NOOP here - handler = BLOCK(gen_op_simple(DUP), gen_op_simple(POP), handler); - exp = BLOCK(exp, gen_op_target(JUMP, handler)); - return BLOCK(gen_op_target(FORK_OPT, exp), exp, handler); + + if (block_is_noop(handler)) + handler = BLOCK(gen_op_simple(DUP), gen_op_simple(POP)); + + block jump = gen_op_target(JUMP, handler); + return BLOCK(gen_op_target(TRY_BEGIN, jump), exp, gen_op_simple(TRY_END), + jump, handler); } block gen_label(const char *label, block exp) { @@ -1124,7 +1314,12 @@ static int count_cfunctions(block b) { } #ifndef WIN32 -extern char **environ; +# ifdef __APPLE__ +# include +# define environ (*_NSGetEnviron()) +# else + extern char ** environ; +# endif #endif static jv @@ -1243,10 +1438,14 @@ static int compile(struct bytecode* bc, block b, struct locfile* lf, jv args, jv int var_frame_idx = 0; bc->nsubfunctions = 0; errors += expand_call_arglist(&b, args, env); - b = BLOCK(b, gen_op_simple(RET)); + int has_start = 0; + jv localnames = jv_array(); for (inst* curr = b.first; curr; curr = curr->next) { if (!curr->next) assert(curr == b.last); + + has_start = has_start || (curr->op == START); + int length = opcode_describe(curr->op)->length; if (curr->op == CALL_JQ) { for (inst* arg = curr->arglist.first; arg; arg = arg->next) { @@ -1278,6 +1477,14 @@ static int compile(struct bytecode* bc, block b, struct locfile* lf, jv args, jv curr->imm.intval = idx; } } + + // block needs a RET_JQ unless it is the main block + if (!b.last || !has_start) { + b = BLOCK(b, gen_op_simple(RET_JQ)); + b.last->bytecode_pos = ++pos; + b.last->compiled = bc; + } + if (pos > 0xFFFF) { // too long for program counter to fit in uint16_t locfile_locate(lf, UNKNOWN_LOCATION, diff --git a/src/compile.h b/src/compile.h index f9e8cd5514..9b35cadc8b 100644 --- a/src/compile.h +++ b/src/compile.h @@ -18,6 +18,7 @@ block gen_location(location, struct locfile*, block); block gen_noop(); int block_is_noop(block b); +block gen_marker(opcode op); block gen_op_simple(opcode op); block gen_const(jv constant); block gen_const_global(jv constant, const char *name); @@ -37,6 +38,7 @@ block gen_import(const char* name, const char *as, int is_data); block gen_import_meta(block import, block metadata); block gen_function(const char* name, block formals, block body); block gen_param_regular(const char* name); +block gen_param_coexpr(const char* name); block gen_param(const char* name); block gen_lambda(block body); block gen_call(const char* name, block body); @@ -57,14 +59,15 @@ block gen_array_matcher(block left, block curr); block gen_object_matcher(block name, block curr); block gen_destructure(block var, block matcher, block body); block gen_destructure_alt(block matcher); +block gen_coexpression_with_param_name(const char* param); block gen_cond(block cond, block iftrue, block iffalse); -block gen_try_handler(block handler); block gen_try(block exp, block handler); block gen_label(const char *label, block exp); block gen_cbinding(const struct cfunction* functions, int nfunctions, block b); +block block_take_block(block *); void block_append(block* b, block b2); block block_join(block a, block b); int block_has_only_binders_and_imports(block, int bindflags); @@ -76,6 +79,8 @@ block block_bind_library(block binder, block body, int bindflags, const char* li block block_bind_referenced(block binder, block body, int bindflags); block block_bind_self(block binder, int bindflags); block block_drop_unreferenced(block body); +block block_hide(block body); +void block_inline(block inlines, block body); jv block_take_imports(block* body); jv block_list_funcs(block body, int omit_underscores); diff --git a/src/exec_stack.h b/src/exec_stack.h index 57e136507d..604cc0e0ab 100644 --- a/src/exec_stack.h +++ b/src/exec_stack.h @@ -20,6 +20,18 @@ * stack. The stack pointer of the "next" block is stored directly below each * block. * + * On the stack itself we only ever store pointers into the stack encoded this + * way. Pointers to heap objects are not encoded in any way, and mostly are + * only pushed on the stack as part of jv values. + * + * Because stack pointers on the stack itself are encoded as relative to the + * top of the stack, we can reallocate, copy, move a stack without having to + * rewrite pointers written in the stack. For co-routines, as long as neither + * parent nor child co-routines backtracks past the point at which the child + * was cloned without halting the child (or the child halting first), all the + * jv values on the stack before the clone operation will be safe to use by + * both, parent and child. + * * <- mem_end = 0x100 * 0xF8 +------------+ * 0xF0 | | @@ -59,8 +71,12 @@ static void stack_init(struct stack* s) { s->limit = 0; } -static void stack_reset(struct stack* s) { - assert(s->limit == 0 && "stack freed while not empty"); +static void stack_reset(struct stack* s, stack_ptr upto) { + if (upto) { + assert(s->limit == upto && "stack freed while not empty"); + } else { + assert(s->limit == 0 && "stack freed while not empty"); + } char* mem_start = s->mem_end - ( -s->bound + ALIGNMENT); free(mem_start); stack_init(s); @@ -70,6 +86,7 @@ static int stack_pop_will_free(struct stack* s, stack_ptr p) { return p == s->limit; } +/* Dereference an encoded stack pointer */ static void* stack_block(struct stack* s, stack_ptr p) { return (void*)(s->mem_end + p); } @@ -90,6 +107,21 @@ static void stack_reallocate(struct stack* s, size_t sz) { s->bound = -(new_mem_length - ALIGNMENT); } +static void stack_copy(struct stack* d, struct stack* s) { + char* src_mem_start = s->mem_end - ( -s->bound + ALIGNMENT); + int src_mem_length = s->mem_end - src_mem_start; + + if (src_mem_length == 0) { + stack_init(d); + } else { + char* dst_mem_start = jv_mem_alloc(src_mem_length); + memcpy(dst_mem_start, src_mem_start, src_mem_length); + d->mem_end = dst_mem_start + src_mem_length; + d->bound = s->bound; + d->limit = s->limit; + } +} + static stack_ptr stack_push_block(struct stack* s, stack_ptr p, size_t sz) { int alloc_sz = align_round_up(sz) + ALIGNMENT; stack_ptr r = s->limit - alloc_sz; diff --git a/src/execute.c b/src/execute.c index fd2ab2c7be..1e0e3f54c3 100644 --- a/src/execute.c +++ b/src/execute.c @@ -1,11 +1,21 @@ #include #include +#include #include #include #include #include #include +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#endif + #include "exec_stack.h" #include "bytecode.h" @@ -14,15 +24,32 @@ #include "locfile.h" #include "jv.h" #include "jq.h" +#include "jq_plugin.h" #include "parser.h" #include "builtin.h" #include "util.h" #include "linker.h" +struct jq_plugin_vtable vtable; + +struct raw_handle { + struct jq_io_table *vt; + void *handle; + int refcnt; +}; + +struct jq_handles { + jv jhandles; + struct raw_handle **handles; + size_t nhandles; +}; + struct jq_state { + struct jq_plugin_vtable *vtable; /* Must be first! */ void (*nomem_handler)(void *); void *nomem_handler_data; struct bytecode* bc; + struct lib_loading_state *libs; jq_msg_cb err_cb; void *err_cb_data; @@ -40,15 +67,56 @@ struct jq_state { int initial_execution; unsigned next_label; - int halted; + unsigned int halted; + unsigned int finished; jv exit_code; jv error_message; + jv vmid; + jv rnd; jv attrs; jq_input_cb input_cb; void *input_cb_data; jq_msg_cb debug_cb; void *debug_cb_data; + + /* + * backward compatible start input + * instead of storing it on the stack + */ + jv start_input; + + /* + * I/O and co-routine handles (futures). + * + * Once we have co-routines we'll have a single handle namespace + * for all co-routines in a family. To avoid an extra allocation + * in jq_init(), we'll have a struct jq_handles and a pointer to it + * or an ancestor co-routine's jq_state's handles. + */ + struct jq_handles handles_s; + struct jq_handles *handles; + + /* + * Co-routines + * + * - parent points to the parent jq_state + * - restore_limit is the point past which the stack is shared with + * the parent, thus the child is not to unwind further than this + * point and the parent must teardown the child before unwinding + * past point + * - start_limit is the point to unwind to in order to reset a child + * co-routine so it can be restarted + */ + struct jq_state* parent; + stack_ptr restore_limit; + uint16_t* start_pc; + + /* + * I/O policy + */ + struct jq_state* io_policy; + jv io_policy_data; }; struct closure { @@ -66,7 +134,7 @@ union frame_entry { struct frame { struct bytecode* bc; // jq bytecode for callee stack_ptr env; // jq stack address of frame to return to - stack_ptr retdata; // jq stack address to unwind to on RET + stack_ptr retdata; // jq stack address to unwind to on RET_JQ uint16_t* retaddr; // jq bytecode return address union frame_entry entries[]; // nclosures + nlocals }; @@ -246,6 +314,15 @@ static void path_append(jq_state* jq, jv component, jv value_at_path) { } } +static void copy_callbacks(jq_state *src, jq_state *dst) { + dst->err_cb = src->err_cb; + dst->err_cb_data = src->err_cb_data; + dst->input_cb = src->input_cb; + dst->input_cb_data = src->input_cb_data; + dst->debug_cb = src->debug_cb; + dst->debug_cb_data = src->debug_cb_data; +} + /* For f_getpath() */ jv _jq_path_append(jq_state *jq, jv v, jv p, jv value_at_path) { @@ -269,7 +346,7 @@ _jq_path_append(jq_state *jq, jv v, jv p, jv value_at_path) { } uint16_t* stack_restore(jq_state *jq){ - while (!stack_pop_will_free(&jq->stk, jq->fork_top)) { + while (jq->stk.limit < jq->restore_limit && !stack_pop_will_free(&jq->stk, jq->fork_top)) { if (stack_pop_will_free(&jq->stk, jq->stk_top)) { jv_free(stack_pop(jq)); } else if (stack_pop_will_free(&jq->stk, jq->curr_frame)) { @@ -279,7 +356,7 @@ uint16_t* stack_restore(jq_state *jq){ } } - if (jq->fork_top == 0) { + if (jq->fork_top == 0 || jq->stk.limit >= jq->restore_limit) { return 0; } @@ -304,16 +381,34 @@ uint16_t* stack_restore(jq_state *jq){ static void jq_reset(jq_state *jq) { while (stack_restore(jq)) {} - assert(jq->stk_top == 0); - assert(jq->fork_top == 0); - assert(jq->curr_frame == 0); - stack_reset(&jq->stk); + assert(jq->parent || jq->stk_top == 0); + assert(jq->parent || jq->fork_top == 0); + assert(jq->parent || jq->curr_frame == 0); + if (!jq->parent) + stack_reset(&jq->stk, 0); jv_free(jq->error); jq->error = jv_null(); - jq->halted = 0; + jq->finished = 0; jv_free(jq->exit_code); jv_free(jq->error_message); + jq->exit_code = jv_invalid(); + jq->error_message = jv_invalid(); + + if (jq->handles == &jq->handles_s) { + if (jv_is_valid(jq->handles->jhandles)) { + jv_array_foreach(jq->handles->jhandles, i, v) { + if (jv_is_valid(v) && i > -1 && (size_t)i < jq->handles->nhandles) + jv_free(jq_handle_close(jq, v)); + } + } + jv_free(jq->handles->jhandles); + free(jq->handles->handles); + jq->handles->handles = 0; + jq->handles->nhandles = 0; + jq->handles->jhandles = jv_array(); + } + if (jv_get_kind(jq->path) != JV_KIND_INVALID) jv_free(jq->path); jq->path = jv_null(); @@ -336,18 +431,37 @@ static void set_error(jq_state *jq, jv value) { #define ON_BACKTRACK(op) ((op)+NUM_OPCODES) +static jq_state *coinit(jq_state *, uint16_t*); +static void co_err_cb(void *, jv); + jv jq_next(jq_state *jq) { jv cfunc_input[MAX_CFUNCTION_ARGS]; jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); + if (jq->halted) { + if (jq->debug_trace_enabled) + printf("\t\n"); + return jv_invalid(); + } + + if (jq->finished) { + if (jq->debug_trace_enabled) + printf("\t\n"); + return jv_invalid(); + } + + int initial_execution = jq->initial_execution; + jq->initial_execution = 0; + uint16_t* pc = stack_restore(jq); assert(pc); int raising; - int backtracking = !jq->initial_execution; - jq->initial_execution = 0; + int backtracking = !initial_execution; + assert(jv_get_kind(jq->error) == JV_KIND_NULL); + assert(jq->parent == 0 || jq->restore_limit >= jq->stk.limit); while (1) { if (jq->halted) { if (jq->debug_trace_enabled) @@ -359,13 +473,14 @@ jv jq_next(jq_state *jq) { if (jq->debug_trace_enabled) { dump_operation(frame_current(jq)->bc, pc); - printf("\t"); const struct opcode_description* opdesc = opcode_describe(opcode); stack_ptr param = 0; if (!backtracking) { int stack_in = opdesc->stack_in; if (stack_in == -1) stack_in = pc[1]; param = jq->stk_top; + + printf("\t(( "); for (int i=0; ipath), 0); } - if (jq->debug_trace_enabled & JQ_DEBUG_TRACE_DETAIL) { + printf(" )) "); + + if (jq->debug_trace_enabled & JQ_DEBUG_TRACE_DETAIL && param < jq->restore_limit) { + int first = 1; + if(stack_in == 0) { + // we haven't printed the top of the stack yet, print now + jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT); + } while ((param = *stack_block_next(&jq->stk, param))) { - printf(" || "); + if (!first || !stack_in) { + printf(" || "); + } else { + first = 0; + } jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT); } } } else { - printf("\t"); + jv e = jv_copy(jq->error); + jv *pe = &e; + + if (jv_is_valid(e)) { + printf("\t"); + } else { + printf("\t "); + + while (pe && !jv_is_valid(*pe)) { + printf(" E:"); + if (jv_invalid_has_msg(jv_copy(*pe))) { + *pe = jv_invalid_get_msg(*pe); + } else { + jv_free(*pe); + pe = 0; + } + } + + if (pe) { + jv_dump(*pe, JV_PRINT_REFCOUNT); + } else { + printf("()"); + } + } + } + if (jq->parent) + printf("\t (CHILD %p of %p)", jq, jq->parent); + printf("\n"); } @@ -399,9 +552,6 @@ jv jq_next(jq_state *jq) { switch (opcode) { default: assert(0 && "invalid instruction"); - - case TOP: break; - case LOADK: { jv v = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); assert(jv_is_valid(v)); @@ -411,7 +561,12 @@ jv jq_next(jq_state *jq) { } case GENLABEL: { - stack_push(jq, JV_OBJECT(jv_string("__jq"), jv_number(jq->next_label++))); + if (!jv_is_valid(jq->rnd)) { + stack_push(jq, JV_OBJECT(jv_string("__jq"), jv_number(jq->next_label++))); + } else { + stack_push(jq, JV_OBJECT(jv_string("__jq"), jv_number(jq->next_label++), + jv_string("__jqv"), jv_copy((jq->rnd)))); + } break; } @@ -543,7 +698,7 @@ jv jq_next(jq_state *jq) { if (jq->debug_trace_enabled) { printf("V%d = ", v); jv_dump(jv_copy(*var), 0); - printf(" (%d)\n", jv_get_refcnt(*var)); + printf(" <%d>\n", jv_get_refcnt(*var)); } jv_free(stack_pop(jq)); stack_push(jq, jv_copy(*var)); @@ -567,7 +722,8 @@ jv jq_next(jq_state *jq) { } case STOREVN: - stack_save(jq, pc - 1, stack_get_pos(jq)); + stack_save(jq, pc - 1, stack_get_pos(jq)); + /* fallthru */ case STOREV: { uint16_t level = *pc++; uint16_t v = *pc++; @@ -576,7 +732,7 @@ jv jq_next(jq_state *jq) { if (jq->debug_trace_enabled) { printf("V%d = ", v); jv_dump(jv_copy(val), 0); - printf(" (%d)\n", jv_get_refcnt(val)); + printf(" <%d>\n", jv_get_refcnt(val)); } jv_free(*var); *var = val; @@ -714,6 +870,7 @@ jv jq_next(jq_state *jq) { } case EACH: + /* fallthru */ case EACH_OPT: { jv container = stack_pop(jq); // detect invalid path expression like path(reverse | .[]) @@ -727,8 +884,8 @@ jv jq_next(jq_state *jq) { } stack_push(jq, container); stack_push(jq, jv_number(-1)); - // fallthrough } + /* fallthru */ case ON_BACKTRACK(EACH): case ON_BACKTRACK(EACH_OPT): { int idx = jv_number_value(stack_pop(jq)); @@ -744,7 +901,7 @@ jv jq_next(jq_state *jq) { is_last = idx == len - 1; if (keep_going) { key = jv_number(idx); - value = jv_array_get(jv_copy(container), idx); + value = jv_array_get(jv_copy(container), jq->subexp_nest ? idx : len - (idx + 1)); } } else if (jv_get_kind(container) == JV_KIND_OBJECT) { if (opcode == EACH || opcode == EACH_OPT) idx = jv_object_iter(container); @@ -794,15 +951,69 @@ jv jq_next(jq_state *jq) { if (!jv_is_valid(jq->error)) { jv error = jq->error; jq->error = jv_null(); + jq->finished = 1; return error; } + jq->finished = 1; return jv_invalid(); } backtracking = 1; break; } - case FORK_OPT: + case TRY_BEGIN: + stack_save(jq, pc - 1, stack_get_pos(jq)); + pc++; // skip handler offset this time + break; + + case TRY_END: + stack_save(jq, pc - 1, stack_get_pos(jq)); + break; + + case ON_BACKTRACK(TRY_BEGIN): { + if (!raising) { + /* + * `try EXP ...` -- EXP backtracked (e.g., EXP was `empty`), so we + * backtrack more: + */ + jv_free(stack_pop(jq)); + goto do_backtrack; + } + + /* + * Else `(try EXP ... ) | EXP2` raised an error. + * + * If the error was wrapped in another error, then that means EXP2 raised + * the error. We unwrap it and re-raise it as it wasn't raised by EXP. + * + * See commentary in gen_try(). + */ + jv e = jv_invalid_get_msg(jv_copy(jq->error)); + if (!jv_is_valid(e) && jv_invalid_has_msg(jv_copy(e))) { + set_error(jq, e); + goto do_backtrack; + } + jv_free(e); + + /* + * Else we caught an error containing a non-error value, so we jump to + * the handler. + * + * See commentary in gen_try(). + */ + uint16_t offset = *pc++; + jv_free(stack_pop(jq)); // free the input + stack_push(jq, jv_invalid_get_msg(jq->error)); // push the error's message + jq->error = jv_null(); + pc += offset; + break; + } + case ON_BACKTRACK(TRY_END): + // Wrap the error so the matching TRY_BEGIN doesn't catch it + if (raising) + set_error(jq, jv_invalid_with_msg(jv_copy(jq->error))); + goto do_backtrack; + case DESTRUCTURE_ALT: case FORK: { stack_save(jq, pc - 1, stack_get_pos(jq)); @@ -810,7 +1021,6 @@ jv jq_next(jq_state *jq) { break; } - case ON_BACKTRACK(FORK_OPT): case ON_BACKTRACK(DESTRUCTURE_ALT): { if (jv_is_valid(jq->error)) { // `try EXP ...` backtracked here (no value, `empty`), so we backtrack more @@ -921,7 +1131,243 @@ jv jq_next(jq_state *jq) { break; } - case RET: { + case UNWINDING: { + jv_free(stack_pop(jq)); + stack_push(jq, jv_false()); + stack_save(jq, pc - 1, stack_get_pos(jq)); + break; + } + case ON_BACKTRACK(UNWINDING): { + jv done = stack_pop(jq); + /* + * done is false the first time we backtrack to an UNWINDING because the + * above case will have pushed false. + * + * In that case we'll go forth so we can run an unwind-protect handler. + * + * But first we'll push a value so that when the unwind-protect handler + * backtracks we then backtrack too. + */ + if (jv_get_kind(done) == JV_KIND_FALSE) { + if (!raising) { + /* + * We push true because when we backtrack here it will be because an + * unwind-protect handler is done and so we'll take the else brack if + * the if jv_get_kind(done) == JV_KIND_FALSE) above. + */ + stack_push(jq, jv_true()); + } else { + /* + * We'll push the error's message, and we wrap it in an array in case + * the message was a jv_true(). + */ + stack_push(jq, JV_ARRAY(jv_invalid_get_msg(jq->error))); + jq->error = jv_null(); + } + stack_save(jq, pc - 1, stack_get_pos(jq)); + } else { + /* + * We're done then. If done is an array, the one element will be an + * error message. + */ + if (jv_get_kind(done) == JV_KIND_ARRAY) + set_error(jq, jv_invalid_with_msg(jv_array_get(done, 0))); + goto do_backtrack; + } + break; + } + + case COCREATE: { + /* Create a child co-routine with the following code + * The child side will start happily at the next instruction + * + * + * coinit() makes a copy of the parent jq_state, but arranges for the + * child never to stack_restore() past this point. See jq_reset(). + * + * This all works because we never store pointers into the stack on the + * stack without first encoding them to be relative to the stack, and + * because the child cannot backtrack past this point, the parent will + * teardown the child if the parent backtracks past this point, and there + * is no concurrent access to the stack. + */ + jv input = stack_pop(jq); + + uint16_t body_len = *pc++; + + assert(*pc == START && "COCREATE must be followed by START"); + jq_state *child = coinit(jq, pc); + jq_start(child, input, jq->debug_trace_enabled ? JQ_DEBUG_TRACE_ALL : 0); + + // jump over the cobody + pc += body_len; + + // and return its handle + extern struct jq_io_table jq__covt; + jv handle = jq_handle_new(jq, "coroutine", &jq__covt, child); + stack_push(jq, handle); + + break; + } + case START: + initial_execution = 0; + /* fallthrough, to the input */ + case ON_BACKTRACK(START): { + // we do different things for main program and for coroutines + // because backward compatibility is a bitch + // + // main: if the jq->start_input is invalid, return invalid() + // so that the caller may decide how to proceed + // coexp: if the jq_start_input is invalid, return invalid() + jv start_input = jq->start_input; + jq->start_input = jv_invalid(); + + if(!jv_is_valid(start_input)) { + if(jq->parent) { + jq->halted = 1; + if (jv_invalid_has_msg(jv_copy(start_input))) { + return start_input; + } else { + jv_free(start_input); + return jv_invalid(); + } + } else { + // backward compatible way of saying "i want more input" + jv_free(start_input); + stack_save(jq, jq->start_pc, stack_get_pos(jq)); + return jv_invalid(); + } + } else { + stack_save(jq, jq->start_pc, stack_get_pos(jq)); + stack_push(jq, start_input); + } + break; + } + + case COEVAL: { + /* + * Eval. Setup a new jq_state to run the given program. Treat it like a co-routine. + */ + jv program = stack_pop(jq); + jv options; + jv input; + jv args; + if (jv_get_kind(program) == JV_KIND_ARRAY) { + input = jv_array_get(jv_copy(program), 1); + args = jv_array_get(jv_copy(program), 2); + options = jv_array_get(jv_copy(program), 3); + program = jv_array_get(program, 0); + } else { + options = jv_invalid(); + args = JV_OBJECT(jv_string("positional"), jv_array()); + } + if (jv_get_kind(args) != JV_KIND_OBJECT && jv_get_kind(args) != JV_KIND_NULL) { + set_error(jq, jv_invalid_with_msg(jv_string("Eval program arguments must be an object or null"))); + jv_free(program); + jv_free(options); + jv_free(input); + jv_free(args); + goto do_backtrack; + } + if (jv_get_kind(args) == JV_KIND_NULL) { + jv_free(args); + args = JV_OBJECT(jv_string("positional"), jv_array()); + } + if (jv_get_kind(options) != JV_KIND_OBJECT && jv_get_kind(options) != JV_KIND_NULL) { + set_error(jq, jv_invalid_with_msg(jv_string("Eval program options must be an object"))); + jv_free(program); + jv_free(options); + jv_free(input); + jv_free(args); + goto do_backtrack; + } + if (jv_get_kind(options) == JV_KIND_OBJECT && + jv_object_has(jv_copy(options), jv_string("ALLOW_IO"))) { + jv allow_io = jv_object_get(jv_copy(jq->attrs), jv_string("ALLOW_IO")); + if (jv_get_kind(allow_io) == JV_KIND_TRUE) { + /* Parent allows I/O; child may allow I/O */ + jv_free(allow_io); + options = jv_object_set(jv_copy(jq->attrs), jv_string("ALLOW_IO"), + jv_object_get(options, jv_string("ALLOW_IO"))); + } else { + /* No I/O for child because no I/O for parent */ + jv_free(allow_io); + jv_free(options); + options = jv_copy(jq->attrs); + } + } else { + /* Child will not allow I/O regardless of whether the parent does */ + jv_free(options); + options = jv_object_set(jv_copy(jq->attrs), jv_string("ALLOW_IO"), + jv_false()); + } + if (jv_get_kind(program) != JV_KIND_STRING) { + set_error(jq, jv_invalid_with_msg(jv_string("Eval program must be a string"))); + jv_free(program); + jv_free(options); + jv_free(input); + jv_free(args); + goto do_backtrack; + } + + jq_state *child = jq_init(); + if (jv_is_valid(options)) + jq_set_attrs(jq, jv_copy(options)); + + /* Give the child a way to report errors */ + jv *p = jv_mem_calloc(1, sizeof(jv)); + *p = jv_null(); + jq_set_error_cb(child, co_err_cb, p); + if (!jq_compile_args(child, jv_string_value(program), jv_copy(args))) { + set_error(jq, jv_invalid_with_msg(jv_string_fmt("Eval program failed to compile: %s", jv_string_value(*p)))); + jq_teardown(&child); + jv_free(program); + jv_free(options); + jv_free(input); + jv_free(args); + jv_free(*p); + free(p); + goto do_backtrack; + } + /* Now let the child send errors to stderr again? */ + jq_set_error_cb(child, NULL, NULL); + jq_start(child, jv_copy(input), jq->debug_trace_enabled ? JQ_DEBUG_TRACE_ALL : 0); + copy_callbacks(jq, child); + jv_free(program); + jv_free(options); + jv_free(input); + jv_free(args); + jv_free(*p); + free(p); + + extern struct jq_io_table jq__covt; + stack_push(jq, jq_handle_new(jq, "coroutine", &jq__covt, child)); + stack_save(jq, pc - 1, stack_get_pos(jq)); + break; + } + case ON_BACKTRACK(COEVAL): { + jv cohandle = stack_pop(jq); + jq_handle_close(jq, cohandle); + goto do_backtrack; + } + + case TAIL_OUT: { + // optimized version of OUT;BACKTRACK + jv value = stack_pop(jq); + return value; + } + case OUT: { + jv value = stack_pop(jq); + stack_save(jq, pc - 1, stack_get_pos(jq)); + return value; + } + case ON_BACKTRACK(OUT): { + // stop backtracking, + // move on + break; + } + + case RET_JQ: { jv value = stack_pop(jq); assert(jq->stk_top == frame_current(jq)->retdata); uint16_t* retaddr = frame_current(jq)->retaddr; @@ -939,10 +1385,6 @@ jv jq_next(jq_state *jq) { stack_push(jq, value); break; } - case ON_BACKTRACK(RET): { - // resumed after top-level return - goto do_backtrack; - } } } } @@ -980,6 +1422,8 @@ jv jq_format_error(jv msg) { return jq_format_error(jv_invalid_get_msg(msg)); } +static void init_vtable(struct jq_plugin_vtable *); + // XXX Refactor into a utility function that returns a jv and one that // uses it and then prints that jv's string as the complete error // message. @@ -995,31 +1439,136 @@ jq_state *jq_init(void) { if (jq == NULL) return NULL; + init_vtable(&vtable); + jq->vtable = &vtable; jq->bc = 0; + jq->libs = 0; jq->next_label = 0; stack_init(&jq->stk); + jq->parent = 0; + jq->start_pc = 0; + jq->restore_limit = 0; jq->stk_top = 0; jq->fork_top = 0; jq->curr_frame = 0; jq->error = jv_null(); jq->halted = 0; + jq->finished = 0; jq->exit_code = jv_invalid(); jq->error_message = jv_invalid(); jq->err_cb = default_err_cb; jq->err_cb_data = stderr; + jq->input_cb = 0; + jq->input_cb_data = 0; + + jq->start_input = jv_invalid(); + + jq->vmid = jv_number_random_int(); + jq->rnd = jv_number_random_int(); jq->attrs = jv_object(); jq->path = jv_null(); jq->value_at_path = jv_null(); jq->nomem_handler = NULL; jq->nomem_handler_data = NULL; + jq->handles = &jq->handles_s; + jq->handles->jhandles = jv_array(); + jq->handles->nhandles = 0; + jq->handles->handles = 0; + + jq->io_policy = NULL; + jq->io_policy_data = jv_null(); + return jq; } +static void co_err_cb(void *d, jv msg) { + jv prev = *(jv *)d; + + if (jv_get_kind(prev) == JV_KIND_NULL) { + *(jv *)d = msg; + } else if (jv_get_kind(prev) == JV_KIND_STRING) { + *(jv *)d = jv_string_fmt("%s; %s", jv_string_value(prev), jv_string_value(msg)); + jv_free(prev); + jv_free(msg); + } else { + jv_free(prev); + *(jv *)d = msg; + } +} + +static jv coinput_cb(jq_state *child, void *vjv) { + jv *jvp = vjv; + jv ret; + + if (jv_is_valid(*jvp) || jv_invalid_has_msg(jv_copy(*jvp))) { + ret = *jvp; + *jvp = jv_invalid(); + return ret; + } + + return jv_invalid(); +} + +/* Not intended to be called by apps */ +static jq_state *coinit(jq_state *parent, uint16_t* start_pc) { + jq_state *child; + child = jv_mem_calloc(1, sizeof(*child)); + + /* First, copy all fields */ + *child = *parent; + + /* Copy the stack (see notes in exec_stack.h) */ + stack_copy(&child->stk, &parent->stk); + + /* Linkt the parent */ + child->parent = parent; + + /* Stop the child freeing things that belong to the parent */ + child->restore_limit = child->stk.limit; + child->start_pc = start_pc; + + child->halted = 0; + child->libs = 0; + child->initial_execution = 1; + + /* Give the client a VM ID */ + child->rnd = jv_number_random_int(); + child->vmid = jv_invalid(); + do { + jv_free(child->vmid); + child->vmid = jv_number_random_int(); + } while (jv_is_valid(child->vmid) && jv_is_valid(parent->vmid) && + jv_equal(jv_copy(parent->vmid), jv_copy(child->vmid))); /* paranoia */ + + /* Copy or null out various jv values not kept on the stack */ + child->value_at_path = jv_copy(parent->value_at_path); + child->error_message = jv_invalid(); + child->exit_code = jv_invalid(); + child->error = jv_null(); + child->attrs = jv_copy(parent->attrs); + child->path = jv_copy(parent->path); + child->io_policy_data = jv_copy(parent->io_policy_data); + child->start_input = jv_invalid(); + + /* Share I/O handles with the parent */ + child->handles = parent->handles; + + /* + * Give the child a way to get inputs from writes to the I/O handle for the + * client. + */ + jq_set_input_cb(child, coinput_cb, &child->start_input); + + return child; +} + +jv jq_get_vmid(jq_state *jq) { return jv_copy(jq->vmid); } + void jq_set_error_cb(jq_state *jq, jq_msg_cb cb, void *data) { if (cb == NULL) { jq->err_cb = default_err_cb; @@ -1044,35 +1593,53 @@ void jq_set_nomem_handler(jq_state *jq, void (*nomem_handler)(void *), void *dat void jq_start(jq_state *jq, jv input, int flags) { jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); - jq_reset(jq); - struct closure top = {jq->bc, -1}; - struct frame* top_frame = frame_push(jq, top, 0, 0); - top_frame->retdata = 0; - top_frame->retaddr = 0; + if (!jq->parent) { + jq_reset(jq); + struct closure top = {jq->bc, -1}; + struct frame* top_frame = frame_push(jq, top, 0, 0); + top_frame->retdata = 0; + top_frame->retaddr = 0; + } + + jq->start_input = input; + stack_save(jq, jq->parent ? jq->start_pc : jq->bc->code, stack_get_pos(jq)); - stack_push(jq, input); - stack_save(jq, jq->bc->code, stack_get_pos(jq)); jq->debug_trace_enabled = flags & JQ_DEBUG_TRACE_ALL; jq->initial_execution = 1; + jq->halted = 0; + jq->finished = 0; } -void jq_teardown(jq_state **jq) { - jq_state *old_jq = *jq; - if (old_jq == NULL) +void jq_teardown(jq_state **jqp) { + jq_state *jq = *jqp; + if (jq == NULL) return; - *jq = NULL; + *jqp = NULL; + + jq_reset(jq); + if (jq->parent) + stack_reset(&jq->stk, jq->restore_limit); - jq_reset(old_jq); - bytecode_free(old_jq->bc); - old_jq->bc = 0; - jv_free(old_jq->attrs); + if (jq->handles == &jq->handles_s) + jv_free(jq->handles->jhandles); - jv_mem_free(old_jq); + if (!jq->parent) { + bytecode_free(jq->bc); + libraries_free(jq->libs); + if (jq->io_policy) + jq_teardown(&jq->io_policy); + } + jv_free(jq->rnd); + jv_free(jq->vmid); + jv_free(jq->attrs); + jv_free(jq->io_policy_data); + + jv_mem_free(jq); } static int ret_follows(uint16_t *pc) { - if (*pc == RET) + if (*pc == RET_JQ) return 1; if (*pc++ != JUMP) return 0; @@ -1098,8 +1665,8 @@ static int ret_follows(uint16_t *pc) { * * We're looking for: * - * a) the next instruction is a RET or a chain of unconditional JUMPs - * that ends in a RET, and + * a) the next instruction is a RET_JQ or a chain of unconditional JUMPs + * that ends in a RET_JQ, and * * b) none of the closures -callee included- have level == 0. */ @@ -1168,8 +1735,13 @@ int jq_compile_args(jq_state *jq, const char* str, jv args) { if (jq->bc) { bytecode_free(jq->bc); jq->bc = 0; + jq->start_pc = 0; } - int nerrors = load_program(jq, locations, &program); + if (jq->libs) { + libraries_free(jq->libs); + jq->libs = 0; + } + int nerrors = load_program(jq, locations, &program, &jq->libs); if (nerrors == 0) { nerrors = builtins_bind(jq, &program); if (nerrors == 0) { @@ -1179,8 +1751,10 @@ int jq_compile_args(jq_state *jq, const char* str, jv args) { jv_free(args); if (nerrors) jq_report_error(jq, jv_string_fmt("jq: %d compile %s", nerrors, nerrors > 1 ? "errors" : "error")); - if (jq->bc) + if (jq->bc) { jq->bc = optimize(jq->bc); + jq->start_pc = jq->bc->code; + } locfile_free(locations); return jq->bc != NULL; } @@ -1189,6 +1763,192 @@ int jq_compile(jq_state *jq, const char* str) { return jq_compile_args(jq, str, jv_object()); } +static int get_handle_index(jq_state *jq, jv handle) { + int i = -1; + jv n = jv_invalid(); + + if (jq->handles->nhandles > 0 && + jv_get_kind(handle) == JV_KIND_OBJECT && + jv_get_kind((n = jv_object_get(jv_copy(handle), jv_string("n")))) == JV_KIND_NUMBER && + jv_number_value(n) < jq->handles->nhandles && + jv_number_value(n) < INT_MAX && + jv_equal(jv_copy(handle), + jv_array_get(jv_copy(jq->handles->jhandles), jv_number_value(n)))) + i = jv_number_value(n); + jv_free(handle); + jv_free(n); + return i; +} + +void *jq_handle_get(jq_state *jq, jv handle) { + int i = get_handle_index(jq, handle); + + if (i == -1 || !jq->handles->handles[i]) + return 0; + return jq->handles->handles[i]->handle; +} + +jv jq_handle_get_kind(jq_state *jq, jv handle) { + void *h = jq_handle_get(jq, handle); + + if (h && jv_get_kind(handle) == JV_KIND_OBJECT) + return jv_getpath(handle, JV_ARRAY(jv_string("v"), jv_string("kind"))); + + jv_free(handle); + return jv_invalid(); +} + +static jv make_verifier(const char *kind, void *handle, void *junk) { + jv n = jv_number_random_int(); + + if (jv_is_valid(n)) + return JV_OBJECT(jv_string("kind"), jv_string(kind), + jv_string("r"), n); + + /* No system RNG? Use handle and junk ptr values as verifier "randoms" */ + return JV_OBJECT(jv_string("kind"), jv_string(kind), + jv_string("r"), JV_ARRAY(jv_number((uintptr_t)handle), + jv_number((uintptr_t)junk))); +} + +static int new_handle_slot(jq_state *jq) { + size_t additions = jq->handles->nhandles == 0 ? 16 : (jq->handles->nhandles>>1) + 4; + size_t k; + + /* Find a slot */ + for (k = 0; k < jq->handles->nhandles; k++) { + if (jq->handles->handles[k] == 0 || jq->handles->handles[k]->handle == 0) { + assert(k < INT_MAX); + return k; + } + } + + /* Allocate additional slots */ + jq->handles->handles = jv_mem_realloc(jq->handles->handles, + sizeof(jq->handles->handles[0]) * (jq->handles->nhandles + additions)); + memset(&jq->handles->handles[jq->handles->nhandles], 0, sizeof(jq->handles->handles[0]) * additions); + jq->handles->nhandles += additions; + assert(k < INT_MAX); + return k; +} + +jv jq_handle_new(jq_state *jq, const char *kind, struct jq_io_table *vt, void *hdl) { + int i = new_handle_slot(jq); + + if (i < 0) { + if (vt->fhclose) + jv_free(vt->fhclose(jq, jv_invalid(), hdl)); + return jv_invalid(); + } + + jv jhandle = JV_OBJECT(jv_string("n"), jv_number(i), + jv_string("v"), make_verifier(kind, hdl, jq->handles->handles)); + jq->handles->jhandles = jv_array_set(jq->handles->jhandles, i, jv_copy(jhandle)); + jq->handles->handles[i] = jv_mem_alloc(sizeof(jq->handles->handles[i][0])); + jq->handles->handles[i]->handle = hdl; + jq->handles->handles[i]->refcnt = 1; + jq->handles->handles[i]->vt = vt; + return jhandle; +} + +jv jq_handle_close(jq_state *jq, jv handle) { + struct raw_handle *rhp; + int i = get_handle_index(jq, jv_copy(handle)); + + if (i < 0) { + jv_free(handle); + return jv_invalid_with_msg(jv_string("No such open file handle")); + } + + rhp = jq->handles->handles[i]; + jq->handles->handles[i] = 0; + if (--(rhp->refcnt)) { + jv_free(handle); + return jv_true(); + } + + /* We cleanup first, then call the close function to avoid reentry via coclose() */ + struct raw_handle rh = *rhp; + jq->handles->jhandles = jv_array_set(jq->handles->jhandles, i, jv_invalid()); + rhp->handle = 0; + rhp->vt = 0; + free(rhp); + jv ret = rh.vt->fhclose ? rh.vt->fhclose(jq, jv_copy(handle), rh.handle) : jv_true(); + jv_free(handle); + return ret; +} + +jv jq_handle_reset(jq_state *jq, jv handle) { + struct raw_handle *rh; + int i = get_handle_index(jq, jv_copy(handle)); + + if (i < 0) + return jv_invalid_with_msg(jv_string("No such open file handle")); + + rh = jq->handles->handles[i]; + if (rh->vt->fhreset) + return rh->vt->fhreset(jq, handle, rh->handle); + jv_free(handle); + return jv_false(); +} + +jv jq_handle_write(jq_state *jq, jv handle, jv v) { + struct raw_handle *rh; + int i = get_handle_index(jq, jv_copy(handle)); + + if (i < 0) + return jv_invalid_with_msg(jv_string("No such open file handle")); + + rh = jq->handles->handles[i]; + if (rh->vt->fhwrite) + return rh->vt->fhwrite(jq, handle, rh->handle, v); + else + jv_free(handle); + return jv_invalid_with_msg(jv_string("Failed to write to file")); /* XXX filename would be nice */ +} + +jv jq_handle_read(jq_state *jq, jv handle) { + struct raw_handle *rh; + int i = get_handle_index(jq, jv_copy(handle)); + + if (i < 0) + return jv_invalid_with_msg(jv_string("No such open file handle")); + + rh = jq->handles->handles[i]; + if (rh->vt->fhread) + return rh->vt->fhread(jq, handle, rh->handle); + jv_free(handle); + return jv_invalid_with_msg(jv_string("Failed to read from file")); /* XXX filename would be nice */ +} + +jv jq_handle_stat(jq_state *jq, jv handle) { + struct raw_handle *rh; + int i = get_handle_index(jq, jv_copy(handle)); + + if (i < 0) + return jv_invalid_with_msg(jv_string("No such open file handle")); + + rh = jq->handles->handles[i]; + if (rh->vt->fhstat) + return rh->vt->fhstat(jq, handle, rh->handle); + jv_free(handle); + return jv_invalid_with_msg(jv_string("Failed to stat file")); /* XXX filename would be nice */ +} + +jv jq_handle_eof(jq_state *jq, jv handle) { + struct raw_handle *rh; + int i = get_handle_index(jq, jv_copy(handle)); + + if (i < 0) + return jv_invalid_with_msg(jv_string("No such open file handle")); + + rh = jq->handles->handles[i]; + if (rh->vt->fheof) + return rh->vt->fheof(jq, handle, rh->handle); + jv_free(handle); + return jv_invalid_with_msg(jv_string("Failed to determine if file handle at EOF")); +} + jv jq_get_jq_origin(jq_state *jq) { return jq_get_attr(jq, jv_string("JQ_ORIGIN")); } @@ -1207,6 +1967,110 @@ void jq_set_attrs(jq_state *jq, jv attrs) { jq->attrs = attrs; } +/* + * Set an I/O policy -- a jq program. + * + * If, when given `null` as input, the policy jq program produces an object or + * an array, or `true` or `null` or `false`, then that will be the policy data + * and the program used at run time will be the `default_io_policy_check` + * builtin using the constant data produced by running the original program + * with `null` as input. + * + * Otherwise the given jq program will be the policy checker. + * + * At run-time the policy will be checked by calling the policy program (on a + * separate jq_state!) with a request descriptor and the policy data as input. + */ +jv jq_set_io_policy(jq_state *jq, jv policy) { + if (jq->io_policy) + jq_teardown(&jq->io_policy); + + switch (jv_get_kind(policy)) { + case JV_KIND_STRING: + break; + case JV_KIND_INVALID: + jv_free(policy); + return jv_invalid_with_msg(jv_string_fmt("Invalid I/O policy given")); + case JV_KIND_NULL: + case JV_KIND_TRUE: + case JV_KIND_FALSE: + jv_free(jq->io_policy_data); + jq->io_policy_data = policy; + return jv_true(); + default: + jv_free(jq->io_policy_data); + jq->io_policy_data = policy; + policy = jv_string("default_io_policy_check"); + break; + } + + jq_state *io_policy = jq_init(); + if (!io_policy) + return jv_invalid_with_msg(jv_string("Out of memory")); + + int r = jq_compile_args(io_policy, jv_string_value(policy), jv_array()); + if (!r) { + jq_teardown(&io_policy); + jv ret = jv_invalid_with_msg(jv_string_fmt("Failed to compile I/O policy program: %s\n", + jv_string_value(policy))); + jv_free(policy); + return ret; + } + + /* Check if the program produces policy data, or evaluates policy */ + jq_start(io_policy, jv_null(), 0); + copy_callbacks(jq, io_policy); + jv v = jq_next(io_policy); + jv ret; + switch (jv_get_kind(v)) { + case JV_KIND_OBJECT: + case JV_KIND_ARRAY: + /* Produces data to evaluate with the default policy checker */ + jv_free(jq->io_policy_data); + jq->io_policy_data = v; + v = jv_null(); + jq_teardown(&io_policy); + io_policy = jq_init(); + if (!io_policy) { + jv_free(policy); + return jv_invalid_with_msg(jv_string("Out of memory")); // XXX leak + } + r = jq_compile_args(io_policy, "default_io_policy_check", jv_array()); + if (!r) { + jq_teardown(&io_policy); + jv ret = jv_invalid_with_msg(jv_string("Failed to compile default I/O policy program\n")); + jv_free(policy); + return ret; + } + jq->io_policy = io_policy; + return jv_true(); + case JV_KIND_NULL: + case JV_KIND_TRUE: + case JV_KIND_FALSE: + /* Produces simple data */ + jv_free(jq->io_policy_data); + jq->io_policy_data = v; + jq_teardown(&io_policy); + return jv_true(); + case JV_KIND_INVALID: + /* The program is a policy evaluator */ + jq->io_policy = io_policy; + jv_free(policy); + jv_free(v); + return jv_true(); + case JV_KIND_STRING: + /* Usage error */ + ret = jv_invalid_with_msg(jv_string_fmt("Strange policy value: %s", jv_string_value(policy))); + jv_free(policy); + return ret; + default: + /* Usage error */ + ret = jv_invalid_with_msg(jv_string_fmt("Strange policy value")); + jv_free(policy); + return ret; + } +} + void jq_set_attr(jq_state *jq, jv attr, jv val) { jq->attrs = jv_object_set(jq->attrs, attr, val); } @@ -1254,6 +2118,12 @@ jq_halted(jq_state *jq) return jq->halted; } +int +jq_finished(jq_state *jq) +{ + return jq->halted || jq->finished; +} + jv jq_get_exit_code(jq_state *jq) { return jv_copy(jq->exit_code); @@ -1263,3 +2133,169 @@ jv jq_get_error_message(jq_state *jq) { return jv_copy(jq->error_message); } + +jv jq_io_policy_check(jq_state *jq, jv req) { + if (!jq->io_policy) { + jv_free(req); + return jv_copy(jq->io_policy_data); + } + jq_start(jq->io_policy, + JV_OBJECT(jv_string("io_policy"), jv_copy(jq->io_policy_data), + jv_string("io_request"), req), 0); + copy_callbacks(jq, jq->io_policy); + jv res = jq_next(jq->io_policy); + switch (jv_get_kind(res)) { + case JV_KIND_TRUE: + case JV_KIND_FALSE: + return res; + case JV_KIND_INVALID: + if (jv_invalid_has_msg(jv_copy(res))) + return res; + jv_free(res); + return jv_false(); + default: + jv_free(res); + return jv_false(); + } +} + +static void init_vtable(struct jq_plugin_vtable *vtable) { + vtable->jv_string_append_buf = jv_string_append_buf; + vtable->jv_object_iter_next = jv_object_iter_next; + vtable->jq_get_lib_dirs = jq_get_lib_dirs; + vtable->jv_mem_free = jv_mem_free; + vtable->jq_get_error_cb = jq_get_error_cb; + vtable->jv_string_vfmt = jv_string_vfmt; + vtable->jv_number_value = jv_number_value; + vtable->jv_mem_alloc_unguarded = jv_mem_alloc_unguarded; + vtable->jv_true = jv_true; + vtable->jv_object_set = jv_object_set; + vtable->jv_mem_calloc = jv_mem_calloc; + vtable->jv_parser_next = jv_parser_next; + vtable->jv_dump_string = jv_dump_string; + vtable->jv_invalid_get_msg = jv_invalid_get_msg; + vtable->jq_util_input_set_parser = jq_util_input_set_parser; + vtable->jv_copy = jv_copy; + vtable->jv_get = jv_get; + vtable->jv_mem_calloc_unguarded = jv_mem_calloc_unguarded; + vtable->jv_string_value = jv_string_value; + vtable->jv_identical = jv_identical; + vtable->jq_get_prog_origin = jq_get_prog_origin; + vtable->jv_invalid_with_msg = jv_invalid_with_msg; + vtable->jv_equal = jv_equal; + vtable->jq_dump_disassembly = jq_dump_disassembly; + vtable->jv_object_iter = jv_object_iter; + vtable->jv_dump = jv_dump; + vtable->jv_array_sized = jv_array_sized; + vtable->jv_string_append_str = jv_string_append_str; + vtable->jq_get_exit_code = jq_get_exit_code; + vtable->jv_getpath = jv_getpath; + vtable->jq_get_attr = jq_get_attr; + vtable->jq_halted = jq_halted; + vtable->jq_finished = jq_finished; + vtable->jv_array_length = jv_array_length; + vtable->jv_array_concat = jv_array_concat; + vtable->jv_string_implode = jv_string_implode; + vtable->jv_string_explode = jv_string_explode; + vtable->jq_start = jq_start; + vtable->jq_teardown = jq_teardown; + vtable->jv_parser_remaining = jv_parser_remaining; + vtable->jq_util_input_get_position = jq_util_input_get_position; + vtable->jv_group = jv_group; + vtable->jv_false = jv_false; + vtable->jv_string_fmt = jv_string_fmt; + vtable->jq_set_input_cb = jq_set_input_cb; + vtable->jq_util_input_init = jq_util_input_init; + vtable->jv_null = jv_null; + vtable->jv_setpath = jv_setpath; + vtable->jv_string_split = jv_string_split; + vtable->jv_set = jv_set; + vtable->jv_mem_strdup_unguarded = jv_mem_strdup_unguarded; + vtable->jq_get_jq_origin = jq_get_jq_origin; + vtable->jq_halt = jq_halt; + vtable->jv_show = jv_show; + vtable->jq_init = jq_init; + vtable->jv_kind_name = jv_kind_name; + vtable->jv_string_append_codepoint = jv_string_append_codepoint; + vtable->jq_get_error_message = jq_get_error_message; + vtable->jv_array_get = jv_array_get; + vtable->jv_object_merge = jv_object_merge; + vtable->jq_compile_args = jq_compile_args; + vtable->jq_util_input_next_input = jq_util_input_next_input; + vtable->jv_dump_string_trunc = jv_dump_string_trunc; + vtable->jq_next = jq_next; + vtable->jv_parse_sized = jv_parse_sized; + vtable->jv_cmp = jv_cmp; + vtable->jv_number = jv_number; + vtable->jv_dumpf = jv_dumpf; + vtable->jv_object_get = jv_object_get; + vtable->jv_parse = jv_parse; + vtable->jq_set_attr = jq_set_attr; + vtable->jq_util_input_get_current_line = jq_util_input_get_current_line; + vtable->jv_parser_new = jv_parser_new; + vtable->jv_object_iter_value = jv_object_iter_value; + vtable->jv_invalid_has_msg = jv_invalid_has_msg; + vtable->jv_string_length_bytes = jv_string_length_bytes; + vtable->jv_object_iter_key = jv_object_iter_key; + vtable->jq_report_error = jq_report_error; + vtable->jv_is_integer = jv_is_integer; + vtable->jv_string = jv_string; + vtable->jv_contains = jv_contains; + vtable->jv_mem_alloc = jv_mem_alloc; + vtable->jv_string_hash = jv_string_hash; + vtable->jv_string_slice = jv_string_slice; + vtable->jv_load_file = jv_load_file; + vtable->jq_compile = jq_compile; + vtable->jv_get_kind = jv_get_kind; + vtable->jv_object_merge_recursive = jv_object_merge_recursive; + vtable->jv_bool = jv_bool; + vtable->jq_util_input_get_current_filename = jq_util_input_get_current_filename; + vtable->jv_object_iter_valid = jv_object_iter_valid; + vtable->jv_has = jv_has; + vtable->jv_array_set = jv_array_set; + vtable->jv_object_delete = jv_object_delete; + vtable->jq_set_debug_cb = jq_set_debug_cb; + vtable->jv_string_empty = jv_string_empty; + vtable->jq_realpath = jq_realpath; + vtable->jq_set_error_cb = jq_set_error_cb; + vtable->jq_util_input_next_input_cb = jq_util_input_next_input_cb; + vtable->jv_get_refcnt = jv_get_refcnt; + vtable->jq_set_colors = jq_set_colors; + vtable->jv_array_slice = jv_array_slice; + vtable->jv_mem_realloc = jv_mem_realloc; + vtable->jv_array = jv_array; + vtable->jv_parser_set_buf = jv_parser_set_buf; + vtable->jv_keys_unsorted = jv_keys_unsorted; + vtable->jv_delpaths = jv_delpaths; + vtable->jv_sort = jv_sort; + vtable->jv_parser_free = jv_parser_free; + vtable->jv_array_indexes = jv_array_indexes; + vtable->jv_string_concat = jv_string_concat; + vtable->jv_object_has = jv_object_has; + vtable->jv_invalid = jv_invalid; + vtable->jq_util_input_free = jq_util_input_free; + vtable->jv_object_length = jv_object_length; + vtable->jq_get_input_cb = jq_get_input_cb; + vtable->jv_string_sized = jv_string_sized; + vtable->jv_string_length_codepoints = jv_string_length_codepoints; + vtable->jq_format_error = jq_format_error; + vtable->jv_array_append = jv_array_append; + vtable->jv_string_indexes = jv_string_indexes; + vtable->jv_free = jv_free; + vtable->jq_get_debug_cb = jq_get_debug_cb; + vtable->jq_util_input_errors = jq_util_input_errors; + vtable->jv_mem_strdup = jv_mem_strdup; + vtable->jq_util_input_add_input = jq_util_input_add_input; + vtable->jv_object = jv_object; + vtable->jv_keys = jv_keys; + vtable->jq_set_attrs = jq_set_attrs; + vtable->jq_handle_get_kind = jq_handle_get_kind; + vtable->jq_handle_get = jq_handle_get; + vtable->jq_handle_new = jq_handle_new; + vtable->jq_handle_reset = jq_handle_reset; + vtable->jq_handle_close = jq_handle_close; + vtable->jq_handle_write = jq_handle_write; + vtable->jq_handle_read = jq_handle_read; + vtable->jq_handle_stat = jq_handle_stat; + vtable->jq_handle_eof = jq_handle_eof; +} diff --git a/src/jq.h b/src/jq.h index 5269de3ff8..48c12daf4e 100644 --- a/src/jq.h +++ b/src/jq.h @@ -10,6 +10,7 @@ enum { JQ_DEBUG_TRACE_ALL = JQ_DEBUG_TRACE | JQ_DEBUG_TRACE_DETAIL, }; + typedef struct jq_state jq_state; typedef void (*jq_msg_cb)(void *, jv); @@ -28,6 +29,7 @@ void jq_teardown(jq_state **); void jq_halt(jq_state *, jv, jv); int jq_halted(jq_state *); +int jq_finished(jq_state *); jv jq_get_exit_code(jq_state *); jv jq_get_error_message(jq_state *); @@ -38,6 +40,11 @@ void jq_get_input_cb(jq_state *, jq_input_cb *, void **); void jq_set_debug_cb(jq_state *, jq_msg_cb, void *); void jq_get_debug_cb(jq_state *, jq_msg_cb *, void **); +jv jq_get_vmid(jq_state *); + +jv jq_io_policy_check(jq_state *, jv); + +jv jq_set_io_policy(jq_state *, jv); void jq_set_attrs(jq_state *, jv); jv jq_get_attrs(jq_state *); jv jq_get_jq_origin(jq_state *); diff --git a/src/jq_plugin.h b/src/jq_plugin.h new file mode 100644 index 0000000000..a9d9e670e3 --- /dev/null +++ b/src/jq_plugin.h @@ -0,0 +1,509 @@ + +#ifndef JQ_PLUGIN_H +#define JQ_PLUGIN_H + +#include +#include +#include + +typedef jv (*jq_fhclose_f)(jq_state *, jv, void *); +typedef jv (*jq_fhreset_f)(jq_state *, jv, void *); +typedef jv (*jq_fhwrite_f)(jq_state *, jv, void *, jv); +typedef jv (*jq_fhread_f)(jq_state *, jv, void *); +typedef jv (*jq_fhstat_f)(jq_state *, jv, void *); +typedef jv (*jq_fheof_f)(jq_state *, jv, void *); + +struct jq_io_table { + const char *kind; + jq_fhclose_f fhclose; + jq_fhreset_f fhreset; + jq_fhwrite_f fhwrite; + jq_fhread_f fhread; + jq_fhstat_f fhstat; + jq_fheof_f fheof; +}; + +void *jq_handle_get(jq_state *, jv); +jv jq_handle_get_kind(jq_state *, jv); +jv jq_handle_new(jq_state *, const char *, struct jq_io_table *, void *); +jv jq_handle_close(jq_state *jq, jv jhandle); +jv jq_handle_reset(jq_state *jq, jv jhandle); +jv jq_handle_write(jq_state *jq, jv jhandle, jv); +jv jq_handle_read(jq_state *jq, jv jhandle); +jv jq_handle_stat(jq_state *jq, jv jhandle); +jv jq_handle_eof(jq_state *jq, jv jhandle); + + +#define MAX_CFUNCTION_ARGS 10 +typedef void (*cfunction_ptr)(); +struct cfunction { + cfunction_ptr fptr; + const char* name; + int nargs; + unsigned int pure:1; + unsigned int exported:1; +}; + +/* GENERATED BY dwarf2h START */ +typedef jv (*jq_get_error_message_f)(jq_state*); +typedef jv (*jq_get_exit_code_f)(jq_state*); +typedef int (*jq_halted_f)(jq_state*); +typedef int (*jq_finished_f)(jq_state*); +typedef void (*jq_halt_f)(jq_state*,jv,jv); +typedef void (*jq_get_debug_cb_f)(jq_state*,jq_msg_cb*,void **); +typedef void (*jq_set_debug_cb_f)(jq_state*,jq_msg_cb,void *); +typedef void (*jq_get_input_cb_f)(jq_state*,jq_input_cb*,void **); +typedef void (*jq_set_input_cb_f)(jq_state*,jq_input_cb,void *); +typedef void (*jq_dump_disassembly_f)(jq_state*,int); +typedef jv (*jq_get_attr_f)(jq_state*,jv); +typedef jv (*jq_io_policy_check_f)(jq_state *, jv); +typedef jv (*jq_set_io_policy_f)(jq_state *, jv); +typedef void (*jq_set_attr_f)(jq_state*,jv,jv); +typedef void (*jq_set_attrs_f)(jq_state*,jv); +typedef void * (*jq_handle_get_f)(jq_state*,jv); +typedef jv (*jq_handle_get_kind_f)(jq_state *, jv); +typedef jv (*jq_handle_new_f)(jq_state *, const char *, struct jq_io_table *, void *); +typedef jv (*jq_handle_close_f)(jq_state *jq, jv jhandle); +typedef jv (*jq_handle_reset_f)(jq_state *jq, jv jhandle); +typedef jv (*jq_handle_write_f)(jq_state *jq, jv jhandle, jv); +typedef jv (*jq_handle_read_f)(jq_state *jq, jv jhandle); +typedef jv (*jq_handle_stat_f)(jq_state *jq, jv jhandle); +typedef jv (*jq_handle_eof_f)(jq_state *jq, jv jhandle); +typedef jv (*jq_get_lib_dirs_f)(jq_state*); +typedef jv (*jq_get_prog_origin_f)(jq_state*); +typedef jv (*jq_get_jq_origin_f)(jq_state*); +typedef int (*jq_compile_f)(jq_state*,const char*); +typedef int (*jq_compile_args_f)(jq_state*,const char*,jv); +typedef void (*jq_teardown_f)(jq_state**); +typedef void (*jq_start_f)(jq_state*,jv,int); +typedef void (*jq_get_error_cb_f)(jq_state*,jq_msg_cb*,void **); +typedef void (*jq_set_error_cb_f)(jq_state*,jq_msg_cb,void *); +typedef jq_state* (*jq_init_f)(); +typedef jv (*jq_format_error_f)(jv); +typedef jv (*jq_next_f)(jq_state*); +typedef void (*jq_report_error_f)(jq_state*,jv); +typedef void * (*jv_mem_realloc_f)(void *,size_t); +typedef void (*jv_mem_free_f)(void *); +typedef char* (*jv_mem_strdup_unguarded_f)(const char*); +typedef char* (*jv_mem_strdup_f)(const char*); +typedef void * (*jv_mem_calloc_unguarded_f)(size_t,size_t); +typedef void * (*jv_mem_calloc_f)(size_t,size_t); +typedef void * (*jv_mem_alloc_unguarded_f)(size_t); +typedef void * (*jv_mem_alloc_f)(size_t); +typedef jv (*jv_group_f)(jv,jv); +typedef jv (*jv_sort_f)(jv,jv); +typedef int (*jv_cmp_f)(jv,jv); +typedef jv (*jv_keys_f)(jv); +typedef jv (*jv_keys_unsorted_f)(jv); +typedef jv (*jv_delpaths_f)(jv,jv); +typedef jv (*jv_getpath_f)(jv,jv); +typedef jv (*jv_setpath_f)(jv,jv,jv); +typedef jv (*jv_has_f)(jv,jv); +typedef jv (*jv_set_f)(jv,jv,jv); +typedef jv (*jv_get_f)(jv,jv); +typedef jv (*jv_load_file_f)(const char*,int); +typedef int (*jv_contains_f)(jv,jv); +typedef int (*jv_identical_f)(jv,jv); +typedef int (*jv_equal_f)(jv,jv); +typedef int (*jv_get_refcnt_f)(jv); +typedef void (*jv_free_f)(jv); +typedef jv (*jv_copy_f)(jv); +typedef jv (*jv_object_iter_value_f)(jv,int); +typedef jv (*jv_object_iter_key_f)(jv,int); +typedef int (*jv_object_iter_next_f)(jv,int); +typedef int (*jv_object_iter_f)(jv); +typedef int (*jv_object_iter_valid_f)(jv,int); +typedef jv (*jv_object_merge_recursive_f)(jv,jv); +typedef jv (*jv_object_merge_f)(jv,jv); +typedef int (*jv_object_length_f)(jv); +typedef jv (*jv_object_delete_f)(jv,jv); +typedef jv (*jv_object_set_f)(jv,jv,jv); +typedef int (*jv_object_has_f)(jv,jv); +typedef jv (*jv_object_get_f)(jv,jv); +typedef jv (*jv_object_f)(); +typedef jv (*jv_string_fmt_f)(const char*,...); +typedef jv (*jv_string_vfmt_f)(const char*,va_list); +typedef jv (*jv_string_append_str_f)(jv,const char*); +typedef jv (*jv_string_append_codepoint_f)(jv,uint32_t); +typedef jv (*jv_string_append_buf_f)(jv,const char*,int); +typedef jv (*jv_string_concat_f)(jv,jv); +typedef jv (*jv_string_slice_f)(jv,int,int); +typedef const char* (*jv_string_value_f)(jv); +typedef long unsigned int (*jv_string_hash_f)(jv); +typedef jv (*jv_string_implode_f)(jv); +typedef jv (*jv_string_explode_f)(jv); +typedef jv (*jv_string_split_f)(jv,jv); +typedef jv (*jv_string_indexes_f)(jv,jv); +typedef int (*jv_string_length_codepoints_f)(jv); +typedef int (*jv_string_length_bytes_f)(jv); +typedef jv (*jv_string_f)(const char*); +typedef jv (*jv_string_empty_f)(int); +typedef jv (*jv_string_sized_f)(const char*,int); +typedef jv (*jv_array_indexes_f)(jv,jv); +typedef jv (*jv_array_slice_f)(jv,int,int); +typedef jv (*jv_array_concat_f)(jv,jv); +typedef jv (*jv_array_append_f)(jv,jv); +typedef jv (*jv_array_set_f)(jv,int,jv); +typedef jv (*jv_array_get_f)(jv,int); +typedef int (*jv_array_length_f)(jv); +typedef jv (*jv_array_f)(); +typedef jv (*jv_array_sized_f)(int); +typedef int (*jv_is_integer_f)(jv); +typedef double (*jv_number_value_f)(jv); +typedef jv (*jv_number_f)(double); +typedef int (*jv_invalid_has_msg_f)(jv); +typedef jv (*jv_invalid_get_msg_f)(jv); +typedef jv (*jv_invalid_f)(); +typedef jv (*jv_invalid_with_msg_f)(jv); +typedef jv (*jv_bool_f)(int); +typedef jv (*jv_null_f)(); +typedef jv (*jv_false_f)(); +typedef jv (*jv_true_f)(); +typedef const char* (*jv_kind_name_f)(jv_kind); +typedef jv_kind (*jv_get_kind_f)(jv); +typedef jv (*jv_parse_f)(const char*); +typedef jv (*jv_parse_sized_f)(const char*,int); +typedef jv (*jv_parser_next_f)(jv_parser*); +typedef void (*jv_parser_set_buf_f)(jv_parser*,const char*,int,int); +typedef int (*jv_parser_remaining_f)(jv_parser*); +typedef void (*jv_parser_free_f)(jv_parser*); +typedef jv_parser* (*jv_parser_new_f)(int); +typedef char* (*jv_dump_string_trunc_f)(jv,char*,size_t); +typedef jv (*jv_dump_string_f)(jv,int); +typedef void (*jv_show_f)(jv,int); +typedef void (*jv_dump_f)(jv,int); +typedef void (*jv_dumpf_f)(jv,FILE*,int); +typedef int (*jq_set_colors_f)(const char*); +typedef jv (*jq_util_input_next_input_f)(jq_util_input_state*); +typedef jv (*jq_util_input_get_current_line_f)(jq_state*); +typedef jv (*jq_util_input_get_current_filename_f)(jq_state*); +typedef jv (*jq_util_input_get_position_f)(jq_state*); +typedef jv (*jq_util_input_next_input_cb_f)(jq_state*,void *); +typedef int (*jq_util_input_errors_f)(jq_util_input_state*); +typedef void (*jq_util_input_add_input_f)(jq_util_input_state*,const char*); +typedef void (*jq_util_input_free_f)(jq_util_input_state**); +typedef void (*jq_util_input_set_parser_f)(jq_util_input_state*,jv_parser*,int); +typedef jq_util_input_state* (*jq_util_input_init_f)(jq_util_msg_cb,void *); +typedef jv (*jq_realpath_f)(jv); +struct jq_plugin_vtable { + jq_get_error_message_f jq_get_error_message; + jq_get_exit_code_f jq_get_exit_code; + jq_halted_f jq_halted; + jq_finished_f jq_finished; + jq_halt_f jq_halt; + jq_get_debug_cb_f jq_get_debug_cb; + jq_set_debug_cb_f jq_set_debug_cb; + jq_get_input_cb_f jq_get_input_cb; + jq_set_input_cb_f jq_set_input_cb; + jq_dump_disassembly_f jq_dump_disassembly; + jq_get_attr_f jq_get_attr; + jq_set_attr_f jq_set_attr; + jq_set_attrs_f jq_set_attrs; + jq_get_lib_dirs_f jq_get_lib_dirs; + jq_handle_get_kind_f jq_handle_get_kind; + jq_handle_get_f jq_handle_get; + jq_handle_new_f jq_handle_new; + jq_handle_close_f jq_handle_close; + jq_handle_reset_f jq_handle_reset; + jq_handle_write_f jq_handle_write; + jq_handle_read_f jq_handle_read; + jq_handle_stat_f jq_handle_stat; + jq_handle_eof_f jq_handle_eof; + jq_get_prog_origin_f jq_get_prog_origin; + jq_get_jq_origin_f jq_get_jq_origin; + jq_compile_f jq_compile; + jq_compile_args_f jq_compile_args; + jq_teardown_f jq_teardown; + jq_start_f jq_start; + jq_get_error_cb_f jq_get_error_cb; + jq_set_error_cb_f jq_set_error_cb; + jq_init_f jq_init; + jq_format_error_f jq_format_error; + jq_next_f jq_next; + jq_report_error_f jq_report_error; + jv_mem_realloc_f jv_mem_realloc; + jv_mem_free_f jv_mem_free; + jv_mem_strdup_unguarded_f jv_mem_strdup_unguarded; + jv_mem_strdup_f jv_mem_strdup; + jv_mem_calloc_unguarded_f jv_mem_calloc_unguarded; + jv_mem_calloc_f jv_mem_calloc; + jv_mem_alloc_unguarded_f jv_mem_alloc_unguarded; + jv_mem_alloc_f jv_mem_alloc; + jv_group_f jv_group; + jv_sort_f jv_sort; + jv_cmp_f jv_cmp; + jv_keys_f jv_keys; + jv_keys_unsorted_f jv_keys_unsorted; + jv_delpaths_f jv_delpaths; + jv_getpath_f jv_getpath; + jv_setpath_f jv_setpath; + jv_has_f jv_has; + jv_set_f jv_set; + jv_get_f jv_get; + jv_load_file_f jv_load_file; + jv_contains_f jv_contains; + jv_identical_f jv_identical; + jv_equal_f jv_equal; + jv_get_refcnt_f jv_get_refcnt; + jv_free_f jv_free; + jv_copy_f jv_copy; + jv_object_iter_value_f jv_object_iter_value; + jv_object_iter_key_f jv_object_iter_key; + jv_object_iter_next_f jv_object_iter_next; + jv_object_iter_f jv_object_iter; + jv_object_iter_valid_f jv_object_iter_valid; + jv_object_merge_recursive_f jv_object_merge_recursive; + jv_object_merge_f jv_object_merge; + jv_object_length_f jv_object_length; + jv_object_delete_f jv_object_delete; + jv_object_set_f jv_object_set; + jv_object_has_f jv_object_has; + jv_object_get_f jv_object_get; + jv_object_f jv_object; + jv_string_fmt_f jv_string_fmt; + jv_string_vfmt_f jv_string_vfmt; + jv_string_append_str_f jv_string_append_str; + jv_string_append_codepoint_f jv_string_append_codepoint; + jv_string_append_buf_f jv_string_append_buf; + jv_string_concat_f jv_string_concat; + jv_string_slice_f jv_string_slice; + jv_string_value_f jv_string_value; + jv_string_hash_f jv_string_hash; + jv_string_implode_f jv_string_implode; + jv_string_explode_f jv_string_explode; + jv_string_split_f jv_string_split; + jv_string_indexes_f jv_string_indexes; + jv_string_length_codepoints_f jv_string_length_codepoints; + jv_string_length_bytes_f jv_string_length_bytes; + jv_string_f jv_string; + jv_string_empty_f jv_string_empty; + jv_string_sized_f jv_string_sized; + jv_array_indexes_f jv_array_indexes; + jv_array_slice_f jv_array_slice; + jv_array_concat_f jv_array_concat; + jv_array_append_f jv_array_append; + jv_array_set_f jv_array_set; + jv_array_get_f jv_array_get; + jv_array_length_f jv_array_length; + jv_array_f jv_array; + jv_array_sized_f jv_array_sized; + jv_is_integer_f jv_is_integer; + jv_number_value_f jv_number_value; + jv_number_f jv_number; + jv_invalid_has_msg_f jv_invalid_has_msg; + jv_invalid_get_msg_f jv_invalid_get_msg; + jv_invalid_f jv_invalid; + jv_invalid_with_msg_f jv_invalid_with_msg; + jv_bool_f jv_bool; + jv_null_f jv_null; + jv_false_f jv_false; + jv_true_f jv_true; + jv_kind_name_f jv_kind_name; + jv_get_kind_f jv_get_kind; + jv_parse_f jv_parse; + jv_parse_sized_f jv_parse_sized; + jv_parser_next_f jv_parser_next; + jv_parser_set_buf_f jv_parser_set_buf; + jv_parser_remaining_f jv_parser_remaining; + jv_parser_free_f jv_parser_free; + jv_parser_new_f jv_parser_new; + jv_dump_string_trunc_f jv_dump_string_trunc; + jv_dump_string_f jv_dump_string; + jv_show_f jv_show; + jv_dump_f jv_dump; + jv_dumpf_f jv_dumpf; + jq_set_colors_f jq_set_colors; + jq_util_input_next_input_f jq_util_input_next_input; + jq_util_input_get_current_line_f jq_util_input_get_current_line; + jq_util_input_get_current_filename_f jq_util_input_get_current_filename; + jq_util_input_get_position_f jq_util_input_get_position; + jq_util_input_next_input_cb_f jq_util_input_next_input_cb; + jq_util_input_errors_f jq_util_input_errors; + jq_util_input_add_input_f jq_util_input_add_input; + jq_util_input_free_f jq_util_input_free; + jq_util_input_set_parser_f jq_util_input_set_parser; + jq_util_input_init_f jq_util_input_init; + jq_realpath_f jq_realpath; + jq_set_io_policy_f jq_set_io_policy; + jq_io_policy_check_f jq_io_policy_check; +}; +#ifdef JQ_PLUGIN +#define jv_string_append_buf ((*(struct jq_plugin_vtable **)jq)->jv_string_append_buf) +#define jv_object_iter_next ((*(struct jq_plugin_vtable **)jq)->jv_object_iter_next) +#define jq_get_lib_dirs ((*(struct jq_plugin_vtable **)jq)->jq_get_lib_dirs) +#define jv_mem_free ((*(struct jq_plugin_vtable **)jq)->jv_mem_free) +#define jq_get_error_cb ((*(struct jq_plugin_vtable **)jq)->jq_get_error_cb) +#define jv_string_vfmt ((*(struct jq_plugin_vtable **)jq)->jv_string_vfmt) +#define jv_number_value ((*(struct jq_plugin_vtable **)jq)->jv_number_value) +#define jv_mem_alloc_unguarded ((*(struct jq_plugin_vtable **)jq)->jv_mem_alloc_unguarded) +#define jv_true ((*(struct jq_plugin_vtable **)jq)->jv_true) +#define jv_object_set ((*(struct jq_plugin_vtable **)jq)->jv_object_set) +#define jv_mem_calloc ((*(struct jq_plugin_vtable **)jq)->jv_mem_calloc) +#define jv_parser_next ((*(struct jq_plugin_vtable **)jq)->jv_parser_next) +#define jv_dump_string ((*(struct jq_plugin_vtable **)jq)->jv_dump_string) +#define jv_invalid_get_msg ((*(struct jq_plugin_vtable **)jq)->jv_invalid_get_msg) +#define jq_util_input_set_parser ((*(struct jq_plugin_vtable **)jq)->jq_util_input_set_parser) +#define jv_copy ((*(struct jq_plugin_vtable **)jq)->jv_copy) +#define jv_get ((*(struct jq_plugin_vtable **)jq)->jv_get) +#define jv_mem_calloc_unguarded ((*(struct jq_plugin_vtable **)jq)->jv_mem_calloc_unguarded) +#define jv_string_value ((*(struct jq_plugin_vtable **)jq)->jv_string_value) +#define jv_identical ((*(struct jq_plugin_vtable **)jq)->jv_identical) +#define jq_get_prog_origin ((*(struct jq_plugin_vtable **)jq)->jq_get_prog_origin) +#define jv_invalid_with_msg ((*(struct jq_plugin_vtable **)jq)->jv_invalid_with_msg) +#define jv_equal ((*(struct jq_plugin_vtable **)jq)->jv_equal) +#define jq_dump_disassembly ((*(struct jq_plugin_vtable **)jq)->jq_dump_disassembly) +#define jv_object_iter ((*(struct jq_plugin_vtable **)jq)->jv_object_iter) +#define jv_dump ((*(struct jq_plugin_vtable **)jq)->jv_dump) +#define jv_array_sized ((*(struct jq_plugin_vtable **)jq)->jv_array_sized) +#define jv_string_append_str ((*(struct jq_plugin_vtable **)jq)->jv_string_append_str) +#define jq_get_exit_code ((*(struct jq_plugin_vtable **)jq)->jq_get_exit_code) +#define jv_getpath ((*(struct jq_plugin_vtable **)jq)->jv_getpath) +#define jq_get_attr ((*(struct jq_plugin_vtable **)jq)->jq_get_attr) +#define jq_halted ((*(struct jq_plugin_vtable **)jq)->jq_halted) +#define jq_finished ((*(struct jq_plugin_vtable **)jq)->jq_finished) +#define jv_array_length ((*(struct jq_plugin_vtable **)jq)->jv_array_length) +#define jv_array_concat ((*(struct jq_plugin_vtable **)jq)->jv_array_concat) +#define jv_string_implode ((*(struct jq_plugin_vtable **)jq)->jv_string_implode) +#define jv_string_explode ((*(struct jq_plugin_vtable **)jq)->jv_string_explode) +#define jq_start ((*(struct jq_plugin_vtable **)jq)->jq_start) +#define jq_teardown ((*(struct jq_plugin_vtable **)jq)->jq_teardown) +#define jv_parser_remaining ((*(struct jq_plugin_vtable **)jq)->jv_parser_remaining) +#define jq_util_input_get_position ((*(struct jq_plugin_vtable **)jq)->jq_util_input_get_position) +#define jv_group ((*(struct jq_plugin_vtable **)jq)->jv_group) +#define jv_false ((*(struct jq_plugin_vtable **)jq)->jv_false) +#define jv_string_fmt ((*(struct jq_plugin_vtable **)jq)->jv_string_fmt) +#define jq_set_input_cb ((*(struct jq_plugin_vtable **)jq)->jq_set_input_cb) +#define jq_util_input_init ((*(struct jq_plugin_vtable **)jq)->jq_util_input_init) +#define jv_null ((*(struct jq_plugin_vtable **)jq)->jv_null) +#define jv_setpath ((*(struct jq_plugin_vtable **)jq)->jv_setpath) +#define jv_string_split ((*(struct jq_plugin_vtable **)jq)->jv_string_split) +#define jv_set ((*(struct jq_plugin_vtable **)jq)->jv_set) +#define jv_mem_strdup_unguarded ((*(struct jq_plugin_vtable **)jq)->jv_mem_strdup_unguarded) +#define jq_get_jq_origin ((*(struct jq_plugin_vtable **)jq)->jq_get_jq_origin) +#define jq_halt ((*(struct jq_plugin_vtable **)jq)->jq_halt) +#define jv_show ((*(struct jq_plugin_vtable **)jq)->jv_show) +#define jq_init ((*(struct jq_plugin_vtable **)jq)->jq_init) +#define jv_kind_name ((*(struct jq_plugin_vtable **)jq)->jv_kind_name) +#define jv_string_append_codepoint ((*(struct jq_plugin_vtable **)jq)->jv_string_append_codepoint) +#define jq_get_error_message ((*(struct jq_plugin_vtable **)jq)->jq_get_error_message) +#define jv_array_get ((*(struct jq_plugin_vtable **)jq)->jv_array_get) +#define jv_object_merge ((*(struct jq_plugin_vtable **)jq)->jv_object_merge) +#define jq_compile_args ((*(struct jq_plugin_vtable **)jq)->jq_compile_args) +#define jq_util_input_next_input ((*(struct jq_plugin_vtable **)jq)->jq_util_input_next_input) +#define jv_dump_string_trunc ((*(struct jq_plugin_vtable **)jq)->jv_dump_string_trunc) +#define jq_next ((*(struct jq_plugin_vtable **)jq)->jq_next) +#define jv_parse_sized ((*(struct jq_plugin_vtable **)jq)->jv_parse_sized) +#define jv_cmp ((*(struct jq_plugin_vtable **)jq)->jv_cmp) +#define jv_number ((*(struct jq_plugin_vtable **)jq)->jv_number) +#define jv_dumpf ((*(struct jq_plugin_vtable **)jq)->jv_dumpf) +#define jv_object_get ((*(struct jq_plugin_vtable **)jq)->jv_object_get) +#define jv_parse ((*(struct jq_plugin_vtable **)jq)->jv_parse) +#define jq_io_policy_check ((*(struct jq_plugin_vtable **)jq)->jq_io_policy_check) +#define jq_set_io_policy ((*(struct jq_plugin_vtable **)jq)->jq_set_io_policy) +#define jq_set_attr ((*(struct jq_plugin_vtable **)jq)->jq_set_attr) +#define jq_util_input_get_current_line ((*(struct jq_plugin_vtable **)jq)->jq_util_input_get_current_line) +#define jv_parser_new ((*(struct jq_plugin_vtable **)jq)->jv_parser_new) +#define jv_object_iter_value ((*(struct jq_plugin_vtable **)jq)->jv_object_iter_value) +#define jv_invalid_has_msg ((*(struct jq_plugin_vtable **)jq)->jv_invalid_has_msg) +#define jv_string_length_bytes ((*(struct jq_plugin_vtable **)jq)->jv_string_length_bytes) +#define jv_object_iter_key ((*(struct jq_plugin_vtable **)jq)->jv_object_iter_key) +#define jq_report_error ((*(struct jq_plugin_vtable **)jq)->jq_report_error) +#define jv_is_integer ((*(struct jq_plugin_vtable **)jq)->jv_is_integer) +#define jv_string ((*(struct jq_plugin_vtable **)jq)->jv_string) +#define jv_contains ((*(struct jq_plugin_vtable **)jq)->jv_contains) +#define jv_mem_alloc ((*(struct jq_plugin_vtable **)jq)->jv_mem_alloc) +#define jv_string_hash ((*(struct jq_plugin_vtable **)jq)->jv_string_hash) +#define jv_string_slice ((*(struct jq_plugin_vtable **)jq)->jv_string_slice) +#define jv_load_file ((*(struct jq_plugin_vtable **)jq)->jv_load_file) +#define jq_compile ((*(struct jq_plugin_vtable **)jq)->jq_compile) +#define jv_get_kind ((*(struct jq_plugin_vtable **)jq)->jv_get_kind) +#define jv_object_merge_recursive ((*(struct jq_plugin_vtable **)jq)->jv_object_merge_recursive) +#define jv_bool ((*(struct jq_plugin_vtable **)jq)->jv_bool) +#define jq_util_input_get_current_filename ((*(struct jq_plugin_vtable **)jq)->jq_util_input_get_current_filename) +#define jv_object_iter_valid ((*(struct jq_plugin_vtable **)jq)->jv_object_iter_valid) +#define jv_has ((*(struct jq_plugin_vtable **)jq)->jv_has) +#define jv_array_set ((*(struct jq_plugin_vtable **)jq)->jv_array_set) +#define jv_object_delete ((*(struct jq_plugin_vtable **)jq)->jv_object_delete) +#define jq_set_debug_cb ((*(struct jq_plugin_vtable **)jq)->jq_set_debug_cb) +#define jv_string_empty ((*(struct jq_plugin_vtable **)jq)->jv_string_empty) +#define jq_realpath ((*(struct jq_plugin_vtable **)jq)->jq_realpath) +#define jq_set_error_cb ((*(struct jq_plugin_vtable **)jq)->jq_set_error_cb) +#define jq_util_input_next_input_cb ((*(struct jq_plugin_vtable **)jq)->jq_util_input_next_input_cb) +#define jv_get_refcnt ((*(struct jq_plugin_vtable **)jq)->jv_get_refcnt) +#define jq_set_colors ((*(struct jq_plugin_vtable **)jq)->jq_set_colors) +#define jv_array_slice ((*(struct jq_plugin_vtable **)jq)->jv_array_slice) +#define jv_mem_realloc ((*(struct jq_plugin_vtable **)jq)->jv_mem_realloc) +#define jv_array ((*(struct jq_plugin_vtable **)jq)->jv_array) +#define jv_parser_set_buf ((*(struct jq_plugin_vtable **)jq)->jv_parser_set_buf) +#define jv_keys_unsorted ((*(struct jq_plugin_vtable **)jq)->jv_keys_unsorted) +#define jv_delpaths ((*(struct jq_plugin_vtable **)jq)->jv_delpaths) +#define jv_sort ((*(struct jq_plugin_vtable **)jq)->jv_sort) +#define jv_parser_free ((*(struct jq_plugin_vtable **)jq)->jv_parser_free) +#define jv_array_indexes ((*(struct jq_plugin_vtable **)jq)->jv_array_indexes) +#define jv_string_concat ((*(struct jq_plugin_vtable **)jq)->jv_string_concat) +#define jv_object_has ((*(struct jq_plugin_vtable **)jq)->jv_object_has) +#define jv_invalid ((*(struct jq_plugin_vtable **)jq)->jv_invalid) +#define jq_util_input_free ((*(struct jq_plugin_vtable **)jq)->jq_util_input_free) +#define jv_object_length ((*(struct jq_plugin_vtable **)jq)->jv_object_length) +#define jq_get_input_cb ((*(struct jq_plugin_vtable **)jq)->jq_get_input_cb) +#define jv_string_sized ((*(struct jq_plugin_vtable **)jq)->jv_string_sized) +#define jv_string_length_codepoints ((*(struct jq_plugin_vtable **)jq)->jv_string_length_codepoints) +#define jq_format_error ((*(struct jq_plugin_vtable **)jq)->jq_format_error) +#define jv_array_append ((*(struct jq_plugin_vtable **)jq)->jv_array_append) +#define jv_string_indexes ((*(struct jq_plugin_vtable **)jq)->jv_string_indexes) +#define jv_free ((*(struct jq_plugin_vtable **)jq)->jv_free) +#define jq_get_debug_cb ((*(struct jq_plugin_vtable **)jq)->jq_get_debug_cb) +#define jq_util_input_errors ((*(struct jq_plugin_vtable **)jq)->jq_util_input_errors) +#define jv_mem_strdup ((*(struct jq_plugin_vtable **)jq)->jv_mem_strdup) +#define jq_util_input_add_input ((*(struct jq_plugin_vtable **)jq)->jq_util_input_add_input) +#define jv_object ((*(struct jq_plugin_vtable **)jq)->jv_object) +#define jv_keys ((*(struct jq_plugin_vtable **)jq)->jv_keys) +#define jq_set_attrs ((*(struct jq_plugin_vtable **)jq)->jq_set_attrs) +#define jq_handle_get ((*(struct jq_plugin_vtable **)jq)->jq_handle_get) +#define jq_handle_get_kind ((*(struct jq_plugin_vtable **)jq)->jq_handle_get_kind) +#define jq_handle_new ((*(struct jq_plugin_vtable **)jq)->jq_handle_new) +#define jq_handle_close ((*(struct jq_plugin_vtable **)jq)->jq_handle_close) +#define jq_handle_reset ((*(struct jq_plugin_vtable **)jq)->jq_handle_reset) +#define jq_handle_write ((*(struct jq_plugin_vtable **)jq)->jq_handle_write) +#define jq_handle_read ((*(struct jq_plugin_vtable **)jq)->jq_handle_read) +#define jq_handle_eof ((*(struct jq_plugin_vtable **)jq)->jq_handle_eof) +#endif /* JQ_PLUGIN */ +/* GENERATED BY dwarf2h END */ + +typedef int (*jq_plugin_init_f) + (int, /* jq plugin min supported ABI version */ + int, /* jq plugin current ABI version */ + struct jq_state *, + const char **, /* error string */ + const char **, /* jq-coded module contents */ + size_t *, /* jq-coded module contents size */ + struct cfunction **, /* array of C-coded function descriptors */ + size_t *); + +/* + * jq ABI identifiers. + * + * There are two: one for minimum supported ABI, the other for the current + * (max) ABI supported. + * + * These are constructed as MAJOR x 10,000 + MINOR x 100 + MICRO. + */ +#define JQ_CURRENT_ABI 10700 /* 1.7.0 */ +#define JQ_MIN_ABI 10700 /* 1.7.0 */ +#define JQ_MAX_ABI JQ_CURRENT_ABI + +#define JQ_BUILTIN_INIT_FUN(n, c, ...) \ + static int n (int minabi, int maxabi, jq_state *jq, const char **e, \ + const char **contents, size_t *contents_sz, \ + struct cfunction **cfuncs, size_t *ncfuncs) { \ + static struct cfunction f[] = { \ + __VA_ARGS__ \ + }; \ + if ((minabi) > JQ_CURRENT_ABI || (maxabi) < JQ_CURRENT_ABI) \ + return (*e = "JQ ABI mismatch"), -1; \ + *e = NULL; *contents = (c); *contents_sz = 0; \ + *cfuncs = f; *ncfuncs = sizeof(f) / sizeof(f[0]); \ + return 0; \ + } + +#endif /* JQ_PLUGIN_H */ diff --git a/src/jq_test.c b/src/jq_test.c index eed633f43d..0cf574c036 100644 --- a/src/jq_test.c +++ b/src/jq_test.c @@ -83,6 +83,7 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int if (jv_get_kind(lib_dirs) == JV_KIND_NULL) lib_dirs = jv_array(); jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_dirs); + jq_set_attr(jq, jv_string("ALLOW_IO"), jv_true()); while (1) { if (!fgets(prog, sizeof(prog), testdata)) break; @@ -177,28 +178,69 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int } jq_start(jq, input, verbose ? JQ_DEBUG_TRACE : 0); + // XXX Use getline(), not fgets() while (fgets(buf, sizeof(buf), testdata)) { + int expect_error = 0; + int ignore_error = 0; + jv expected; + lineno++; if (skipline(buf)) break; - jv expected = jv_parse(buf); + if ((expect_error = (strncmp(buf, "%%ERROR", sizeof("%%ERROR") - 1) == 0))) { + if ((ignore_error = (strncmp(buf, "%%ERROR IGNORE", sizeof("%%ERROR IGNORE") - 1) == 0))) { + expected = jv_parse(buf + sizeof("%%ERROR IGNORE") - 1); + } else { + expected = jv_parse(buf + sizeof("%%ERROR:") - 1); + } + } else { + expected = jv_parse(buf); + } if (!jv_is_valid(expected)) { printf("*** Expected result is invalid on line %u: %s\n", lineno, buf); invalid++; continue; } jv actual = jq_next(jq); - if (!jv_is_valid(actual)) { + if (!jv_is_valid(actual) && jv_invalid_has_msg(jv_copy(actual))) { + actual = jv_invalid_get_msg(actual); + if (!expect_error) { + printf("*** Expected non-error "); + jv_dump(expected, 0); + printf(", but got jq program error "); + jv_dump(actual, 0); + printf(" for test at line number %u: %s\n", lineno, prog); + pass = 0; + break; + } + if (!jv_equal(jv_copy(expected), jv_copy(actual))) { + printf("*** Expected %s", expect_error ? "error " : ""); + jv_dump(jv_copy(expected), 0); + printf(", but got %s", expect_error ? "error " : ""); + jv_dump(jv_copy(actual), 0); + printf(" for test at line number %u: %s\n", lineno, prog); + pass = 0; + } + } else if (!jv_is_valid(actual)) { jv_free(actual); printf("*** Insufficient results for test at line number %u: %s\n", lineno, prog); pass = 0; break; + } else if (expect_error) { + printf("*** Expected error "); + jv_dump(expected, 0); + printf(", but got non-error "); + jv_dump(actual, 0); + printf(" for test at line number %u: %s\n", lineno, prog); + pass = 0; + break; } else if (!jv_equal(jv_copy(expected), jv_copy(actual))) { - printf("*** Expected "); - jv_dump(jv_copy(expected), 0); - printf(", but got "); - jv_dump(jv_copy(actual), 0); + printf("*** Expected %s", expect_error ? "error " : ""); + jv_dump(expected, 0); + printf(", but got %s", expect_error ? "error " : ""); + jv_dump(actual, 0); printf(" for test at line number %u: %s\n", lineno, prog); pass = 0; + break; } jv as_string = jv_dump_string(jv_copy(expected), rand() & ~(JV_PRINT_COLOR|JV_PRINT_REFCOUNT)); jv reparsed = jv_parse_sized(jv_string_value(as_string), jv_string_length_bytes(jv_copy(as_string))); @@ -208,13 +250,18 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int jv_free(expected); jv_free(actual); } - if (pass) { + if (compiled && pass) { jv extra = jq_next(jq); if (jv_is_valid(extra)) { printf("*** Superfluous result: "); jv_dump(extra, 0); printf(" for test at line number %u, %s\n", lineno, prog); pass = 0; + } else if (jv_invalid_has_msg(jv_copy(extra))) { + printf("*** Superfluous error result: "); + jv_dump(jv_invalid_get_msg(extra), 0); + printf(" for test at line number %u, %s\n", lineno, prog); + pass = 0; } else { jv_free(extra); } diff --git a/src/jv.h b/src/jv.h index 8c96f822f0..40e0d2f2bd 100644 --- a/src/jv.h +++ b/src/jv.h @@ -38,7 +38,7 @@ typedef struct { jv_kind jv_get_kind(jv); const char* jv_kind_name(jv_kind); -static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; } +static int jv_is_valid(jv x) { return ((x).kind_flags & 0xf) != JV_KIND_INVALID; } jv jv_copy(jv); void jv_free(jv); @@ -210,20 +210,26 @@ enum jv_print_flags { JV_PRINT_SPACE0 = 256, JV_PRINT_SPACE1 = 512, JV_PRINT_SPACE2 = 1024, + JV_PRINT_RAW = 8192, /* not a real flag for jv_dump functions yet */ + JV_PRINT_NOLF = 16384, /* not a real flag for jv_dump functions yet */ }; #define JV_PRINT_INDENT_FLAGS(n) \ ((n) < 0 || (n) > 7 ? JV_PRINT_TAB | JV_PRINT_PRETTY : (n) == 0 ? 0 : (n) << 8 | JV_PRINT_PRETTY) +jv jv_dump_options(jv); void jv_dumpf(jv, FILE *f, int flags); void jv_dump(jv, int flags); void jv_show(jv, int flags); jv jv_dump_string(jv, int flags); char *jv_dump_string_trunc(jv x, char *outbuf, size_t bufsize); -enum { +enum jv_parse_flags { + JV_PARSE_PLAIN = 0, JV_PARSE_SEQ = 1, JV_PARSE_STREAMING = 2, JV_PARSE_STREAM_ERRORS = 4, + JV_PARSE_RAW = 8, }; +jv jv_parse_options(jv); jv jv_parse(const char* string); jv jv_parse_sized(const char* string, int length); @@ -251,7 +257,9 @@ jv jv_keys_unsorted(jv /*object or array*/); int jv_cmp(jv, jv); jv jv_group(jv, jv); jv jv_sort(jv, jv); - +jv jv_number_random_int(void); +jv jv_number_random_bytes(size_t); +jv jv_number_random_string(size_t); #endif diff --git a/src/jv_alloc.c b/src/jv_alloc.c index 5fa6768482..9fd7463aea 100644 --- a/src/jv_alloc.c +++ b/src/jv_alloc.c @@ -120,7 +120,7 @@ static void memory_exhausted() { void* jv_mem_alloc(size_t sz) { void* p = malloc(sz); - if (!p) { + if (!p && sz) { memory_exhausted(); } return p; @@ -132,7 +132,7 @@ void* jv_mem_alloc_unguarded(size_t sz) { void* jv_mem_calloc(size_t nemb, size_t sz) { void* p = calloc(nemb, sz); - if (!p) { + if (!p && sz) { memory_exhausted(); } return p; @@ -160,7 +160,7 @@ void jv_mem_free(void* p) { void* jv_mem_realloc(void* p, size_t sz) { p = realloc(p, sz); - if (!p) { + if (!p && sz) { memory_exhausted(); } return p; diff --git a/src/jv_aux.c b/src/jv_aux.c index eca2345fec..e29177bb10 100644 --- a/src/jv_aux.c +++ b/src/jv_aux.c @@ -1,8 +1,20 @@ +#include #include #include -#include + +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#endif + +#include "jv.h" #include "jv_alloc.h" #include "jv_type_private.h" +#include "jv_unicode.h" // making this static verbose function here // until we introduce a less confusing naming scheme @@ -656,3 +668,142 @@ jv jv_group(jv objects, jv keys) { jv_mem_free(entries); return ret; } + +static int random_fill_buffer(unsigned char *buf, size_t sz) { +#ifdef WIN32 + if (BCryptGenRandom(NULL, buf, sz, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) + return 1; +#else + int fd = open("/dev/urandom", O_RDONLY); + ssize_t n = -1; + + if (fd > -1) { + n = read(fd, buf, sz); + (void) close(fd); + } + if (n > -1 && sz == (size_t)n) + return 1; +#endif + return 0; +} + +jv jv_number_random_int(void) { + unsigned char buf[7]; + + if (!random_fill_buffer(buf, sizeof(buf))) + return jv_invalid_with_msg(jv_string("Could not generate random numbers")); + return jv_number(( (uint64_t)buf[0] | + (uint64_t)buf[1] << 8 | + (uint64_t)buf[2] << 16 | + (uint64_t)buf[3] << 24 | + (uint64_t)buf[4] << 32 | + (uint64_t)buf[5] << 40 | + ((uint64_t)buf[6] & 0x7) << 48)); +} + +jv jv_number_random_bytes(size_t n) { + unsigned char buf[64]; + jv ret = jv_array(); + + while (n > 0) { + size_t r = n > sizeof(buf) ? sizeof(buf) : n; + if (!random_fill_buffer(buf, r)) { + jv_free(ret); + return jv_invalid_with_msg(jv_string("Could not generate random numbers")); + } + n -= r; + for (size_t i = 0; i < r; i++) + ret = jv_array_append(ret, jv_number(buf[i])); + } + return ret; +} + +jv jv_number_random_string(size_t n) { + jv ret = jv_string(""); + + n *= 2; + while (n > 0) { + unsigned char buf[64]; + size_t r = n > sizeof(buf) ? sizeof(buf) : n; + if (!random_fill_buffer(buf, r)) { + jv_free(ret); + return jv_invalid_with_msg(jv_string("Could not generate random numbers")); + } + n -= r; + for (size_t i = 0; i < r; i+=2) { + char u8[8]; /* 4 is enough */ + int len = jvp_utf8_encode(buf[i] << 8 | buf[i+1], u8); + ret = jv_string_concat(ret, jv_string_sized(u8, len)); + } + } + return ret; +} + +jv jv_parse_options(jv opts) { + if (jv_get_kind(opts) == JV_KIND_NULL || + (jv_get_kind(opts) == JV_KIND_INVALID && !jv_invalid_has_msg(jv_copy(opts)))) { + jv_free(opts); + return jv_number(0); + } + if (jv_get_kind(opts) == JV_KIND_STRING) + opts = JV_ARRAY(opts); + if (jv_get_kind(opts) != JV_KIND_ARRAY) { + jv_free(opts); + return jv_invalid_with_msg(jv_string("invalid file input options")); + } + enum jv_parse_flags o = 0; + jv_array_foreach(opts, i, opt) { + if (jv_equal(jv_copy(opt), jv_string("seq"))) + o |= JV_PARSE_SEQ; + else if (jv_equal(jv_copy(opt), jv_string("stream"))) + o |= JV_PARSE_STREAMING; + else if (jv_equal(jv_copy(opt), jv_string("streamerrors"))) + o |= JV_PARSE_STREAM_ERRORS; + else if (jv_equal(jv_copy(opt), jv_string("raw"))) + o |= JV_PARSE_RAW; + jv_free(opt); + } + jv_free(opts); + return jv_number(o); +} + +jv jv_dump_options(jv opts) { + if (jv_get_kind(opts) == JV_KIND_NULL) + return jv_number(0); + if (jv_get_kind(opts) == JV_KIND_STRING) + opts = JV_ARRAY(opts); + if (jv_get_kind(opts) != JV_KIND_ARRAY) { + jv_free(opts); + return jv_invalid_with_msg(jv_string("invalid file output options")); + } + enum jv_parse_flags o = 0; + jv_array_foreach(opts, i, opt) { + if (jv_equal(jv_copy(opt), jv_string("pretty"))) + o |= JV_PRINT_PRETTY; + else if (jv_equal(jv_copy(opt), jv_string("ascii"))) + o |= JV_PRINT_ASCII; + else if (jv_equal(jv_copy(opt), jv_string("color"))) + o |= JV_PRINT_COLOR; + else if (jv_equal(jv_copy(opt), jv_string("colour"))) + o |= JV_PRINT_COLOUR; + else if (jv_equal(jv_copy(opt), jv_string("sorted"))) + o |= JV_PRINT_SORTED; + else if (jv_equal(jv_copy(opt), jv_string("tab"))) + o |= JV_PRINT_TAB; + else if (jv_equal(jv_copy(opt), jv_string("isatty"))) + o |= JV_PRINT_ISATTY; + else if (jv_equal(jv_copy(opt), jv_string("raw"))) + o |= JV_PRINT_RAW; + else if (jv_equal(jv_copy(opt), jv_string("nolf"))) + o |= JV_PRINT_NOLF; + else if (jv_get_kind(opt) == JV_KIND_NUMBER) { + /* Indent by N spaces */ + int n = jv_number_value(opt); + o |= JV_PRINT_INDENT_FLAGS(n); + } + jv_free(opt); + } + jv_free(opts); + return jv_number(o); +} diff --git a/src/jv_dtoa_tsd.c b/src/jv_dtoa_tsd.c index 0f95df4f18..b2bf105a80 100644 --- a/src/jv_dtoa_tsd.c +++ b/src/jv_dtoa_tsd.c @@ -10,7 +10,8 @@ static pthread_key_t dtoa_ctx_key; static pthread_once_t dtoa_ctx_once = PTHREAD_ONCE_INIT; -static void tsd_dtoa_ctx_dtor(struct dtoa_context *ctx) { +static void tsd_dtoa_ctx_dtor(void *d) { + struct dtoa_context *ctx = d; if (ctx) { jvp_dtoa_context_free(ctx); jv_mem_free(ctx); @@ -43,4 +44,4 @@ inline struct dtoa_context *tsd_dtoa_context_get() { } } return ctx; -} \ No newline at end of file +} diff --git a/src/jv_print.c b/src/jv_print.c index 2e781bb8b4..e551108d16 100644 --- a/src/jv_print.c +++ b/src/jv_print.c @@ -185,9 +185,9 @@ static void jvp_dump_string(jv str, int ascii_only, FILE* F, jv* S, int T) { static void put_refcnt(struct dtoa_context* C, int refcnt, FILE *F, jv* S, int T){ char buf[JVP_DTOA_FMT_MAX_LEN]; put_char(' ', F, S, T); - put_char('(', F, S, T); + put_char('<', F, S, T); put_str(jvp_dtoa_fmt(C, buf, refcnt), F, S, T); - put_char(')', F, S, T); + put_char('>', F, S, T); } static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FILE* F, jv* S) { @@ -257,11 +257,13 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI break; } case JV_KIND_STRING: - jvp_dump_string(x, flags & JV_PRINT_ASCII, F, S, flags & JV_PRINT_ISATTY); if (flags & JV_PRINT_REFCOUNT) put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); + jvp_dump_string(x, flags & JV_PRINT_ASCII, F, S, flags & JV_PRINT_ISATTY); break; case JV_KIND_ARRAY: { + if (flags & JV_PRINT_REFCOUNT) + put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); if (jv_array_length(jv_copy(x)) == 0) { put_str("[]", F, S, flags & JV_PRINT_ISATTY); break; @@ -289,11 +291,11 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI } if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); put_char(']', F, S, flags & JV_PRINT_ISATTY); - if (flags & JV_PRINT_REFCOUNT) - put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); break; } case JV_KIND_OBJECT: { + if (flags & JV_PRINT_REFCOUNT) + put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); if (jv_object_length(jv_copy(x)) == 0) { put_str("{}", F, S, flags & JV_PRINT_ISATTY); break; @@ -361,8 +363,6 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI } if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); put_char('}', F, S, flags & JV_PRINT_ISATTY); - if (flags & JV_PRINT_REFCOUNT) - put_refcnt(C, refcnt, F, S, flags & JV_PRINT_ISATTY); } } jv_free(x); diff --git a/src/lexer.c b/src/lexer.c index cd2012f1ab..183a855eef 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1,6 +1,6 @@ -#line 2 "src/lexer.c" +#line 1 "src/lexer.c" -#line 4 "src/lexer.c" +#line 3 "src/lexer.c" #define YY_INT_ALIGNED short int @@ -573,8 +573,8 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 50 -#define YY_END_OF_BUFFER 51 +#define YY_NUM_RULES 53 +#define YY_END_OF_BUFFER 54 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -582,25 +582,26 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[157] = +static const flex_int16_t yy_accept[163] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 51, 49, 48, 48, 49, 40, 1, 35, - 35, 36, 37, 35, 35, 35, 35, 35, 39, 35, - 35, 35, 35, 49, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 35, 44, - 44, 42, 45, 48, 2, 1, 29, 27, 25, 26, - 33, 39, 47, 47, 18, 28, 0, 31, 3, 32, - 0, 38, 46, 0, 46, 46, 4, 46, 46, 46, - 46, 46, 46, 9, 46, 46, 46, 46, 14, 46, - 46, 46, 24, 44, 43, 41, 43, 47, 0, 39, - - 30, 39, 34, 0, 46, 13, 46, 46, 8, 46, - 46, 15, 46, 46, 46, 46, 46, 46, 46, 19, - 0, 43, 46, 46, 46, 46, 12, 11, 46, 46, - 46, 46, 46, 46, 10, 43, 46, 22, 20, 46, - 46, 46, 21, 46, 46, 43, 46, 46, 5, 46, - 7, 16, 23, 17, 6, 0 + 0, 0, 54, 52, 51, 51, 52, 43, 1, 38, + 38, 39, 40, 38, 38, 38, 38, 38, 42, 38, + 38, 38, 38, 52, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 38, 47, + 47, 45, 48, 51, 2, 1, 31, 29, 27, 28, + 35, 42, 50, 50, 19, 30, 0, 33, 3, 34, + 25, 0, 41, 37, 49, 0, 49, 49, 4, 49, + 49, 49, 49, 49, 49, 49, 10, 49, 49, 49, + 49, 15, 49, 49, 49, 26, 47, 46, 44, 46, + + 50, 0, 42, 32, 42, 36, 0, 49, 14, 49, + 49, 49, 8, 49, 49, 16, 49, 49, 49, 49, + 49, 49, 49, 20, 0, 46, 49, 49, 49, 49, + 49, 13, 12, 49, 49, 49, 49, 49, 49, 11, + 46, 49, 23, 21, 9, 49, 49, 49, 22, 49, + 49, 46, 49, 49, 5, 49, 7, 17, 24, 18, + 6, 0 } ; static const YY_CHAR yy_ec[256] = @@ -639,144 +640,148 @@ static const YY_CHAR yy_meta[54] = { 0, 1, 1, 2, 2, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 5, 6, 1, - 1, 1, 1, 1, 1, 7, 7, 1, 8, 1, - 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 1, 1, 1, 1, 7, 8, 8, 1, 9, 1, + 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1 } ; -static const flex_int16_t yy_base[170] = +static const flex_int16_t yy_base[176] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 51, 52, 320, 321, 57, 59, 297, 321, 0, 321, - 296, 321, 321, 295, 294, 293, 47, 47, 50, 292, - 291, 290, 294, 0, 291, 48, 51, 53, 52, 37, - 59, 57, 66, 56, 63, 68, 70, 72, 287, 0, - 0, 321, 80, 90, 321, 0, 321, 321, 321, 321, - 95, 99, 0, 106, 286, 321, 110, 321, 321, 321, - 290, 0, 285, 281, 86, 77, 277, 97, 101, 111, - 113, 115, 117, 274, 119, 120, 118, 121, 270, 122, - 123, 124, 321, 0, 257, 321, 255, 0, 254, 249, - - 321, 245, 321, 0, 125, 239, 126, 127, 237, 128, - 134, 234, 136, 143, 147, 148, 149, 152, 154, 232, - 165, 212, 210, 157, 159, 158, 209, 208, 160, 161, - 162, 163, 164, 166, 207, 196, 171, 205, 204, 174, - 167, 175, 201, 170, 176, 190, 190, 184, 199, 194, - 198, 197, 85, 78, 76, 321, 230, 239, 245, 250, - 255, 264, 273, 278, 283, 285, 290, 294, 298 + 51, 52, 336, 337, 57, 59, 313, 337, 0, 337, + 312, 337, 337, 311, 310, 309, 47, 47, 50, 308, + 307, 45, 311, 302, 307, 51, 52, 54, 57, 56, + 53, 59, 65, 66, 60, 68, 69, 71, 303, 0, + 0, 337, 81, 108, 337, 0, 337, 337, 337, 337, + 97, 100, 0, 107, 302, 337, 108, 337, 337, 337, + 337, 304, 295, 337, 297, 296, 87, 100, 292, 93, + 112, 113, 115, 118, 119, 120, 291, 122, 121, 123, + 124, 288, 126, 127, 125, 337, 0, 274, 337, 273, + + 0, 281, 279, 337, 278, 337, 0, 128, 264, 130, + 134, 145, 258, 132, 151, 254, 152, 139, 154, 155, + 131, 157, 158, 252, 168, 238, 245, 160, 163, 166, + 165, 242, 240, 167, 170, 171, 173, 174, 177, 239, + 218, 178, 215, 214, 213, 179, 181, 186, 211, 188, + 189, 199, 191, 193, 208, 199, 207, 204, 200, 74, + 37, 337, 235, 245, 252, 258, 264, 274, 284, 290, + 296, 298, 304, 309, 314 } ; -static const flex_int16_t yy_def[170] = +static const flex_int16_t yy_def[176] = { 0, - 156, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 157, 157, 156, 156, 156, 156, 156, 156, 158, 156, - 156, 156, 156, 156, 156, 156, 159, 156, 156, 156, - 156, 156, 156, 160, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, 156, 162, - 162, 156, 163, 156, 156, 158, 156, 156, 156, 156, - 156, 156, 164, 164, 156, 156, 156, 156, 156, 156, - 156, 160, 161, 156, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 156, 162, 156, 156, 165, 164, 156, 164, - - 156, 156, 156, 166, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, - 163, 167, 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 168, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 169, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 0, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156 + 162, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 163, 163, 162, 162, 162, 162, 162, 162, 164, 162, + 162, 162, 162, 162, 162, 162, 165, 162, 162, 162, + 162, 162, 162, 166, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 162, 168, + 168, 162, 169, 162, 162, 164, 162, 162, 162, 162, + 162, 162, 170, 170, 162, 162, 162, 162, 162, 162, + 162, 162, 166, 162, 167, 162, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 162, 168, 162, 162, 171, + + 170, 162, 170, 162, 162, 162, 172, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 169, 173, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 174, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 175, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 0, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162 } ; -static const flex_int16_t yy_nxt[375] = +static const flex_int16_t yy_nxt[391] = { 0, 14, 15, 16, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 20, 26, 27, 28, 29, 20, 20, 30, 31, 32, 33, 34, 35, 35, 22, 14, 23, 36, 37, 38, 39, 40, 41, 42, 35, 43, 35, 44, 45, 35, 46, 35, 47, 35, 48, 35, 35, - 22, 49, 23, 51, 51, 74, 52, 52, 54, 54, - 54, 54, 61, 65, 62, 62, 74, 62, 66, 74, - 74, 74, 80, 64, 74, 74, 67, 74, 75, 53, - 53, 74, 64, 79, 74, 67, 74, 87, 74, 96, - 74, 54, 54, 76, 74, 74, 74, 77, 78, 81, - - 83, 82, 84, 74, 74, 90, 88, 85, 86, 91, - 62, 106, 62, 89, 62, 74, 62, 92, 99, 74, - 99, 67, 99, 100, 99, 67, 105, 102, 97, 74, - 67, 74, 107, 74, 67, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 109, 108, 112, - 116, 110, 74, 115, 74, 117, 118, 125, 119, 111, - 126, 74, 113, 114, 127, 74, 74, 74, 124, 128, - 74, 129, 74, 120, 156, 74, 74, 74, 74, 74, - 74, 74, 74, 132, 74, 74, 130, 131, 74, 74, - 137, 140, 74, 74, 74, 139, 135, 133, 138, 145, - - 134, 147, 74, 143, 144, 151, 141, 148, 74, 150, - 142, 152, 74, 97, 149, 74, 74, 74, 121, 74, - 153, 154, 74, 74, 121, 74, 74, 74, 74, 155, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 56, - 121, 56, 56, 56, 56, 56, 56, 56, 63, 63, - 74, 63, 74, 63, 72, 74, 72, 74, 72, 73, - 73, 73, 102, 73, 94, 94, 100, 94, 94, 94, - 94, 102, 94, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 98, 121, 98, 121, 98, 122, 74, 122, - 122, 123, 74, 123, 136, 74, 136, 136, 146, 104, - - 146, 146, 95, 74, 95, 95, 103, 101, 93, 74, - 71, 70, 69, 68, 60, 59, 58, 57, 55, 156, - 13, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156 + 22, 49, 23, 51, 51, 76, 52, 52, 54, 54, + 54, 54, 61, 65, 62, 62, 70, 62, 66, 76, + 76, 76, 76, 64, 76, 76, 67, 76, 76, 53, + 53, 77, 64, 76, 76, 67, 76, 76, 81, 76, + 99, 83, 76, 84, 78, 85, 71, 90, 79, 80, + + 82, 87, 86, 91, 93, 76, 88, 89, 94, 54, + 54, 76, 62, 92, 62, 62, 95, 62, 76, 102, + 102, 102, 102, 67, 103, 105, 67, 108, 110, 100, + 76, 76, 67, 76, 109, 67, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 112, 76, 76, + 76, 113, 76, 116, 119, 120, 114, 76, 121, 111, + 122, 129, 123, 76, 115, 117, 118, 130, 132, 76, + 76, 128, 76, 76, 124, 76, 76, 162, 76, 138, + 131, 76, 135, 76, 76, 76, 133, 134, 76, 76, + 137, 76, 76, 142, 136, 76, 76, 76, 146, 76, + + 140, 145, 143, 144, 76, 139, 76, 76, 153, 76, + 151, 76, 154, 149, 150, 147, 100, 76, 76, 148, + 156, 159, 76, 157, 158, 76, 76, 125, 155, 76, + 160, 76, 76, 76, 161, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 56, 125, 56, 56, 56, + 56, 56, 56, 56, 56, 63, 63, 76, 76, 63, + 76, 63, 73, 76, 73, 73, 125, 73, 75, 75, + 76, 75, 76, 75, 97, 97, 76, 97, 97, 97, + 97, 97, 76, 97, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 101, 105, 103, 101, 105, 101, + + 126, 125, 125, 126, 126, 127, 76, 127, 141, 76, + 76, 141, 141, 152, 107, 76, 152, 152, 98, 162, + 106, 98, 98, 104, 96, 76, 74, 72, 69, 68, + 60, 59, 58, 57, 55, 162, 13, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162 } ; -static const flex_int16_t yy_chk[375] = +static const flex_int16_t yy_chk[391] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 11, 12, 40, 11, 12, 15, 15, - 16, 16, 27, 28, 27, 29, 36, 29, 28, 37, - 39, 38, 40, 27, 44, 42, 29, 41, 36, 11, - 12, 45, 27, 39, 43, 29, 46, 44, 47, 53, - 48, 54, 54, 37, 155, 76, 154, 37, 38, 41, - - 42, 41, 43, 153, 75, 47, 45, 43, 43, 48, - 61, 76, 61, 46, 62, 78, 62, 48, 64, 79, - 64, 61, 67, 64, 67, 62, 75, 67, 53, 80, - 61, 81, 78, 82, 62, 83, 87, 85, 86, 88, - 90, 91, 92, 105, 107, 108, 110, 80, 79, 82, - 87, 81, 111, 86, 113, 88, 90, 107, 91, 81, - 108, 114, 83, 85, 110, 115, 116, 117, 105, 111, - 118, 113, 119, 92, 121, 124, 126, 125, 129, 130, - 131, 132, 133, 116, 134, 141, 114, 115, 144, 137, - 124, 129, 140, 142, 145, 126, 119, 117, 125, 134, - - 118, 137, 148, 132, 133, 144, 130, 140, 147, 142, - 131, 145, 150, 121, 141, 152, 151, 149, 146, 143, - 147, 148, 139, 138, 136, 135, 128, 127, 123, 150, - 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, - 122, 158, 158, 158, 158, 158, 158, 158, 159, 159, - 120, 159, 112, 159, 160, 109, 160, 106, 160, 161, - 161, 161, 102, 161, 162, 162, 100, 162, 162, 162, - 162, 99, 162, 163, 163, 163, 163, 163, 163, 163, - 163, 163, 164, 97, 164, 95, 164, 165, 89, 165, - 165, 166, 84, 166, 167, 77, 167, 167, 168, 74, - - 168, 168, 169, 73, 169, 169, 71, 65, 49, 35, - 33, 32, 31, 30, 26, 25, 24, 21, 17, 13, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156 + 1, 1, 1, 11, 12, 161, 11, 12, 15, 15, + 16, 16, 27, 28, 27, 29, 32, 29, 28, 36, + 37, 41, 38, 27, 40, 39, 29, 42, 45, 11, + 12, 36, 27, 43, 44, 29, 46, 47, 39, 48, + 53, 40, 160, 41, 37, 41, 32, 44, 37, 38, + + 39, 43, 42, 45, 47, 77, 43, 43, 48, 54, + 54, 80, 61, 46, 61, 62, 48, 62, 78, 64, + 67, 64, 67, 61, 64, 67, 62, 77, 80, 53, + 81, 82, 61, 83, 78, 62, 84, 85, 86, 89, + 88, 90, 91, 95, 93, 94, 108, 82, 110, 121, + 114, 83, 111, 85, 89, 90, 84, 118, 91, 81, + 93, 110, 94, 112, 84, 86, 88, 111, 114, 115, + 117, 108, 119, 120, 95, 122, 123, 125, 128, 121, + 112, 129, 118, 131, 130, 134, 115, 117, 135, 136, + 120, 137, 138, 128, 119, 139, 142, 146, 134, 147, + + 123, 131, 129, 130, 148, 122, 150, 151, 142, 153, + 139, 154, 146, 137, 138, 135, 125, 156, 159, 136, + 148, 153, 158, 150, 151, 157, 155, 152, 147, 149, + 154, 145, 144, 143, 156, 163, 163, 163, 163, 163, + 163, 163, 163, 163, 163, 164, 141, 164, 164, 164, + 164, 164, 164, 164, 164, 165, 165, 140, 133, 165, + 132, 165, 166, 127, 166, 166, 126, 166, 167, 167, + 124, 167, 116, 167, 168, 168, 113, 168, 168, 168, + 168, 168, 109, 168, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 170, 105, 103, 170, 102, 170, + + 171, 100, 98, 171, 171, 172, 92, 172, 173, 87, + 79, 173, 173, 174, 76, 75, 174, 174, 175, 73, + 72, 175, 175, 65, 49, 35, 34, 33, 31, 30, + 26, 25, 24, 21, 17, 13, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162 } ; /* The intent behind this definition is that it'll catch @@ -803,14 +808,14 @@ struct lexer_param; yyset_extra(yylloc->end, yyscanner); \ } while (0); -#line 807 "src/lexer.c" +#line 811 "src/lexer.c" #line 25 "src/lexer.l" static int enter(int opening, int state, yyscan_t yyscanner); static int try_exit(int closing, int state, yyscan_t yyscanner); -#line 812 "src/lexer.c" +#line 816 "src/lexer.c" #define YY_NO_INPUT 1 -#line 814 "src/lexer.c" +#line 818 "src/lexer.c" #define INITIAL 0 #define IN_PAREN 1 @@ -1104,7 +1109,7 @@ YY_DECL #line 38 "src/lexer.l" -#line 1108 "src/lexer.c" +#line 1112 "src/lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1131,13 +1136,13 @@ YY_DECL while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 157 ) + if ( yy_current_state >= 163 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 321 ); + while ( yy_base[yy_current_state] != 337 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -1204,194 +1209,209 @@ YY_RULE_SETUP case 9: YY_RULE_SETUP #line 49 "src/lexer.l" -{ return IF; } +{ return CODEF; } YY_BREAK case 10: YY_RULE_SETUP #line 50 "src/lexer.l" -{ return THEN; } +{ return IF; } YY_BREAK case 11: YY_RULE_SETUP #line 51 "src/lexer.l" -{ return ELSE; } +{ return THEN; } YY_BREAK case 12: YY_RULE_SETUP #line 52 "src/lexer.l" -{ return ELSE_IF; } +{ return ELSE; } YY_BREAK case 13: YY_RULE_SETUP #line 53 "src/lexer.l" -{ return AND; } +{ return ELSE_IF; } YY_BREAK case 14: YY_RULE_SETUP #line 54 "src/lexer.l" -{ return OR; } +{ return AND; } YY_BREAK case 15: YY_RULE_SETUP #line 55 "src/lexer.l" -{ return END; } +{ return OR; } YY_BREAK case 16: YY_RULE_SETUP #line 56 "src/lexer.l" -{ return REDUCE; } +{ return END; } YY_BREAK case 17: YY_RULE_SETUP #line 57 "src/lexer.l" -{ return FOREACH; } +{ return REDUCE; } YY_BREAK case 18: YY_RULE_SETUP #line 58 "src/lexer.l" -{ return DEFINEDOR; } +{ return FOREACH; } YY_BREAK case 19: YY_RULE_SETUP #line 59 "src/lexer.l" -{ return TRY; } +{ return DEFINEDOR; } YY_BREAK case 20: YY_RULE_SETUP #line 60 "src/lexer.l" -{ return CATCH; } +{ return TRY; } YY_BREAK case 21: YY_RULE_SETUP #line 61 "src/lexer.l" -{ return LABEL; } +{ return CATCH; } YY_BREAK case 22: YY_RULE_SETUP #line 62 "src/lexer.l" -{ return BREAK; } +{ return LABEL; } YY_BREAK case 23: YY_RULE_SETUP #line 63 "src/lexer.l" -{ return LOC; } +{ return BREAK; } YY_BREAK case 24: YY_RULE_SETUP #line 64 "src/lexer.l" -{ return SETPIPE; } +{ return LOC; } YY_BREAK case 25: YY_RULE_SETUP #line 65 "src/lexer.l" -{ return SETPLUS; } +{ return HIGHPRECPIPE; } YY_BREAK case 26: YY_RULE_SETUP #line 66 "src/lexer.l" -{ return SETMINUS; } +{ return SETPIPE; } YY_BREAK case 27: YY_RULE_SETUP #line 67 "src/lexer.l" -{ return SETMULT; } +{ return SETPLUS; } YY_BREAK case 28: YY_RULE_SETUP #line 68 "src/lexer.l" -{ return SETDIV; } +{ return SETMINUS; } YY_BREAK case 29: YY_RULE_SETUP #line 69 "src/lexer.l" -{ return SETMOD; } +{ return SETMULT; } YY_BREAK case 30: YY_RULE_SETUP #line 70 "src/lexer.l" -{ return SETDEFINEDOR; } +{ return SETDIV; } YY_BREAK case 31: YY_RULE_SETUP #line 71 "src/lexer.l" -{ return LESSEQ; } +{ return SETMOD; } YY_BREAK case 32: YY_RULE_SETUP #line 72 "src/lexer.l" -{ return GREATEREQ; } +{ return SETDEFINEDOR; } YY_BREAK case 33: YY_RULE_SETUP #line 73 "src/lexer.l" -{ return REC; } +{ return LESSEQ; } YY_BREAK case 34: YY_RULE_SETUP #line 74 "src/lexer.l" -{ return ALTERNATION; } +{ return GREATEREQ; } YY_BREAK case 35: YY_RULE_SETUP #line 75 "src/lexer.l" -{ return yytext[0];} +{ return REC; } YY_BREAK case 36: YY_RULE_SETUP +#line 76 "src/lexer.l" +{ return ALTERNATION; } + YY_BREAK +case 37: +YY_RULE_SETUP #line 77 "src/lexer.l" +{ return COEXPR; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 78 "src/lexer.l" +{ return yytext[0];} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 80 "src/lexer.l" { return enter(yytext[0], YY_START, yyscanner); } YY_BREAK -case 37: +case 40: YY_RULE_SETUP -#line 81 "src/lexer.l" +#line 84 "src/lexer.l" { return try_exit(yytext[0], YY_START, yyscanner); } YY_BREAK -case 38: +case 41: YY_RULE_SETUP -#line 85 "src/lexer.l" +#line 88 "src/lexer.l" { yylval->literal = jv_string_sized(yytext + 1, yyleng - 1); return FORMAT; } YY_BREAK -case 39: +case 42: YY_RULE_SETUP -#line 89 "src/lexer.l" +#line 92 "src/lexer.l" { yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; } YY_BREAK -case 40: +case 43: YY_RULE_SETUP -#line 93 "src/lexer.l" +#line 96 "src/lexer.l" { yy_push_state(IN_QQSTRING, yyscanner); return QQSTRING_START; } YY_BREAK -case 41: +case 44: YY_RULE_SETUP -#line 99 "src/lexer.l" +#line 102 "src/lexer.l" { return enter(QQSTRING_INTERP_START, YY_START, yyscanner); } YY_BREAK -case 42: +case 45: YY_RULE_SETUP -#line 102 "src/lexer.l" +#line 105 "src/lexer.l" { yy_pop_state(yyscanner); return QQSTRING_END; } YY_BREAK -case 43: -/* rule 43 can match eol */ +case 46: +/* rule 46 can match eol */ YY_RULE_SETUP -#line 106 "src/lexer.l" +#line 109 "src/lexer.l" { /* pass escapes to the json parser */ jv escapes = jv_string_fmt("\"%.*s\"", (int)yyleng, yytext); @@ -1400,50 +1420,50 @@ YY_RULE_SETUP return QQSTRING_TEXT; } YY_BREAK -case 44: -/* rule 44 can match eol */ +case 47: +/* rule 47 can match eol */ YY_RULE_SETUP -#line 113 "src/lexer.l" +#line 116 "src/lexer.l" { yylval->literal = jv_string_sized(yytext, yyleng); return QQSTRING_TEXT; } YY_BREAK -case 45: +case 48: YY_RULE_SETUP -#line 117 "src/lexer.l" +#line 120 "src/lexer.l" { return INVALID_CHARACTER; } YY_BREAK -case 46: +case 49: YY_RULE_SETUP -#line 123 "src/lexer.l" +#line 126 "src/lexer.l" { yylval->literal = jv_string(yytext); return IDENT;} YY_BREAK -case 47: +case 50: YY_RULE_SETUP -#line 124 "src/lexer.l" +#line 127 "src/lexer.l" { yylval->literal = jv_string(yytext+1); return FIELD;} YY_BREAK -case 48: -/* rule 48 can match eol */ +case 51: +/* rule 51 can match eol */ YY_RULE_SETUP -#line 126 "src/lexer.l" +#line 129 "src/lexer.l" {} YY_BREAK -case 49: +case 52: YY_RULE_SETUP -#line 128 "src/lexer.l" +#line 131 "src/lexer.l" { return INVALID_CHARACTER; } YY_BREAK -case 50: +case 53: YY_RULE_SETUP -#line 130 "src/lexer.l" +#line 133 "src/lexer.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK -#line 1447 "src/lexer.c" +#line 1466 "src/lexer.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(IN_PAREN): case YY_STATE_EOF(IN_BRACKET): @@ -1747,7 +1767,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 157 ) + if ( yy_current_state >= 163 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1776,11 +1796,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 157 ) + if ( yy_current_state >= 163 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 156); + yy_is_jam = (yy_current_state == 162); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -2615,7 +2635,7 @@ static int yy_flex_strlen (const char * s , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 130 "src/lexer.l" +#line 133 "src/lexer.l" /* perhaps these should be calls... */ /* diff --git a/src/lexer.h b/src/lexer.h index 8ad2a44ba6..2a351a63d1 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -2,9 +2,9 @@ #define jq_yyHEADER_H 1 #define jq_yyIN_HEADER 1 -#line 6 "src/lexer.h" +#line 5 "src/lexer.h" -#line 8 "src/lexer.h" +#line 7 "src/lexer.h" #define YY_INT_ALIGNED short int @@ -731,9 +731,9 @@ extern int yylex \ #undef yyTABLES_NAME #endif -#line 130 "src/lexer.l" +#line 133 "src/lexer.l" -#line 738 "src/lexer.h" +#line 737 "src/lexer.h" #undef jq_yyIN_HEADER #endif /* jq_yyHEADER_H */ diff --git a/src/lexer.l b/src/lexer.l index 6b9164bf28..c472f0f376 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -46,6 +46,7 @@ struct lexer_param; "include" { return INCLUDE; } "module" { return MODULE; } "def" { return DEF; } +"codef" { return CODEF; } "if" { return IF; } "then" { return THEN; } "else" { return ELSE; } @@ -61,6 +62,7 @@ struct lexer_param; "label" { return LABEL; } "break" { return BREAK; } "__loc__" { return LOC; } +">|" { return HIGHPRECPIPE; } "|=" { return SETPIPE; } "+=" { return SETPLUS; } "-=" { return SETMINUS; } @@ -72,6 +74,7 @@ struct lexer_param; ">=" { return GREATEREQ; } ".." { return REC; } "?//" { return ALTERNATION; } +"@@" { return COEXPR; } "."|"?"|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"%"|"\$"|"<"|">" { return yytext[0];} "["|"{"|"(" { diff --git a/src/linker.c b/src/linker.c index 962bdc14d2..ced67066c2 100644 --- a/src/linker.c +++ b/src/linker.c @@ -16,16 +16,91 @@ #include "locfile.h" #include "jv.h" #include "jq.h" +#include "jq.h" +#include "linker.h" #include "parser.h" #include "util.h" +#include "builtin_modules.h" #include "compile.h" #include "jv_alloc.h" +#ifdef WIN32 +#include +#include +#include + +typedef union { + HMODULE dl_handle; + struct jq_builtin_module *bmodule; +} jq_dl_handle; + +char *jq_dl_error() { +#ifdef _MSC_VER + static __declspec(thread) char *s = 0; +#else + static __thread char *s = 0; +#endif /* _MSC_VER */ + + LocalFree(s); + s = 0; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + 0, GetLastError(), 0, (LPTSTR) &s, 0, 0); + return s; +} +#define JQ_DL_OPEN(name) LoadLibraryA(name) +#define JQ_DL_CLOSE(h) FreeLibrary(h) +#define JQ_DL_SYM(h, sym) GetProcAddress(h, sym) +#define JQ_DL_ERROR() jq_dl_error() + +#elif defined(HAVE_DLOPEN) +#include + +#ifndef RTLD_GROUP +#define RTLD_GROUP 0 +#endif + +typedef union { + void *dl_handle; + struct jq_builtin_module *bmodule; +} jq_dl_handle; +#define JQ_DL_OPEN(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP) +#define JQ_DL_CLOSE(h) dlclose(h) +#define JQ_DL_SYM(h, sym) dlsym(h, sym) +#define JQ_DL_ERROR() dlerror() + +#else + +typedef union { + void *dl_handle; + struct jq_builtin_module *bmodule; +} jq_dl_handle; +#define JQ_DL_OPEN(name) (NULL) +#define JQ_DL_CLOSE(h) +#define JQ_DL_SYM(h, sym) (NULL) + +#endif + +typedef void *(*jq_dl_sym_f)(jq_dl_handle, const char *); +typedef void (*jq_dl_close_f)(jq_dl_handle); + +struct jq_lib { + jv jname; + jv jbasename; /* basename() of jname */ + jv origin; /* dirname() of jname */ + jv contents; /* jq code or JSON text */ + const char *name; /* jv_string_value(jname) */ + block defs; /* parsed library program */ + jq_dl_handle h; + jq_dl_sym_f dl_sym; + jq_dl_close_f dl_close; + struct cfunction *cfuncs; + size_t ncfuncs; +}; struct lib_loading_state { - char **names; - block *defs; - uint64_t ct; + struct jq_lib *libs; + size_t nlibs; }; + static int load_library(jq_state *jq, jv lib_path, int is_data, int raw, int optional, const char *as, block *out_block, @@ -132,23 +207,115 @@ static jv jv_basename(jv name) { return res; } +static jv load_file(jv path, int raw) { + /* + * For now. Change this in 1.8. + */ + jv contents = jv_load_file(jv_string_value(path), raw); + if (strncmp(jv_string_value(path), "jq/", sizeof("jq/") - 1) != 0) + return contents; + + if (jv_is_valid(contents)) { + if (strncmp(jv_string_value(path), "jq/", sizeof("jq/") - 1) == 0) + fprintf(stderr, "jq: warning: the module name prefix \"jq/\" is reserved for builtin modules\n"); + return contents; + } + + contents = jv_invalid_has_msg(jv_copy(contents)) ? + jv_invalid_get_msg(contents) : jv_string(""); + + jv ret; + for (size_t i = 0; i < jq_builtin_nmodules; i++) { + if (strcmp(jq_builtin_modules[i].name, jv_string_value(path))) + continue; + if (!raw) { + ret = jv_invalid_with_msg(jv_string_fmt("Builtin jq module %s is not JSON; %s", + jv_string_value(path), jv_string_value(contents))); + jv_free(contents); + return ret; + } + jv_free(contents); + return jv_string(jq_builtin_modules[i].contents); + } + ret = jv_invalid_with_msg(jv_string_fmt("No such builtin module %s; %s", + jv_string_value(path), jv_string_value(contents))); + jv_free(contents); + return ret; +} + +static void * dl_builtin_sym(jq_dl_handle h, const char *name) { + struct jq_builtin_module *mod = h.bmodule; + + if (strcmp(name, "jq_plugin_init") == 0) + return mod->init; + return 0; +} + +static void *jq_dl_sym(jq_dl_handle h, const char *name) { + return JQ_DL_SYM(h.dl_handle, name); +} + +static void jq_dl_close(jq_dl_handle h) { + JQ_DL_CLOSE(h.dl_handle); +} + +static jv jq_dl_open(const char *path, jq_dl_handle *h, jq_dl_sym_f *dl_sym, jq_dl_close_f *dl_close) { + if (strncmp(path, "jq/", sizeof("jq/") - 1) == 0) { + for (size_t i = 0; i < jq_builtin_nmodules; i++) { + if (strcmp(jq_builtin_modules[i].name, path)) + continue; + h->bmodule = &jq_builtin_modules[i]; + *dl_sym = dl_builtin_sym; + *dl_close = 0; + return jv_true(); + } + h->bmodule = 0; + *dl_sym = 0; + *dl_close = 0; + return jv_invalid_with_msg(jv_string("no such builtin module object")); + } + if (!(h->dl_handle = JQ_DL_OPEN(path))) { + char *s = JQ_DL_ERROR(); + *dl_sym = 0; + *dl_close = 0; + return jv_invalid_with_msg(jv_string(s ? s : "")); + } + *dl_sym = jq_dl_sym; + *dl_close = jq_dl_close; + return jv_true(); +} + // Asummes validated relative path to module static jv find_lib(jq_state *jq, jv rel_path, jv search, const char *suffix, jv jq_origin, jv lib_origin) { if (!jv_is_valid(rel_path)) { + jv_free(lib_origin); + jv_free(jq_origin); jv_free(search); return rel_path; } if (jv_get_kind(rel_path) != JV_KIND_STRING) { + jv_free(lib_origin); + jv_free(jq_origin); jv_free(rel_path); jv_free(search); return jv_invalid_with_msg(jv_string_fmt("Module path must be a string")); } if (jv_get_kind(search) != JV_KIND_ARRAY) { + jv_free(lib_origin); + jv_free(jq_origin); jv_free(rel_path); jv_free(search); return jv_invalid_with_msg(jv_string_fmt("Module search path must be an array")); } + if (strncmp(jv_string_value(rel_path), "jq/", sizeof("jq/") - 1) == 0) { + /* Builtin module */ + jv_free(lib_origin); + jv_free(jq_origin); + jv_free(search); + return jv_string_concat(rel_path, jv_string(suffix)); + } + struct stat st; int ret; @@ -284,7 +451,7 @@ static int process_dependencies(jq_state *jq, jv jq_origin, jv lib_origin, block if (is_data) { // Can't reuse data libs because the wrong name is bound block dep_def_block; - nerrors += load_library(jq, resolved, is_data, raw, optional, as_str, &dep_def_block, lib_state); + nerrors += load_library(jq, resolved, 1, raw, optional, as_str, &dep_def_block, lib_state); if (nerrors == 0) { // Bind as both $data::data and $data for backward compatibility vs common sense bk = block_bind_library(dep_def_block, bk, OP_IS_CALL_PSEUDO, as_str); @@ -292,18 +459,18 @@ static int process_dependencies(jq_state *jq, jv jq_origin, jv lib_origin, block } } else { uint64_t state_idx = 0; - for (; state_idx < lib_state->ct; ++state_idx) { - if (strcmp(lib_state->names[state_idx],jv_string_value(resolved)) == 0) + for (; state_idx < lib_state->nlibs; ++state_idx) { + if (strcmp(lib_state->libs[state_idx].name,jv_string_value(resolved)) == 0) break; } - if (state_idx < lib_state->ct) { // Found + if (state_idx < lib_state->nlibs) { // Found jv_free(resolved); // Bind the library to the program - bk = block_bind_library(lib_state->defs[state_idx], bk, OP_IS_CALL_PSEUDO, as_str); + bk = block_bind_library(lib_state->libs[state_idx].defs, bk, OP_IS_CALL_PSEUDO, as_str); } else { // Not found. Add it to the table before binding. block dep_def_block = gen_noop(); - nerrors += load_library(jq, resolved, is_data, raw, optional, as_str, &dep_def_block, lib_state); + nerrors += load_library(jq, resolved, 0, 1, optional, as_str, &dep_def_block, lib_state); // resolved has been freed if (nerrors == 0) { // Bind the library to the program @@ -320,55 +487,162 @@ static int process_dependencies(jq_state *jq, jv jq_origin, jv lib_origin, block return nerrors; } +static int load_shared_object(jq_state *jq, struct jq_lib *lib) { + jq_plugin_init_f get_cfuncs; + int ret = 0; + const char *err = 0; + const char *data = 0; + size_t datasz = 0; + jv meta = block_module_meta(lib->defs); + jv oname = jv_invalid(); + jv sym = jv_string("jq_plugin_init"); + jv tmp = jv_invalid(); + + if (jv_get_kind(meta) != JV_KIND_OBJECT || + !jv_is_valid((oname = jv_object_get(jv_copy(meta), jv_string("cfunctions"))))) + goto out; + + if (jv_object_has(jv_copy(meta), jv_string("plugin_init_function"))) + sym = jv_object_get(jv_copy(meta), jv_string("plugin_init_function")); + + ret = 1; + if (jv_get_kind(oname) == JV_KIND_TRUE) + oname = jv_copy(lib->jbasename); + if (jv_get_kind(oname) != JV_KIND_STRING) { + jq_report_error(jq, jv_string_fmt("module %s: value of \"cfunctions\" key must be a string", + lib->name)); + goto out; + } + oname = jv_string_concat(oname, jv_string(JQ_DLL_EXT)); + if (!jv_is_valid((tmp = validate_relpath(jv_copy(oname))))) { + jq_report_error(jq, jv_string_fmt("module %s: path for DLL / shared object is not relative: %s: %s", + lib->name, jv_string_value(oname), jv_string_value(tmp))); + goto out; + } + /* A more idiomatic version of this would be nice: */ + jv_free(tmp); + tmp = jv_string_fmt("%s%s%s", jv_string_value(lib->origin), JQ_PATH_SEP, jv_string_value(oname)); + jv_free(oname); + oname = tmp; + tmp = jv_invalid(); + + jv msg = jq_dl_open(jv_string_value(oname), &lib->h, &lib->dl_sym, &lib->dl_close); + if (!jv_is_valid(msg)) { + jq_report_error(jq, jv_string_fmt("module %s: could not load DLL / shared object: %s", + lib->name, jv_string_value(oname))); + goto out; + } + if ((get_cfuncs = lib->dl_sym(lib->h, jv_string_value(sym))) == NULL) { + jq_report_error(jq, jv_string_fmt("module %s: could find \"%s\" symbol in DLL / shared object: %s", + lib->name, jv_string_value(sym), jv_string_value(oname))); + goto out; + } + + if ((ret = get_cfuncs(JQ_MIN_ABI, JQ_MAX_ABI, jq, &err, &data, &datasz, &lib->cfuncs, &lib->ncfuncs))) { + jq_report_error(jq, jv_string_fmt("module %s: failed to initialize DLL / shared object: %s", + lib->name, err ? err : "")); + goto out; + } + + ret = 0; + if (data) { + struct locfile* src = NULL; + + jv_free(lib->contents); + block_free(lib->defs); + lib->contents = datasz ? jv_string_sized(data, datasz) : jv_string(data); + + src = locfile_init(jq, lib->name, + jv_string_value(lib->contents), + jv_string_length_bytes(jv_copy(lib->contents))); + ret = jq_parse_library(src, &lib->defs); + locfile_free(src); + } + +out: + jv_free(oname); + jv_free(meta); + jv_free(sym); + jv_free(tmp); + return ret; +} + + // Loads the library at lib_path into lib_state, putting the library's defs // into *out_block static int load_library(jq_state *jq, jv lib_path, int is_data, int raw, int optional, const char *as, block *out_block, struct lib_loading_state *lib_state) { int nerrors = 0; struct locfile* src = NULL; - block program; - jv data; + char *dname = strdup(jv_string_value(lib_path)); // XXX check ENOMEM + char *bname = strdup(dname); // XXX check ENOMEM + size_t state_idx = lib_state->nlibs++; + + *out_block = gen_noop(); + lib_state->libs = jv_mem_realloc(lib_state->libs, lib_state->nlibs * sizeof(lib_state->libs[0])); + + /* + * lib_state->libs gets realloc'ed in load_library(), so we don't want to + * hold on to an element of that array. + */ +#define this_lib (&lib_state->libs[state_idx]) + this_lib->jname = jv_copy(lib_path); + this_lib->origin = dname ? jv_string(dirname(dname)) : jv_invalid_with_msg(jv_false()); // XXX ENOMEM + this_lib->jbasename = bname ? jv_string(basename(bname)) : jv_invalid_with_msg(jv_false()); // XXX ENOMEM + this_lib->name = jv_string_value(this_lib->jname); + this_lib->defs = gen_noop(); + memset(&this_lib->h, 0, sizeof(this_lib->h)); + this_lib->dl_sym = 0; + this_lib->dl_close = 0; + this_lib->cfuncs = NULL; + this_lib->ncfuncs = 0; + if (is_data && !raw) - data = jv_load_file(jv_string_value(lib_path), 0); + this_lib->contents = load_file(lib_path, 0); else - data = jv_load_file(jv_string_value(lib_path), 1); - int state_idx; - if (!jv_is_valid(data)) { - program = gen_noop(); + this_lib->contents = load_file(lib_path, 1); + if (!jv_is_valid(this_lib->contents)) { + this_lib->defs = gen_noop(); if (!optional) { - if (jv_invalid_has_msg(jv_copy(data))) - data = jv_invalid_get_msg(data); + if (jv_invalid_has_msg(jv_copy(this_lib->contents))) + this_lib->contents = jv_invalid_get_msg(this_lib->contents); else - data = jv_string("unknown error"); - jq_report_error(jq, jv_string_fmt("jq: error loading data file %s: %s\n", jv_string_value(lib_path), jv_string_value(data))); + this_lib->contents = jv_string("unknown error"); + jq_report_error(jq, jv_string_fmt("jq: error loading data file %s: %s\n", jv_string_value(lib_path), jv_string_value(this_lib->contents))); nerrors++; } goto out; } else if (is_data) { // import "foo" as $bar; - program = gen_const_global(jv_copy(data), as); + this_lib->defs = gen_const_global(jv_copy(this_lib->contents), as); } else { - // import "foo" as bar; - src = locfile_init(jq, jv_string_value(lib_path), jv_string_value(data), jv_string_length_bytes(jv_copy(data))); - nerrors += jq_parse_library(src, &program); - locfile_free(src); + // import "foo" [as bar] OR include "foo"; + src = locfile_init(jq, jv_string_value(lib_path), + jv_string_value(this_lib->contents), + jv_string_length_bytes(jv_copy(this_lib->contents))); + nerrors += jq_parse_library(src, &this_lib->defs); + /* + * Load the shared object now because it may replace the jq code of the + * library. + */ + if (nerrors == 0) + nerrors += load_shared_object(jq, this_lib); if (nerrors == 0) { - char *lib_origin = strdup(jv_string_value(lib_path)); nerrors += process_dependencies(jq, jq_get_jq_origin(jq), - jv_string(dirname(lib_origin)), - &program, lib_state); - free(lib_origin); - program = block_bind_self(program, OP_IS_CALL_PSEUDO); + jv_copy(this_lib->origin), &this_lib->defs, + lib_state); + if (this_lib->ncfuncs) + this_lib->defs = gen_cbinding(this_lib->cfuncs, this_lib->ncfuncs, this_lib->defs); + this_lib->defs = block_hide(block_bind_self(this_lib->defs, OP_IS_CALL_PSEUDO)); } } - state_idx = lib_state->ct++; - lib_state->names = jv_mem_realloc(lib_state->names, lib_state->ct * sizeof(const char *)); - lib_state->defs = jv_mem_realloc(lib_state->defs, lib_state->ct * sizeof(block)); - lib_state->names[state_idx] = strdup(jv_string_value(lib_path)); - lib_state->defs[state_idx] = program; + *out_block = this_lib->defs; +#undef this_lib + if (src) + locfile_free(src); out: - *out_block = program; + free(dname); + free(bname); jv_free(lib_path); - jv_free(data); return nerrors; } @@ -399,10 +673,9 @@ jv load_module_meta(jq_state *jq, jv mod_relpath) { return meta; } -int load_program(jq_state *jq, struct locfile* src, block *out_block) { +int load_program(jq_state *jq, struct locfile* src, block *out_block, struct lib_loading_state **out_libs) { int nerrors = 0; block program; - struct lib_loading_state lib_state = {0,0,0}; nerrors = jq_parse(src, &program); if (nerrors) return nerrors; @@ -417,21 +690,39 @@ int load_program(jq_state *jq, struct locfile* src, block *out_block) { program = BLOCK(import, program); } - nerrors = process_dependencies(jq, jq_get_jq_origin(jq), jq_get_prog_origin(jq), &program, &lib_state); + struct lib_loading_state *lib_state = jv_mem_calloc(1, sizeof(*lib_state)); + nerrors = process_dependencies(jq, jq_get_jq_origin(jq), jq_get_prog_origin(jq), &program, lib_state); block libs = gen_noop(); - for (uint64_t i = 0; i < lib_state.ct; ++i) { - free(lib_state.names[i]); - if (nerrors == 0 && !block_is_const(lib_state.defs[i])) - libs = block_join(libs, lib_state.defs[i]); - else - block_free(lib_state.defs[i]); + for (size_t i = 0; i < lib_state->nlibs; ++i) { + if (nerrors == 0 && !block_is_const(lib_state->libs[i].defs)) { + libs = block_join(libs, lib_state->libs[i].defs); + lib_state->libs[i].defs = gen_noop(); + } } - free(lib_state.names); - free(lib_state.defs); - if (nerrors) + if (nerrors) { block_free(program); - else + libraries_free(lib_state); + } else { *out_block = block_drop_unreferenced(block_join(libs, program)); + *out_libs = lib_state; + } return nerrors; } + +void libraries_free(struct lib_loading_state *libs) { + if (!libs) + return; + + for (size_t i = 0; i < libs->nlibs; ++i) { + if (libs->libs[i].dl_close) + jq_dl_close(libs->libs[i].h); + jv_free(libs->libs[i].jname); + jv_free(libs->libs[i].jbasename); + jv_free(libs->libs[i].origin); + jv_free(libs->libs[i].contents); + block_free(libs->libs[i].defs); + } + free(libs->libs); + free(libs); +} diff --git a/src/linker.h b/src/linker.h index 3f682ca28b..8b36732cff 100644 --- a/src/linker.h +++ b/src/linker.h @@ -1,7 +1,19 @@ #ifndef LINKER_H #define LINKER_H -int load_program(jq_state *jq, struct locfile* src, block *out_block); +#include "compile.h" + +#ifdef WIN32 +#define JQ_PATH_SEP "\\" +#define JQ_DLL_EXT ".dll" +#else +#define JQ_PATH_SEP "/" +#define JQ_DLL_EXT ".so" +#endif + +struct lib_loading_state; +int load_program(jq_state *jq, struct locfile* src, block *out_block, struct lib_loading_state **libs); +void libraries_free(struct lib_loading_state *); jv load_module_meta(jq_state *jq, jv modname); #endif diff --git a/src/main.c b/src/main.c index 7022f19ebf..547a469dad 100644 --- a/src/main.c +++ b/src/main.c @@ -15,6 +15,8 @@ #include #include #include +#else +#include #endif #if !defined(HAVE_ISATTY) && defined(HAVE__ISATTY) @@ -125,27 +127,28 @@ static int isoption(const char* text, char shortopt, const char* longopt, size_t return 0; } -enum { - SLURP = 1, - RAW_INPUT = 2, - PROVIDE_NULL = 4, - RAW_OUTPUT = 8, - RAW_NUL = 16, - ASCII_OUTPUT = 32, - COLOR_OUTPUT = 64, - NO_COLOR_OUTPUT = 128, - SORTED_OUTPUT = 256, - FROM_FILE = 512, - RAW_NO_LF = 1024, - UNBUFFERED_OUTPUT = 2048, - EXIT_STATUS = 4096, - EXIT_STATUS_EXACT = 8192, - SEQ = 16384, - RUN_TESTS = 32768, +enum option_flags { + SLURP = 1UL, + RAW_INPUT = 1UL<<1, + PROVIDE_NULL = 1UL<<2, + RAW_OUTPUT = 1UL<<3, + RAW_NUL = 1UL<<4, + ASCII_OUTPUT = 1UL<<5, + COLOR_OUTPUT = 1UL<<6, + NO_COLOR_OUTPUT = 1UL<<7, + SORTED_OUTPUT = 1UL<<8, + FROM_FILE = 1UL<<9, + RAW_NO_LF = 1UL<<10, + UNBUFFERED_OUTPUT = 1UL<<11, + EXIT_STATUS = 1UL<<12, + EXIT_STATUS_EXACT = 1UL<<13, + SEQ = 1UL<<14, + RUN_TESTS = 1UL<<15, + ALLOW_IO = 1UL<<16, /* debugging only */ - DUMP_DISASM = 65536, + DUMP_DISASM = 1UL<<17, }; -static int options = 0; +static enum option_flags options = 0; enum { JQ_OK = 0, @@ -250,6 +253,10 @@ static void debug_cb(void *data, jv input) { fprintf(stderr, "\n"); } +#ifndef WIN32 +static void sigchld(int sig) {} +#endif + #ifdef WIN32 int umain(int argc, char* argv[]); @@ -285,6 +292,12 @@ int main(int argc, char* argv[]) { fflush(stderr); _setmode(fileno(stdout), _O_TEXT | _O_U8TEXT); _setmode(fileno(stderr), _O_TEXT | _O_U8TEXT); +#else + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sigchld; + (void) sigaction(SIGCHLD, &sa, NULL); #endif if (argc) progname = argv[0]; @@ -349,6 +362,32 @@ int main(int argc, char* argv[]) { continue; } + if (isoption(argv[i], 'I', "io", &short_opts)) { + options |= ALLOW_IO; + if (!short_opts) continue; + } + if (isoption(argv[i], 0, "io-policy", &short_opts)) { + options &= ~ALLOW_IO; + if (argv[i+1] == NULL) { + fprintf(stderr, "--io-policy takes a parameter"); + die(); + } + jv res = jq_set_io_policy(jq, jv_string(argv[i+1])); + if (!jv_is_valid(res)) { + if (jv_invalid_has_msg(res)) { + res = jv_invalid_get_msg(res); + } else { + jv_free(res); + res = jv_string("unkown error"); + } + fprintf(stderr, "Error: I/O policy rejected: %s", jv_string_value(res)); + jv_free(res); + die(); + } + jv_free(res); + i++; + continue; + } if (isoption(argv[i], 's', "slurp", &short_opts)) { options |= SLURP; if (!short_opts) continue; @@ -580,6 +619,9 @@ int main(int argc, char* argv[]) { if (options & COLOR_OUTPUT) dumpopts |= JV_PRINT_COLOR; if (options & NO_COLOR_OUTPUT) dumpopts &= ~JV_PRINT_COLOR; + if (options & ALLOW_IO) + jq_set_attr(jq, jv_string("ALLOW_IO"), jv_true()); + if (getenv("JQ_COLORS") != NULL && !jq_set_colors(getenv("JQ_COLORS"))) fprintf(stderr, "Failed to set $JQ_COLORS\n"); diff --git a/src/opcode_list.h b/src/opcode_list.h index 886131d7c6..ca841c8865 100644 --- a/src/opcode_list.h +++ b/src/opcode_list.h @@ -11,12 +11,13 @@ OP(STORE_GLOBAL, GLOBAL, 0, 0) OP(INDEX, NONE, 2, 1) OP(INDEX_OPT, NONE, 2, 1) OP(EACH, NONE, 1, 1) -OP(EACH_OPT, NONE, 1, 1) +OP(EACH_OPT, NONE, 1, 1) OP(FORK, BRANCH, 0, 0) -OP(FORK_OPT, BRANCH, 0, 0) +OP(TRY_BEGIN, BRANCH, 0, 0) +OP(TRY_END, NONE, 0, 0) OP(JUMP, BRANCH, 0, 0) OP(JUMP_F,BRANCH, 1, 0) -OP(BACKTRACK, NONE, 0, 0) +OP(BACKTRACK, BACKTRACKING, 0, 0) OP(APPEND, VARIABLE,1, 0) OP(INSERT, NONE, 4, 2) OP(RANGE, VARIABLE, 1, 1) @@ -29,20 +30,30 @@ OP(PATH_END, NONE, 2, 1) OP(CALL_BUILTIN, CFUNC, -1, 1) -OP(CALL_JQ, UFUNC, 1, 1) -OP(RET, NONE, 1, 1) -OP(TAIL_CALL_JQ, UFUNC, 1, 1) +OP(CALL_JQ, UFUNC, 0, 0) +OP(RET_JQ, NONE, 0, 0) +OP(TAIL_CALL_JQ, UFUNC, 0, 0) OP(CLOSURE_PARAM, DEFINITION, 0, 0) OP(CLOSURE_REF, CLOSURE_REF_IMM, 0, 0) OP(CLOSURE_CREATE, DEFINITION, 0, 0) OP(CLOSURE_CREATE_C, DEFINITION, 0, 0) -OP(TOP, NONE, 0, 0) +// Schroedinger's TOP is there and not there at the same time +OP(TOP, MARKER, 0, 0) + +OP(COCREATE, BRANCH, 1, 1) +// the entry point of a coroutine and main +OP(START, NONE, 0, 1) OP(CLOSURE_PARAM_REGULAR, DEFINITION, 0, 0) +OP(CLOSURE_PARAM_COEXPR, DEFINITION, 0, 0) OP(DEPS, CONSTANT, 0, 0) OP(MODULEMETA, CONSTANT, 0, 0) OP(GENLABEL, NONE, 0, 1) OP(DESTRUCTURE_ALT, BRANCH, 0, 0) OP(STOREVN, VARIABLE, 1, 0) +OP(COEVAL, NONE, 1, 1) +OP(UNWINDING, NONE, 0, 0) +OP(OUT, NONE, 1, 0) +OP(TAIL_OUT, BACKTRACKING, 1, 0) diff --git a/src/parser.c b/src/parser.c index b6574e52c8..b7555448de 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.5. */ /* Bison implementation for Yacc-like parsers in C @@ -48,7 +48,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.3.2" +#define YYBISON_VERSION "3.5" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -66,7 +66,7 @@ /* First part of user prologue. */ -#line 1 "src/parser.y" /* yacc.c:337 */ +#line 1 "src/parser.y" #include #include @@ -77,7 +77,17 @@ #define YYMALLOC jv_mem_alloc #define YYFREE jv_mem_free -#line 81 "src/parser.c" /* yacc.c:337 */ +#line 81 "src/parser.c" + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus @@ -98,8 +108,8 @@ # define YYERROR_VERBOSE 1 #endif -/* In a future release of Bison, this section will be replaced - by #include "y.tab.h". */ +/* Use api.header.include to #include this header + instead of duplicating it here. */ #ifndef YY_YY_SRC_PARSER_H_INCLUDED # define YY_YY_SRC_PARSER_H_INCLUDED /* Debug traces. */ @@ -110,7 +120,7 @@ extern int yydebug; #endif /* "%code requires" blocks. */ -#line 11 "src/parser.y" /* yacc.c:352 */ +#line 11 "src/parser.y" #include "locfile.h" struct lexer_param; @@ -127,7 +137,7 @@ struct lexer_param; } \ } while (0) -#line 131 "src/parser.c" /* yacc.c:352 */ +#line 141 "src/parser.c" /* Token type. */ #ifndef YYTOKENTYPE @@ -146,39 +156,42 @@ struct lexer_param; DEFINEDOR = 267, AS = 268, DEF = 269, - MODULE = 270, - IMPORT = 271, - INCLUDE = 272, - IF = 273, - THEN = 274, - ELSE = 275, - ELSE_IF = 276, - REDUCE = 277, - FOREACH = 278, - END = 279, - AND = 280, - OR = 281, - TRY = 282, - CATCH = 283, - LABEL = 284, - BREAK = 285, - LOC = 286, - SETPIPE = 287, - SETPLUS = 288, - SETMINUS = 289, - SETMULT = 290, - SETDIV = 291, - SETDEFINEDOR = 292, - LESSEQ = 293, - GREATEREQ = 294, - ALTERNATION = 295, - QQSTRING_START = 296, - QQSTRING_TEXT = 297, - QQSTRING_INTERP_START = 298, - QQSTRING_INTERP_END = 299, - QQSTRING_END = 300, - FUNCDEF = 301, - NONOPT = 302 + CODEF = 270, + MODULE = 271, + IMPORT = 272, + INCLUDE = 273, + IF = 274, + THEN = 275, + ELSE = 276, + ELSE_IF = 277, + REDUCE = 278, + FOREACH = 279, + END = 280, + AND = 281, + OR = 282, + TRY = 283, + CATCH = 284, + LABEL = 285, + BREAK = 286, + LOC = 287, + HIGHPRECPIPE = 288, + SETPIPE = 289, + SETPLUS = 290, + SETMINUS = 291, + SETMULT = 292, + SETDIV = 293, + SETDEFINEDOR = 294, + LESSEQ = 295, + GREATEREQ = 296, + ALTERNATION = 297, + COEXPR = 298, + QQSTRING_START = 299, + QQSTRING_TEXT = 300, + QQSTRING_INTERP_START = 301, + QQSTRING_INTERP_END = 302, + QQSTRING_END = 303, + FUNCDEF = 304, + NONOPT = 305 }; #endif /* Tokens. */ @@ -194,53 +207,55 @@ struct lexer_param; #define DEFINEDOR 267 #define AS 268 #define DEF 269 -#define MODULE 270 -#define IMPORT 271 -#define INCLUDE 272 -#define IF 273 -#define THEN 274 -#define ELSE 275 -#define ELSE_IF 276 -#define REDUCE 277 -#define FOREACH 278 -#define END 279 -#define AND 280 -#define OR 281 -#define TRY 282 -#define CATCH 283 -#define LABEL 284 -#define BREAK 285 -#define LOC 286 -#define SETPIPE 287 -#define SETPLUS 288 -#define SETMINUS 289 -#define SETMULT 290 -#define SETDIV 291 -#define SETDEFINEDOR 292 -#define LESSEQ 293 -#define GREATEREQ 294 -#define ALTERNATION 295 -#define QQSTRING_START 296 -#define QQSTRING_TEXT 297 -#define QQSTRING_INTERP_START 298 -#define QQSTRING_INTERP_END 299 -#define QQSTRING_END 300 -#define FUNCDEF 301 -#define NONOPT 302 +#define CODEF 270 +#define MODULE 271 +#define IMPORT 272 +#define INCLUDE 273 +#define IF 274 +#define THEN 275 +#define ELSE 276 +#define ELSE_IF 277 +#define REDUCE 278 +#define FOREACH 279 +#define END 280 +#define AND 281 +#define OR 282 +#define TRY 283 +#define CATCH 284 +#define LABEL 285 +#define BREAK 286 +#define LOC 287 +#define HIGHPRECPIPE 288 +#define SETPIPE 289 +#define SETPLUS 290 +#define SETMINUS 291 +#define SETMULT 292 +#define SETDIV 293 +#define SETDEFINEDOR 294 +#define LESSEQ 295 +#define GREATEREQ 296 +#define ALTERNATION 297 +#define COEXPR 298 +#define QQSTRING_START 299 +#define QQSTRING_TEXT 300 +#define QQSTRING_INTERP_START 301 +#define QQSTRING_INTERP_END 302 +#define QQSTRING_END 303 +#define FUNCDEF 304 +#define NONOPT 305 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - union YYSTYPE { -#line 31 "src/parser.y" /* yacc.c:352 */ +#line 31 "src/parser.y" jv literal; block blk; -#line 242 "src/parser.c" /* yacc.c:352 */ -}; +#line 257 "src/parser.c" +}; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 @@ -267,7 +282,7 @@ int yyparse (block* answer, int* errors, struct locfile* locations, struct lexer #endif /* !YY_YY_SRC_PARSER_H_INCLUDED */ /* Second part of user prologue. */ -#line 124 "src/parser.y" /* yacc.c:354 */ +#line 128 "src/parser.y" #include "lexer.h" struct lexer_param { @@ -447,34 +462,82 @@ static block gen_update(block object, block val, int optype) { } -#line 451 "src/parser.c" /* yacc.c:354 */ +#line 466 "src/parser.c" + #ifdef short # undef short #endif -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + and (if available) are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif #endif -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; #else -typedef unsigned short yytype_uint16; +typedef short yytype_int16; +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; #endif -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; #else -typedef short yytype_int16; +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif #endif #ifndef YYSIZE_T @@ -482,7 +545,7 @@ typedef short yytype_int16; # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t -# elif ! defined YYSIZE_T +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else @@ -490,7 +553,19 @@ typedef short yytype_int16; # endif #endif -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + +/* Stored state numbers (used for stacks). */ +typedef yytype_int16 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS @@ -504,22 +579,20 @@ typedef short yytype_int16; # endif #endif -#ifndef YY_ATTRIBUTE -# if (defined __GNUC__ \ - && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ - || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C -# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else -# define YY_ATTRIBUTE(Spec) /* empty */ +# define YY_ATTRIBUTE_PURE # endif #endif -#ifndef YY_ATTRIBUTE_PURE -# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) -#endif - #ifndef YY_ATTRIBUTE_UNUSED -# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif #endif /* Suppress unused-variable warnings by "using" E. */ @@ -531,11 +604,11 @@ typedef short yytype_int16; #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value @@ -548,6 +621,20 @@ typedef short yytype_int16; # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) #if ! defined yyoverflow || YYERROR_VERBOSE @@ -625,18 +712,19 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss_alloc; + yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ + + YYSIZEOF (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 @@ -649,11 +737,11 @@ union yyalloc # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ - YYSIZE_T yynewbytes; \ + YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) @@ -665,12 +753,12 @@ union yyalloc # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ - YYSIZE_T yyi; \ + YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ @@ -680,44 +768,45 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 27 +#define YYFINAL 28 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 2220 +#define YYLAST 2294 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 69 +#define YYNTOKENS 72 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 30 /* YYNRULES -- Number of rules. */ -#define YYNRULES 169 +#define YYNRULES 175 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 322 +#define YYNSTATES 344 #define YYUNDEFTOK 2 -#define YYMAXUTOK 302 +#define YYMAXUTOK 305 + /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ - ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + (0 <= (YYX) && (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ -static const yytype_uint8 yytranslate[] = +static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 62, 56, 2, 2, - 60, 61, 54, 52, 48, 53, 64, 55, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 63, 59, - 50, 49, 51, 58, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 64, 59, 2, 2, + 63, 65, 57, 55, 51, 56, 67, 58, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 66, 62, + 53, 52, 54, 61, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 65, 2, 66, 2, 2, 2, 2, 2, 2, + 2, 68, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 67, 47, 68, 2, 2, 2, 2, + 2, 2, 2, 70, 50, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -735,30 +824,31 @@ static const yytype_uint8 yytranslate[] = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 57 + 45, 46, 47, 48, 49, 60 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = +static const yytype_int16 yyrline[] = { - 0, 306, 306, 309, 314, 317, 328, 331, 336, 339, - 344, 348, 351, 355, 359, 363, 366, 369, 374, 378, - 382, 387, 394, 398, 402, 406, 410, 414, 418, 422, - 426, 430, 434, 438, 442, 446, 450, 454, 458, 464, - 470, 474, 478, 482, 486, 490, 494, 498, 502, 507, - 510, 527, 536, 543, 551, 562, 567, 573, 576, 581, - 585, 589, 596, 596, 600, 600, 607, 610, 613, 619, - 622, 627, 630, 633, 639, 642, 645, 653, 657, 660, - 663, 666, 669, 672, 675, 678, 681, 685, 691, 694, - 697, 700, 703, 706, 709, 712, 715, 718, 721, 724, - 727, 730, 733, 736, 739, 742, 745, 752, 756, 765, - 777, 782, 783, 784, 785, 788, 791, 796, 801, 804, - 809, 812, 817, 821, 824, 829, 832, 837, 840, 845, - 848, 851, 854, 857, 860, 868, 874, 877, 880, 883, - 886, 889, 892, 895, 898, 901, 904, 907, 910, 913, - 916, 919, 922, 925, 928, 933, 936, 937, 938, 941, - 944, 947, 950, 954, 958, 962, 966, 970, 974, 982 + 0, 310, 310, 329, 334, 337, 348, 351, 356, 359, + 364, 368, 388, 391, 395, 399, 403, 406, 409, 414, + 417, 420, 423, 426, 431, 438, 442, 446, 450, 454, + 458, 462, 466, 470, 474, 478, 482, 486, 490, 494, + 498, 502, 506, 512, 518, 522, 526, 530, 534, 538, + 542, 546, 550, 555, 558, 575, 584, 591, 599, 610, + 615, 621, 624, 629, 633, 637, 641, 648, 648, 652, + 652, 659, 662, 665, 671, 674, 679, 682, 685, 691, + 694, 697, 705, 709, 712, 715, 718, 721, 724, 727, + 730, 733, 737, 743, 746, 749, 752, 755, 758, 761, + 764, 767, 770, 773, 776, 779, 782, 785, 788, 791, + 794, 797, 804, 808, 817, 829, 834, 835, 836, 837, + 840, 843, 848, 853, 856, 861, 864, 869, 873, 876, + 881, 884, 889, 892, 897, 900, 903, 906, 909, 912, + 920, 926, 929, 932, 935, 938, 941, 944, 947, 950, + 953, 956, 959, 962, 965, 968, 971, 974, 977, 980, + 983, 988, 991, 992, 993, 996, 999, 1002, 1005, 1009, + 1013, 1017, 1021, 1025, 1029, 1037 }; #endif @@ -769,85 +859,88 @@ static const char *const yytname[] = { "$end", "error", "$undefined", "INVALID_CHARACTER", "IDENT", "FIELD", "LITERAL", "FORMAT", "\"..\"", "\"%=\"", "\"==\"", "\"!=\"", "\"//\"", - "\"as\"", "\"def\"", "\"module\"", "\"import\"", "\"include\"", "\"if\"", - "\"then\"", "\"else\"", "\"elif\"", "\"reduce\"", "\"foreach\"", - "\"end\"", "\"and\"", "\"or\"", "\"try\"", "\"catch\"", "\"label\"", - "\"break\"", "\"__loc__\"", "\"|=\"", "\"+=\"", "\"-=\"", "\"*=\"", - "\"/=\"", "\"//=\"", "\"<=\"", "\">=\"", "\"?//\"", "QQSTRING_START", - "QQSTRING_TEXT", "QQSTRING_INTERP_START", "QQSTRING_INTERP_END", - "QQSTRING_END", "FUNCDEF", "'|'", "','", "'='", "'<'", "'>'", "'+'", - "'-'", "'*'", "'/'", "'%'", "NONOPT", "'?'", "';'", "'('", "')'", "'$'", - "':'", "'.'", "'['", "']'", "'{'", "'}'", "$accept", "TopLevel", - "Module", "Imports", "FuncDefs", "Exp", "Import", "ImportWhat", - "ImportFrom", "FuncDef", "Params", "Param", "String", "@1", "@2", - "QQString", "ElseBody", "ExpD", "Term", "Args", "Arg", "RepPatterns", - "Patterns", "Pattern", "ArrayPats", "ObjPats", "ObjPat", "Keyword", - "MkDict", "MkDictPair", YY_NULLPTR + "\"as\"", "\"def\"", "\"codef\"", "\"module\"", "\"import\"", + "\"include\"", "\"if\"", "\"then\"", "\"else\"", "\"elif\"", + "\"reduce\"", "\"foreach\"", "\"end\"", "\"and\"", "\"or\"", "\"try\"", + "\"catch\"", "\"label\"", "\"break\"", "\"__loc__\"", "\">|\"", "\"|=\"", + "\"+=\"", "\"-=\"", "\"*=\"", "\"/=\"", "\"//=\"", "\"<=\"", "\">=\"", + "\"?//\"", "\"@@\"", "QQSTRING_START", "QQSTRING_TEXT", + "QQSTRING_INTERP_START", "QQSTRING_INTERP_END", "QQSTRING_END", + "FUNCDEF", "'|'", "','", "'='", "'<'", "'>'", "'+'", "'-'", "'*'", "'/'", + "'%'", "NONOPT", "'?'", "';'", "'('", "'$'", "')'", "':'", "'.'", "'['", + "']'", "'{'", "'}'", "$accept", "TopLevel", "Module", "Imports", + "FuncDefs", "Exp", "Import", "ImportWhat", "ImportFrom", "FuncDef", + "Params", "Param", "String", "@1", "@2", "QQString", "ElseBody", "ExpD", + "Term", "Args", "Arg", "RepPatterns", "Patterns", "Pattern", "ArrayPats", + "ObjPats", "ObjPat", "Keyword", "MkDict", "MkDictPair", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ -static const yytype_uint16 yytoknum[] = +static const yytype_int16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 124, 44, 61, - 60, 62, 43, 45, 42, 47, 37, 302, 63, 59, - 40, 41, 36, 58, 46, 91, 93, 123, 125 + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 124, 44, 61, 60, 62, 43, 45, 42, 47, 37, + 305, 63, 59, 40, 36, 41, 58, 46, 91, 93, + 123, 125 }; # endif -#define YYPACT_NINF -157 +#define YYPACT_NINF (-147) -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-157))) +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) -#define YYTABLE_NINF -156 +#define YYTABLE_NINF (-162) -#define yytable_value_is_error(Yytable_value) \ - (!!((Yytable_value) == (-156))) +#define yytable_value_is_error(Yyn) \ + ((Yyn) == YYTABLE_NINF) /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { - 43, 838, 75, 28, 16, 22, -157, 66, -157, 108, - 838, 161, 161, 838, 63, 1, -157, 838, 588, 2133, - 288, 521, 354, 1406, 838, -157, 0, -157, 14, 14, - 838, 28, 746, 838, -157, -157, -9, 1812, 17, 55, - 99, 126, -157, 127, -157, -6, 72, 1236, -157, -157, - -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, - -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, - 140, 66, 85, 78, -157, 983, -45, 82, 838, 2161, - 86, 87, 83, 105, 838, 838, 838, 838, 838, 838, - 838, 838, 838, 838, 838, 838, 838, 838, 838, 838, - 838, 838, 838, 838, 838, 838, 838, 838, -157, -157, - 1980, 96, -26, -3, 454, 142, -157, -157, -157, 1980, - 838, -157, -157, 1457, 1980, -19, -157, -157, 10, 838, - 653, -26, -26, 718, 109, -157, 24, -157, -157, -157, - -157, -157, -157, 411, 130, -157, 130, 1270, 94, -157, - 130, 130, -157, 411, 2048, 209, 209, 2014, 349, 2080, - 2048, 2048, 2048, 2048, 2048, 2048, 209, 209, 1980, 2014, - 2048, 209, 209, -6, -6, 101, 101, 101, -157, 157, - -26, 900, 122, 117, 132, 838, 112, 107, 838, 116, - 933, 11, -157, -157, 838, -157, 81, -157, 2189, -2, - -157, 1508, -157, 1712, 115, 118, -157, -157, 838, -157, - 838, -157, -20, -157, 130, 129, 51, 129, 114, 130, - 129, 129, -157, -157, -157, -13, 119, 125, 838, 175, - 133, -22, -157, 135, -26, 838, 1033, -157, -157, 1083, - -157, 810, 123, -157, 181, -157, -157, -157, -157, 10, - 136, -157, 838, 838, -157, -157, 838, 838, 1980, 1846, - -157, 130, 130, 129, -26, -157, -26, -26, 1304, 137, - -26, 900, -157, -26, 149, 1980, 143, 145, 146, 1133, - -157, -157, -157, 838, 1896, 1946, 1559, 1610, -157, 129, - 129, -157, -157, -157, 148, -26, -157, -157, -157, -157, - -157, -157, 147, 1661, -157, 838, 838, 838, -26, -157, - -157, -157, 1762, 1338, 1183, -157, -157, -157, 838, -157, - 1372, -157 + 55, 808, 74, 28, 59, 65, -147, 84, -147, 116, + 75, 808, 167, 167, 875, 86, 14, -147, 808, 580, + 2204, 307, 510, 376, 1484, 808, -147, 9, -147, 29, + 29, 808, 28, 710, 808, -147, -147, -23, 87, 1866, + 18, 47, 580, 30, 141, -147, 144, -147, -8, 91, + 1268, -147, -147, -147, -147, -147, -147, -147, -147, -147, + -147, -147, -147, -147, -147, -147, -147, -147, -147, -147, + -147, -147, -147, -147, 151, 84, 97, 92, -147, 1009, + 66, 98, 808, 2233, 101, 102, 105, 111, 808, 808, + 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, + 808, 808, 808, 808, 808, 808, 808, 808, 808, 808, + 808, 808, 808, -147, -147, 2044, 108, 57, 68, 479, + 164, -147, -147, -147, 2044, 808, -147, -147, 1521, 2044, + 69, -147, -147, 76, 808, 113, 611, 57, 57, 1157, + 679, 129, -147, 24, -147, -147, -147, -147, -147, -147, + 437, -2, -147, -2, 1304, 114, -147, -2, -2, -147, + 437, 2116, 855, 855, 2080, 2148, 199, 148, 2116, 2116, + 2116, 2116, 2116, 2116, 855, 855, 2044, 2080, 2116, 855, + 855, -8, -8, -17, -17, -17, -147, 178, 57, 933, + 142, 133, 143, 808, 125, 118, 808, 128, 972, 52, + -147, -147, 808, -147, 96, -147, 186, 2262, 81, -147, + 1558, 189, -147, 1760, 134, 136, 808, -147, 148, 808, + -147, 808, -147, -27, -147, -2, 146, 15, 146, 137, + -2, 146, 146, -147, -147, -147, -14, 138, 139, 808, + 196, 147, -24, -147, 150, 57, 808, 1046, -147, -147, + 1083, -147, 777, 153, -147, 198, -147, -147, -147, -147, + -147, 76, 156, -147, 157, 808, 808, -147, -147, 808, + 808, 1194, 2044, 1902, -147, -2, -2, 146, 57, -147, + 57, 57, 1340, 158, 57, 933, -147, 57, 165, 2044, + 166, 168, 172, 1120, -147, -147, -147, 808, 808, 1955, + 2008, 1595, 1632, 808, -147, -147, 146, 146, -147, -147, + -147, 162, 57, -147, -147, -147, -147, -147, -147, 175, + 1669, 1706, -147, 808, 808, 808, 1376, 57, -147, -147, + -147, 808, 1813, 1412, 1231, -147, -147, 2044, -147, -147, + 808, -147, 1448, -147 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -855,55 +948,57 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 4, 0, 0, 6, 109, 83, 100, 102, 75, 0, - 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, - 0, 0, 0, 0, 0, 101, 48, 1, 0, 0, - 8, 6, 0, 0, 79, 64, 0, 0, 0, 0, - 19, 0, 77, 0, 66, 33, 0, 0, 107, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 108, 86, - 0, 0, 85, 0, 105, 0, 0, 166, 0, 0, - 162, 167, 0, 156, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 6, 114, 88, 105, 107, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, + 0, 0, 0, 0, 0, 0, 106, 52, 1, 0, + 0, 8, 6, 0, 0, 84, 69, 0, 0, 0, + 0, 0, 0, 22, 0, 82, 0, 71, 37, 0, + 0, 112, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 113, 91, 0, 0, 90, 0, 110, 0, + 0, 172, 0, 0, 168, 173, 0, 162, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 22, 5, - 10, 82, 0, 0, 0, 0, 54, 53, 3, 2, - 8, 7, 49, 0, 117, 0, 115, 66, 0, 0, - 0, 0, 0, 0, 0, 76, 0, 111, 103, 87, - 81, 112, 104, 0, 0, 114, 0, 0, 164, 165, - 0, 0, 106, 0, 41, 42, 43, 26, 25, 24, - 28, 32, 35, 37, 40, 27, 46, 47, 29, 30, - 23, 44, 45, 31, 34, 36, 38, 39, 78, 0, - 0, 0, 0, 0, 121, 0, 84, 0, 0, 93, - 0, 0, 9, 50, 0, 110, 0, 61, 0, 0, - 57, 0, 17, 0, 0, 0, 20, 18, 0, 67, - 0, 63, 0, 158, 0, 169, 73, 159, 0, 0, - 161, 160, 157, 122, 125, 0, 0, 0, 0, 0, - 0, 0, 127, 0, 0, 0, 0, 80, 113, 0, - 92, 0, 89, 52, 0, 116, 65, 59, 60, 0, - 0, 55, 0, 0, 16, 15, 0, 0, 21, 0, - 72, 0, 0, 163, 0, 123, 0, 0, 0, 129, - 0, 0, 124, 0, 120, 11, 91, 99, 98, 0, - 88, 51, 58, 0, 0, 0, 0, 0, 68, 71, - 168, 126, 135, 131, 0, 0, 133, 128, 132, 90, - 96, 95, 97, 0, 70, 0, 0, 0, 0, 130, - 94, 56, 0, 0, 0, 134, 69, 12, 0, 14, - 0, 13 + 0, 0, 0, 25, 5, 10, 87, 0, 0, 0, + 0, 58, 57, 3, 2, 8, 7, 53, 0, 122, + 0, 120, 71, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 81, 0, 116, 108, 92, 86, 117, 109, + 0, 0, 119, 0, 0, 170, 171, 0, 0, 111, + 0, 45, 46, 47, 29, 28, 27, 33, 31, 36, + 39, 41, 44, 30, 50, 51, 32, 34, 26, 48, + 49, 35, 38, 40, 42, 43, 83, 0, 0, 0, + 0, 0, 126, 0, 89, 0, 0, 98, 0, 0, + 9, 54, 0, 115, 0, 66, 0, 0, 0, 61, + 0, 0, 18, 0, 0, 0, 0, 23, 21, 0, + 72, 0, 68, 0, 164, 0, 175, 78, 165, 0, + 0, 167, 166, 163, 127, 130, 0, 0, 0, 0, + 0, 0, 0, 132, 0, 0, 0, 0, 85, 118, + 0, 97, 0, 94, 56, 0, 121, 70, 65, 63, + 64, 0, 0, 59, 0, 0, 0, 17, 16, 0, + 0, 0, 24, 0, 77, 0, 0, 169, 0, 128, + 0, 0, 0, 134, 0, 0, 129, 0, 125, 12, + 96, 104, 103, 0, 93, 55, 62, 0, 0, 0, + 0, 0, 0, 0, 19, 73, 76, 174, 131, 140, + 136, 0, 0, 138, 133, 137, 95, 101, 100, 102, + 0, 0, 75, 0, 0, 0, 0, 0, 135, 99, + 60, 0, 0, 0, 0, 20, 139, 11, 74, 13, + 0, 15, 0, 14 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -157, -157, -157, 177, 92, -1, -157, -157, 184, -11, - -157, -43, 5, -157, -157, 89, -98, -140, -4, -157, - 23, -157, -61, -156, -157, -157, -53, -18, -106, -157 + -147, -147, -147, 176, 94, -1, -147, -147, 182, -12, + -147, -44, 5, -147, -147, 109, -90, -146, -4, -147, + 41, -147, -80, -121, -147, -147, -41, -19, -112, -147 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 2, 3, 30, 118, 110, 31, 32, 115, 24, - 199, 200, 25, 44, 127, 136, 255, 215, 26, 125, - 126, 182, 183, 184, 225, 231, 232, 81, 82, 83 + -1, 2, 3, 31, 123, 115, 32, 33, 120, 25, + 208, 209, 26, 47, 132, 143, 268, 226, 27, 130, + 131, 190, 191, 192, 236, 242, 243, 85, 86, 87 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -911,539 +1006,557 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 23, 68, 42, 143, 71, 111, 217, 38, 39, 37, - 220, 221, 40, 112, 197, 243, 45, 47, 144, 120, - 75, 71, 111, 145, 224, 72, 271, 80, 143, 119, - 131, 123, 124, 116, 116, 264, 179, 213, 16, 180, - 194, 181, 195, 144, 28, 29, 272, 222, 105, 106, - 107, 128, 108, 265, 129, 16, 111, 249, 1, 250, - 111, 149, 185, 43, 113, 114, 209, 210, 132, 211, - 204, 205, 198, 244, 260, 27, 33, 147, 274, 263, - 34, 113, 114, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 35, 291, 120, - 292, 293, 36, 190, 296, 113, 114, 298, 186, 113, - 114, 289, 290, 209, 210, 41, 246, 133, 201, 203, - 134, 135, 207, 137, 4, 5, 6, 7, 8, 309, - 216, 139, 216, 140, 141, 146, 216, 216, 80, 150, - 151, 152, 315, 153, 178, 191, 208, 219, 80, 108, - 15, 223, 234, 233, 235, 4, 5, 6, 7, 8, - 237, 16, -119, 238, 240, 256, 261, 262, 257, 269, - 248, 280, 266, 214, 236, 281, 230, 239, 267, -118, - 18, 15, 19, 124, 20, 21, 270, 22, 273, 283, - 295, 299, 16, 300, 301, 310, 282, 258, 121, 259, - 216, 308, 192, 117, 316, 216, 196, 245, 297, -156, - -156, 18, 0, 19, 0, 20, 21, 268, 22, 0, - 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, - 279, 0, 0, 0, 0, 0, 0, -156, -156, 0, - 0, 284, 285, 233, 0, 286, 287, 216, 216, -156, - -156, 103, 104, 105, 106, 107, 0, 108, 0, 0, - 0, 0, 0, 0, 0, 0, 230, 0, 0, 0, - 0, 0, 303, 0, 0, 0, 0, 0, -74, 69, - 0, 0, 70, -74, 0, 71, 0, -74, -74, -74, - -74, -74, 0, 0, 312, 313, 314, -74, -74, -74, - 0, 0, -74, -74, -74, 0, -74, 320, 0, 0, - -74, -74, -74, -74, -74, -74, -74, -74, 0, 16, - 0, 0, -74, 0, 0, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, 0, -74, -74, 0, -74, - 0, -74, -74, -74, -74, 76, -74, 0, 77, 85, - 86, 71, 0, 0, 0, 0, 0, 49, 50, 51, + 24, 72, 4, 5, 6, 7, 8, 228, 40, 41, + 39, 231, 232, 43, 116, 45, 94, 48, 50, 125, + 116, 79, 117, 116, 150, 94, 76, 285, 84, 16, + 124, 137, 128, 129, 121, 121, 75, 278, 224, 151, + 133, 139, 17, 134, 113, 29, 30, 286, 233, 110, + 111, 112, 116, 113, 225, 279, 254, 214, 215, 140, + 138, 19, 20, 94, 156, 21, 22, 235, 23, 220, + 221, 1, 222, 17, 28, 75, 118, 119, 46, 274, + 205, 154, 118, 119, 277, 118, 119, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 17, 125, 118, 119, 255, 150, 198, 206, + 37, 187, 34, 194, 288, 188, 35, 189, 36, 306, + 307, 202, 151, 210, 203, 213, 193, 152, 38, 218, + 207, 220, 221, 261, 257, 141, 262, 227, 142, 227, + 44, 135, 146, 227, 227, 84, 144, 308, 147, 309, + 310, 148, 160, 313, 153, 84, 315, 157, 158, 186, + 244, 4, 5, 6, 7, 8, 159, 199, 211, 219, + 230, 94, 234, 246, 245, -124, 248, 249, 260, 251, + 258, 328, 247, 264, 241, 250, 275, 269, 16, 270, + 283, 129, 295, 276, 280, 281, 336, -123, 126, 89, + 90, 17, 122, 284, 294, 271, 287, 296, 272, 200, + 273, 227, 297, 298, 312, 92, 227, 316, 327, 317, + 19, 20, 94, 318, 21, 22, 329, 23, 282, 101, + 102, 204, 338, 256, 314, 289, 0, 0, 0, 0, + 0, 293, 106, 107, 108, 109, 110, 111, 112, 0, + 113, 0, 0, 0, 299, 300, 244, 0, 301, 302, + 0, 227, 227, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 241, 0, 0, 0, 0, 0, 320, 321, 0, 0, + 0, 0, 326, 0, 0, 0, 0, -79, 73, 0, + 0, 74, -79, 0, 75, 0, -79, -79, -79, -79, + -79, 0, 332, 333, 334, 0, 0, -79, -79, -79, + 337, 0, -79, -79, -79, 0, -79, 0, 0, 342, + -79, -79, -79, -79, -79, -79, -79, -79, -79, 0, + 0, 17, 0, 0, -79, 0, 0, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, 0, -79, -79, + 0, 0, -79, -79, -79, -79, -79, 80, -79, 0, + 81, 0, 0, 75, 0, 0, 0, 0, 0, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 223, 82, + 83, 81, 0, 0, 75, 0, 0, -161, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 0, 96, 97, 0, - 0, 0, 0, 0, 0, 16, 0, 0, 0, 101, - 102, 103, 104, 105, 106, 107, 0, 108, 0, 0, - 0, 0, 212, 0, 78, 77, 79, 0, 71, 0, - 0, 0, -155, 0, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 16, 0, 0, 187, 0, 0, 4, 5, - 6, 7, 8, 0, 0, 0, 0, 0, 9, 0, - 0, 78, 10, 79, 0, 0, 11, 12, 0, -155, - 0, 13, 0, 14, 15, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, - 0, 0, 0, 0, 18, 0, 19, 188, 20, 21, - 189, 22, 73, 0, 0, 4, 5, 6, 7, 8, - 0, 0, 0, 0, 0, 9, 0, 0, 0, 10, - 0, 0, 0, 11, 12, 0, 0, 0, 13, 0, - 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 195, 17, 0, 4, 5, 6, 7, 8, 0, 0, + 0, 0, 0, 9, 10, 0, 0, 0, 11, 0, + 82, 83, 12, 13, 0, 0, 0, 14, -161, 15, + 16, 77, 0, 0, 4, 5, 6, 7, 8, 0, + 0, 0, 0, 17, 9, 10, 0, 0, 0, 11, + 0, 0, 0, 12, 13, 18, 0, 0, 14, 0, + 15, 16, 19, 20, 0, 196, 21, 22, 197, 23, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, - 0, 18, 0, 19, 0, 20, 21, 74, 22, 46, + 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, + 0, 0, 0, 19, 20, 0, 0, 21, 22, 78, + 23, 49, 0, 0, 4, 5, 6, 7, 8, 0, + 0, 0, 0, 0, 9, 10, 0, 0, 0, 11, + 0, 0, 0, 12, 13, 0, 0, 0, 14, 0, + 15, 16, 212, 0, 0, 4, 5, 6, 7, 8, + 0, 0, 0, 0, 17, 9, 10, 0, 0, 0, + 11, 0, 0, 0, 12, 13, 18, 0, 0, 14, + 0, 15, 16, 19, 20, 0, 0, 21, 22, 0, + 23, 0, 0, 0, 0, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, + 0, 0, 0, 0, 19, 20, 0, 0, 21, 22, + 217, 23, 0, 4, 5, 6, 7, 8, 0, 0, + 0, 0, 0, 9, 10, 0, 0, 0, 11, 0, + 0, 0, 12, 13, 0, 0, 0, 14, 0, 15, + 16, 0, 0, 0, 4, 5, 6, 7, 8, 0, + 0, 0, 0, 17, 9, 10, 0, 0, 0, 11, + 0, 0, 0, 12, 13, 18, 0, 0, 14, 0, + 15, 16, 19, 20, 0, 0, 21, 22, 0, 23, + 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, + 0, 0, 127, 19, 20, 0, 0, 21, 22, 0, + 23, 4, 5, 6, 7, 8, 0, 0, 0, 0, + 0, 9, 10, 0, 0, 0, 11, 0, 0, 0, + 12, 13, 0, 0, 0, 14, 0, 15, 16, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0, - 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, - 11, 12, 0, 0, 0, 13, 0, 14, 15, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 17, 0, 0, 0, 0, 0, 0, 18, 0, - 19, 0, 20, 21, 202, 22, 0, 4, 5, 6, - 7, 8, 0, 0, 0, 0, 0, 9, 0, 0, - 0, 10, 0, 0, 0, 11, 12, 0, 0, 0, - 13, 0, 14, 15, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, - 0, 0, 0, 18, 0, 19, 0, 20, 21, 206, - 22, 0, 4, 5, 6, 7, 8, 0, 0, 0, - 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, - 11, 12, 0, 0, 0, 13, 0, 14, 15, 0, - 4, 5, 6, 7, 8, 0, 0, 0, 0, 16, - 9, 0, 0, 0, 10, 0, 0, 0, 11, 12, - 0, 17, 0, 13, 0, 14, 15, 0, 18, 0, - 19, 0, 20, 21, 0, 22, 0, 16, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, - 0, 0, 0, 0, 0, 122, 18, 0, 19, 0, - 20, 21, 0, 22, 4, 5, 6, 7, 8, 0, - 0, 0, 0, 0, 9, 0, 0, 0, 10, 0, - 0, 0, 11, 12, 0, 0, 0, 13, 0, 14, - 15, 0, 4, 5, 6, 7, 8, 0, 0, 0, - 0, 16, 9, 0, 0, 0, 10, 0, 0, 0, - 11, 12, 0, 17, 0, 13, 0, 14, 15, 0, - 18, 0, 19, 0, 20, 21, 278, 22, 0, 16, + 0, 17, 9, 10, 0, 0, 0, 11, 0, 0, + 0, 12, 13, 18, 0, 0, 14, 0, 15, 16, + 19, 20, 0, 0, 21, 22, 292, 23, 0, 0, + 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 18, -162, -162, 0, 0, 0, + 0, 19, 20, 0, 0, 21, 22, 0, 23, 4, + 5, 6, 7, 8, 0, 0, 0, 0, 94, 9, + 10, 0, 0, 0, 11, -162, -162, 0, 12, 13, + 0, 0, 0, 14, 0, 15, 16, 0, -162, -162, + 108, 109, 110, 111, 112, 0, 113, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 17, 0, 0, 0, 0, 0, 0, 18, 0, - 19, 226, 20, 21, 227, 22, 0, 71, 0, 0, - 0, 0, 0, 49, 50, 51, 52, 53, 54, 55, + 0, 18, 0, 0, 237, 0, 0, 238, 42, 20, + 75, 0, 21, 22, 0, 23, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 16, 84, 85, 86, 87, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 88, 89, - 228, 0, 229, 0, 0, 90, 91, 92, 93, 94, - 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 0, 108, 84, 85, 86, 87, 241, 0, 0, 242, - 0, 0, 0, 0, 0, 0, 0, 0, 88, 89, - 0, 0, 0, 0, 0, 90, 91, 92, 93, 94, - 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 0, 108, 84, 85, 86, 87, 0, 0, 0, 142, - 0, 0, 0, 0, 0, 0, 0, 0, 88, 89, - 0, 0, 0, 0, 0, 90, 91, 92, 93, 94, - 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 0, 108, 84, 85, 86, 87, 0, 0, 0, 276, - 0, 0, 0, 0, 0, 0, 0, 0, 88, 89, - 0, 0, 0, 0, 0, 90, 91, 92, 93, 94, - 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 0, 108, 84, 85, 86, 87, 0, 0, 0, 277, - 0, 0, 0, 0, 0, 0, 0, 0, 88, 89, - 0, 0, 0, 0, 0, 90, 91, 92, 93, 94, - 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 0, 108, 84, 85, 86, 87, 0, 0, 0, 302, - 0, 0, 0, 0, 0, 0, 0, 0, 88, 89, - 0, 0, 0, 0, 0, 90, 91, 92, 93, 94, - 95, 96, 97, 0, 0, 0, 0, 0, 0, 0, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 0, 108, 318, 0, 319, 84, 85, 86, 87, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 88, 89, 0, 0, 0, 0, 0, 90, 91, - 92, 93, 94, 95, 96, 97, 0, 0, 0, 84, - 85, 86, 87, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 0, 108, 88, 89, 138, 0, 0, - 0, 0, 90, 91, 92, 93, 94, 95, 96, 97, - 0, 0, 0, 84, 85, 86, 87, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 0, 108, 88, - 89, 218, 0, 0, 0, 0, 90, 91, 92, 93, - 94, 95, 96, 97, 0, 0, 0, 84, 85, 86, - 87, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 88, 89, 294, 0, 0, 0, 0, - 90, 91, 92, 93, 94, 95, 96, 97, 0, 0, - 0, 84, 85, 86, 87, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 0, 108, 88, 89, 317, - 0, 0, 0, 0, 90, 91, 92, 93, 94, 95, - 96, 97, 0, 0, 0, 84, 85, 86, 87, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 0, - 108, 88, 89, 321, 0, 0, 0, 0, 90, 91, - 92, 93, 94, 95, 96, 97, 0, 0, 0, 0, - 0, 0, 0, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 0, 108, 109, 84, 85, 86, 87, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 88, 89, 0, 0, 0, 0, 0, 90, - 91, 92, 93, 94, 95, 96, 97, 0, 0, 0, - 0, 0, 0, 0, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 0, 108, 193, 84, 85, 86, - 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 88, 89, 0, 0, 0, 0, 0, - 90, 91, 92, 93, 94, 95, 96, 97, 0, 0, - 0, 0, 0, 0, 0, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 0, 108, 251, 84, 85, - 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 88, 89, 0, 0, 0, 0, - 0, 90, 91, 92, 93, 94, 95, 96, 97, 0, - 0, 0, 0, 0, 0, 0, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 0, 108, 306, 84, - 85, 86, 87, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 88, 89, 0, 0, 0, - 0, 0, 90, 91, 92, 93, 94, 95, 96, 97, - 0, 0, 0, 0, 0, 0, 0, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 0, 108, 307, - 84, 85, 86, 87, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 88, 89, 0, 0, - 0, 0, 0, 90, 91, 92, 93, 94, 95, 96, - 97, 0, 0, 0, 0, 0, 0, 0, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 0, 108, - 311, 84, 85, 86, 87, 0, 0, 0, 0, 0, - 0, 0, 252, 253, 0, 0, 254, 88, 89, 0, - 0, 0, 0, 0, 90, 91, 92, 93, 94, 95, - 96, 97, 0, 0, 0, 0, 0, 0, 0, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 0, - 108, 84, 85, 86, 87, 0, 0, 0, 0, 0, - 0, 0, 252, 253, 0, 0, 0, 88, 89, 0, - 0, 0, 0, 0, 90, 91, 92, 93, 94, 95, - 96, 97, 0, 0, 0, 0, 0, 0, 0, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 0, - 108, 84, 85, 86, 87, 0, 0, 0, 0, 0, - 0, 130, 0, 0, 0, 0, 0, 88, 89, 0, - 0, 0, 0, 0, 90, 91, 92, 93, 94, 95, - 96, 97, 0, 0, 0, 84, 85, 86, 87, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 0, - 108, 88, 89, 0, 0, 0, 0, 0, 90, 91, - 92, 93, 94, 95, 96, 97, 0, 0, 0, 0, - 288, 0, 0, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 0, 108, 84, 85, 86, 87, 0, + 66, 67, 68, 69, 70, 71, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, + 0, 88, 89, 90, 91, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 239, 240, 92, 93, + 0, 0, 0, 0, 0, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 0, 0, 0, 0, 88, 89, + 90, 91, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 0, 113, 0, 92, 93, 0, 252, 0, + 0, 253, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 0, 0, 0, 0, 88, 89, 90, 91, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 0, + 113, 0, 92, 93, 0, 0, 0, 0, 149, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 0, 0, + 0, 0, 88, 89, 90, 91, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 0, 113, 0, 92, + 93, 0, 0, 0, 0, 290, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 0, 0, 0, 0, 88, + 89, 90, 91, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 0, 113, 0, 92, 93, 0, 0, + 0, 0, 291, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 0, 0, 0, 0, 88, 89, 90, 91, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 0, 113, 0, 92, 93, 0, 0, 0, 0, 319, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 0, + 0, 0, 0, 88, 89, 90, 91, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 0, 113, 216, + 92, 93, 145, 0, 0, 0, 0, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 0, 0, 0, 0, + 88, 89, 90, 91, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 0, 113, 303, 92, 93, 304, + 0, 0, 0, 0, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 0, 0, 0, 0, 88, 89, 90, + 91, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 0, 113, 340, 92, 93, 341, 0, 0, 0, + 0, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 0, 0, 0, 88, 89, 90, 91, 0, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 0, 113, + 92, 93, 0, 145, 0, 0, 0, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 0, 0, 0, 88, + 89, 90, 91, 0, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 0, 113, 92, 93, 0, 229, + 0, 0, 0, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 0, 0, 0, 88, 89, 90, 91, 0, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 0, 113, 92, 93, 0, 311, 0, 0, 0, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 0, 0, + 0, 88, 89, 90, 91, 0, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 0, 113, 92, 93, + 0, 335, 0, 0, 0, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 0, 0, 0, 88, 89, 90, + 91, 0, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 0, 113, 92, 93, 0, 339, 0, 0, + 0, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 0, 0, 0, 88, 89, 90, 91, 0, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 0, 113, + 92, 93, 0, 343, 0, 0, 0, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 0, 0, 0, 0, + 88, 89, 90, 91, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 0, 113, 114, 92, 93, 0, + 0, 0, 0, 0, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 0, 0, 0, 0, 88, 89, 90, + 91, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 0, 113, 201, 92, 93, 0, 0, 0, 0, + 0, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 0, 0, 0, 0, 88, 89, 90, 91, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 0, 113, + 263, 92, 93, 0, 0, 0, 0, 0, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 0, 0, 0, + 0, 88, 89, 90, 91, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 0, 113, 324, 92, 93, + 0, 0, 0, 0, 0, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 0, 0, 0, 0, 88, 89, + 90, 91, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 0, 113, 325, 92, 93, 0, 0, 0, + 0, 0, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 0, 0, 0, 0, 88, 89, 90, 91, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 0, + 113, 330, 92, 93, 0, 0, 0, 0, 0, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 0, 0, + 0, 0, 0, 0, 0, 0, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 0, 113, 331, 88, + 89, 90, 91, 0, 0, 0, 0, 0, 0, 0, + 0, 265, 266, 0, 0, 267, 92, 93, 0, 0, + 0, 0, 0, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 0, 0, 0, 0, 0, 0, 0, 0, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 0, 113, 88, 89, 90, 91, 0, 0, 0, 0, + 0, 0, 0, 0, 265, 266, 0, 0, 0, 92, + 93, 0, 0, 0, 0, 0, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 0, 0, 0, 0, 0, + 0, 0, 0, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 0, 113, 88, 89, 90, 91, 0, + 0, 0, 0, 0, 0, 0, 136, 0, 0, 0, + 0, 0, 92, 93, 0, 0, 0, 0, 0, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 0, 0, + 0, 88, 89, 90, 91, 0, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 0, 113, 92, 93, + 0, 0, 0, 0, 0, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 0, 0, 0, 0, 0, 305, + 0, 0, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 0, 113, 88, 89, 90, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 304, 88, 89, 0, 0, 0, 0, 0, 90, 91, - 92, 93, 94, 95, 96, 97, 0, 0, 0, 0, - 0, 0, 0, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 0, 108, 84, 85, 86, 87, 0, - 0, 0, 0, 0, 0, 305, 0, 0, 0, 0, - 0, 88, 89, 0, 0, 0, 0, 0, 90, 91, - 92, 93, 94, 95, 96, 97, 0, 0, 0, 84, - 85, 86, 87, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 0, 108, 88, 89, 0, 0, 0, - 0, 0, 90, 91, 92, 93, 94, 95, 96, 97, - 0, 0, 0, 84, 85, 86, 87, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 0, 108, 88, - 89, 0, 0, 0, 0, 0, 90, 91, 92, 93, - 94, 95, 96, 97, 0, 0, 0, -156, 85, 86, - 0, 0, 0, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 88, 89, 0, 0, 0, 0, 0, - -156, -156, -156, -156, -156, -156, 96, 97, 0, 0, - 85, 86, 0, 0, 0, 0, 0, -156, 101, 102, - 103, 104, 105, 106, 107, 88, 108, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 96, 97, + 322, 92, 93, 0, 0, 0, 0, 0, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 0, 0, 0, + 0, 0, 0, 0, 0, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 0, 113, 88, 89, 90, + 91, 0, 0, 0, 0, 0, 0, 0, 323, 0, + 0, 0, 0, 0, 92, 93, 0, 0, 0, 0, + 0, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 0, 0, 0, 88, 89, 90, 91, 0, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 0, 113, + 92, 93, 0, 0, 0, 0, 0, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 0, 0, 0, 88, + 89, 90, 91, 0, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 0, 113, 92, 93, 0, 0, + 0, 0, 0, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 0, 0, 0, -162, 89, 90, 0, 0, + 0, 0, 105, 106, 107, 108, 109, 110, 111, 112, + 0, 113, 92, 93, 0, 0, 0, 0, 0, 94, + -162, -162, -162, -162, -162, -162, 101, 102, 89, 90, + 0, 0, 0, 0, 0, 0, 0, 0, -162, 106, + 107, 108, 109, 110, 111, 112, 0, 113, 0, 0, + 0, 94, 0, 0, 0, 0, 0, 0, 101, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 101, 102, 103, 104, 105, 106, 107, 48, 108, 0, - 0, 0, 0, 0, 0, 0, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 148, 0, 0, 0, 0, - 0, 0, 0, 0, 49, 50, 51, 52, 53, 54, + 0, 106, 107, 108, 109, 110, 111, 112, 51, 113, + 0, 0, 0, 0, 0, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 247, 0, 0, 0, 0, 0, 0, - 0, 0, 49, 50, 51, 52, 53, 54, 55, 56, + 65, 66, 67, 68, 69, 70, 71, 155, 0, 0, + 0, 0, 0, 0, 0, 0, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 259, 0, 0, 0, + 0, 0, 0, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67 + 67, 68, 69, 70, 71 }; static const yytype_int16 yycheck[] = { - 1, 19, 1, 48, 7, 5, 146, 11, 12, 10, - 150, 151, 13, 13, 4, 4, 17, 18, 63, 30, - 21, 7, 5, 68, 180, 20, 48, 22, 48, 30, - 13, 32, 33, 28, 29, 48, 62, 143, 41, 65, - 59, 67, 61, 63, 16, 17, 68, 153, 54, 55, - 56, 60, 58, 66, 63, 41, 5, 59, 15, 61, - 5, 79, 65, 62, 64, 65, 42, 43, 13, 45, - 131, 132, 62, 62, 214, 0, 60, 78, 234, 219, - 58, 64, 65, 84, 85, 86, 87, 88, 89, 90, + 1, 20, 4, 5, 6, 7, 8, 153, 12, 13, + 11, 157, 158, 14, 5, 1, 33, 18, 19, 31, + 5, 22, 13, 5, 51, 33, 21, 51, 23, 31, + 31, 13, 33, 34, 29, 30, 7, 51, 150, 66, + 63, 42, 44, 66, 61, 17, 18, 71, 160, 57, + 58, 59, 5, 61, 56, 69, 4, 137, 138, 29, + 13, 63, 64, 33, 83, 67, 68, 188, 70, 45, + 46, 16, 48, 44, 0, 7, 67, 68, 64, 225, + 4, 82, 67, 68, 230, 67, 68, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 41, 264, 120, - 266, 267, 4, 114, 270, 64, 65, 273, 113, 64, - 65, 261, 262, 42, 43, 62, 45, 28, 129, 130, - 4, 4, 133, 61, 4, 5, 6, 7, 8, 295, - 144, 1, 146, 58, 66, 63, 150, 151, 143, 63, - 63, 68, 308, 48, 58, 13, 47, 63, 153, 58, - 30, 4, 40, 181, 47, 4, 5, 6, 7, 8, - 58, 41, 40, 66, 58, 60, 47, 63, 60, 4, - 198, 58, 63, 53, 185, 4, 181, 188, 63, 40, - 60, 30, 62, 194, 64, 65, 63, 67, 63, 63, - 63, 58, 41, 58, 58, 58, 249, 208, 31, 210, - 214, 63, 120, 29, 312, 219, 127, 194, 271, 10, - 11, 60, -1, 62, -1, 64, 65, 228, 67, -1, - -1, -1, -1, -1, 235, -1, -1, -1, -1, -1, - 241, -1, -1, -1, -1, -1, -1, 38, 39, -1, - -1, 252, 253, 271, -1, 256, 257, 261, 262, 50, - 51, 52, 53, 54, 55, 56, -1, 58, -1, -1, - -1, -1, -1, -1, -1, -1, 271, -1, -1, -1, - -1, -1, 283, -1, -1, -1, -1, -1, 0, 1, - -1, -1, 4, 5, -1, 7, -1, 9, 10, 11, - 12, 13, -1, -1, 305, 306, 307, 19, 20, 21, - -1, -1, 24, 25, 26, -1, 28, 318, -1, -1, - 32, 33, 34, 35, 36, 37, 38, 39, -1, 41, - -1, -1, 44, -1, -1, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, -1, 58, 59, -1, 61, - -1, 63, 64, 65, 66, 1, 68, -1, 4, 10, - 11, 7, -1, -1, -1, -1, -1, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, -1, 38, 39, -1, - -1, -1, -1, -1, -1, 41, -1, -1, -1, 50, - 51, 52, 53, 54, 55, 56, -1, 58, -1, -1, - -1, -1, 1, -1, 60, 4, 62, -1, 7, -1, - -1, -1, 68, -1, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 41, -1, -1, 1, -1, -1, 4, 5, - 6, 7, 8, -1, -1, -1, -1, -1, 14, -1, - -1, 60, 18, 62, -1, -1, 22, 23, -1, 68, - -1, 27, -1, 29, 30, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, - -1, -1, -1, -1, 60, -1, 62, 63, 64, 65, - 66, 67, 1, -1, -1, 4, 5, 6, 7, 8, - -1, -1, -1, -1, -1, 14, -1, -1, -1, 18, - -1, -1, -1, 22, 23, -1, -1, -1, 27, -1, - 29, 30, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 41, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, - -1, 60, -1, 62, -1, 64, 65, 66, 67, 1, - -1, -1, 4, 5, 6, 7, 8, -1, -1, -1, - -1, -1, 14, -1, -1, -1, 18, -1, -1, -1, - 22, 23, -1, -1, -1, 27, -1, 29, 30, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 44, 125, 67, 68, 64, 51, 119, 43, + 4, 64, 63, 118, 245, 68, 61, 70, 44, 275, + 276, 62, 66, 134, 65, 136, 68, 71, 63, 140, + 64, 45, 46, 62, 48, 4, 65, 151, 4, 153, + 64, 64, 1, 157, 158, 150, 65, 278, 61, 280, + 281, 69, 51, 284, 66, 160, 287, 66, 66, 61, + 189, 4, 5, 6, 7, 8, 71, 13, 65, 50, + 66, 33, 4, 50, 42, 42, 61, 69, 207, 61, + 4, 312, 193, 4, 189, 196, 50, 63, 31, 63, + 4, 202, 4, 66, 66, 66, 327, 42, 32, 10, + 11, 44, 30, 66, 61, 216, 66, 261, 219, 125, + 221, 225, 66, 66, 66, 26, 230, 61, 66, 61, + 63, 64, 33, 61, 67, 68, 61, 70, 239, 40, + 41, 132, 332, 202, 285, 246, -1, -1, -1, -1, + -1, 252, 53, 54, 55, 56, 57, 58, 59, -1, + 61, -1, -1, -1, 265, 266, 285, -1, 269, 270, + -1, 275, 276, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 53, -1, -1, -1, -1, -1, -1, 60, -1, - 62, -1, 64, 65, 1, 67, -1, 4, 5, 6, - 7, 8, -1, -1, -1, -1, -1, 14, -1, -1, - -1, 18, -1, -1, -1, 22, 23, -1, -1, -1, - 27, -1, 29, 30, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, - -1, -1, -1, 60, -1, 62, -1, 64, 65, 1, - 67, -1, 4, 5, 6, 7, 8, -1, -1, -1, - -1, -1, 14, -1, -1, -1, 18, -1, -1, -1, - 22, 23, -1, -1, -1, 27, -1, 29, 30, -1, - 4, 5, 6, 7, 8, -1, -1, -1, -1, 41, - 14, -1, -1, -1, 18, -1, -1, -1, 22, 23, - -1, 53, -1, 27, -1, 29, 30, -1, 60, -1, - 62, -1, 64, 65, -1, 67, -1, 41, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, - -1, -1, -1, -1, -1, 59, 60, -1, 62, -1, - 64, 65, -1, 67, 4, 5, 6, 7, 8, -1, - -1, -1, -1, -1, 14, -1, -1, -1, 18, -1, - -1, -1, 22, 23, -1, -1, -1, 27, -1, 29, - 30, -1, 4, 5, 6, 7, 8, -1, -1, -1, - -1, 41, 14, -1, -1, -1, 18, -1, -1, -1, - 22, 23, -1, 53, -1, 27, -1, 29, 30, -1, - 60, -1, 62, -1, 64, 65, 66, 67, -1, 41, + 285, -1, -1, -1, -1, -1, 297, 298, -1, -1, + -1, -1, 303, -1, -1, -1, -1, 0, 1, -1, + -1, 4, 5, -1, 7, -1, 9, 10, 11, 12, + 13, -1, 323, 324, 325, -1, -1, 20, 21, 22, + 331, -1, 25, 26, 27, -1, 29, -1, -1, 340, + 33, 34, 35, 36, 37, 38, 39, 40, 41, -1, + -1, 44, -1, -1, 47, -1, -1, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, -1, 61, 62, + -1, -1, 65, 66, 67, 68, 69, 1, 71, -1, + 4, -1, -1, 7, -1, -1, -1, -1, -1, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 53, -1, -1, -1, -1, -1, -1, 60, -1, - 62, 1, 64, 65, 4, 67, -1, 7, -1, -1, - -1, -1, -1, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 41, 9, 10, 11, 12, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - 60, -1, 62, -1, -1, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, -1, -1, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - -1, 58, 9, 10, 11, 12, 63, -1, -1, 66, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - -1, -1, -1, -1, -1, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, -1, -1, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - -1, 58, 9, 10, 11, 12, -1, -1, -1, 66, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - -1, -1, -1, -1, -1, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, -1, -1, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - -1, 58, 9, 10, 11, 12, -1, -1, -1, 66, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - -1, -1, -1, -1, -1, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, -1, -1, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - -1, 58, 9, 10, 11, 12, -1, -1, -1, 66, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - -1, -1, -1, -1, -1, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, -1, -1, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - -1, 58, 9, 10, 11, 12, -1, -1, -1, 66, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - -1, -1, -1, -1, -1, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, -1, -1, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - -1, 58, 59, -1, 61, 9, 10, 11, 12, -1, + 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1, 63, + 64, 4, -1, -1, 7, -1, -1, 71, -1, -1, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 25, 26, -1, -1, -1, -1, -1, 32, 33, - 34, 35, 36, 37, 38, 39, -1, -1, -1, 9, - 10, 11, 12, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, -1, 58, 25, 26, 61, -1, -1, - -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, - -1, -1, -1, 9, 10, 11, 12, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, -1, 58, 25, - 26, 61, -1, -1, -1, -1, 32, 33, 34, 35, - 36, 37, 38, 39, -1, -1, -1, 9, 10, 11, - 12, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, -1, 58, 25, 26, 61, -1, -1, -1, -1, - 32, 33, 34, 35, 36, 37, 38, 39, -1, -1, - -1, 9, 10, 11, 12, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, -1, 58, 25, 26, 61, - -1, -1, -1, -1, 32, 33, 34, 35, 36, 37, - 38, 39, -1, -1, -1, 9, 10, 11, 12, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, - 58, 25, 26, 61, -1, -1, -1, -1, 32, 33, - 34, 35, 36, 37, 38, 39, -1, -1, -1, -1, - -1, -1, -1, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, -1, 58, 59, 9, 10, 11, 12, + 1, 44, -1, 4, 5, 6, 7, 8, -1, -1, + -1, -1, -1, 14, 15, -1, -1, -1, 19, -1, + 63, 64, 23, 24, -1, -1, -1, 28, 71, 30, + 31, 1, -1, -1, 4, 5, 6, 7, 8, -1, + -1, -1, -1, 44, 14, 15, -1, -1, -1, 19, + -1, -1, -1, 23, 24, 56, -1, -1, 28, -1, + 30, 31, 63, 64, -1, 66, 67, 68, 69, 70, + -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 56, -1, -1, -1, + -1, -1, -1, 63, 64, -1, -1, 67, 68, 69, + 70, 1, -1, -1, 4, 5, 6, 7, 8, -1, + -1, -1, -1, -1, 14, 15, -1, -1, -1, 19, + -1, -1, -1, 23, 24, -1, -1, -1, 28, -1, + 30, 31, 1, -1, -1, 4, 5, 6, 7, 8, + -1, -1, -1, -1, 44, 14, 15, -1, -1, -1, + 19, -1, -1, -1, 23, 24, 56, -1, -1, 28, + -1, 30, 31, 63, 64, -1, -1, 67, 68, -1, + 70, -1, -1, -1, -1, 44, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 56, -1, -1, + -1, -1, -1, -1, 63, 64, -1, -1, 67, 68, + 1, 70, -1, 4, 5, 6, 7, 8, -1, -1, + -1, -1, -1, 14, 15, -1, -1, -1, 19, -1, + -1, -1, 23, 24, -1, -1, -1, 28, -1, 30, + 31, -1, -1, -1, 4, 5, 6, 7, 8, -1, + -1, -1, -1, 44, 14, 15, -1, -1, -1, 19, + -1, -1, -1, 23, 24, 56, -1, -1, 28, -1, + 30, 31, 63, 64, -1, -1, 67, 68, -1, 70, + -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 56, -1, -1, -1, + -1, -1, 62, 63, 64, -1, -1, 67, 68, -1, + 70, 4, 5, 6, 7, 8, -1, -1, -1, -1, + -1, 14, 15, -1, -1, -1, 19, -1, -1, -1, + 23, 24, -1, -1, -1, 28, -1, 30, 31, -1, + -1, -1, 4, 5, 6, 7, 8, -1, -1, -1, + -1, 44, 14, 15, -1, -1, -1, 19, -1, -1, + -1, 23, 24, 56, -1, -1, 28, -1, 30, 31, + 63, 64, -1, -1, 67, 68, 69, 70, -1, -1, + -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 56, 10, 11, -1, -1, -1, + -1, 63, 64, -1, -1, 67, 68, -1, 70, 4, + 5, 6, 7, 8, -1, -1, -1, -1, 33, 14, + 15, -1, -1, -1, 19, 40, 41, -1, 23, 24, + -1, -1, -1, 28, -1, 30, 31, -1, 53, 54, + 55, 56, 57, 58, 59, -1, 61, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 25, 26, -1, -1, -1, -1, -1, 32, - 33, 34, 35, 36, 37, 38, 39, -1, -1, -1, - -1, -1, -1, -1, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, -1, 58, 59, 9, 10, 11, - 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 25, 26, -1, -1, -1, -1, -1, - 32, 33, 34, 35, 36, 37, 38, 39, -1, -1, - -1, -1, -1, -1, -1, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, -1, 58, 59, 9, 10, - 11, 12, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 25, 26, -1, -1, -1, -1, - -1, 32, 33, 34, 35, 36, 37, 38, 39, -1, - -1, -1, -1, -1, -1, -1, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, -1, 58, 59, 9, + -1, 56, -1, -1, 1, -1, -1, 4, 63, 64, + 7, -1, 67, 68, -1, 70, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 44, -1, -1, + -1, 9, 10, 11, 12, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 63, 64, 26, 27, + -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, + 38, 39, 40, 41, -1, -1, -1, -1, 9, 10, + 11, 12, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, -1, 61, -1, 26, 27, -1, 66, -1, + -1, 69, 33, 34, 35, 36, 37, 38, 39, 40, + 41, -1, -1, -1, -1, 9, 10, 11, 12, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, -1, + 61, -1, 26, 27, -1, -1, -1, -1, 69, 33, + 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, + -1, -1, 9, 10, 11, 12, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, -1, 61, -1, 26, + 27, -1, -1, -1, -1, 69, 33, 34, 35, 36, + 37, 38, 39, 40, 41, -1, -1, -1, -1, 9, + 10, 11, 12, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, -1, 61, -1, 26, 27, -1, -1, + -1, -1, 69, 33, 34, 35, 36, 37, 38, 39, + 40, 41, -1, -1, -1, -1, 9, 10, 11, 12, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + -1, 61, -1, 26, 27, -1, -1, -1, -1, 69, + 33, 34, 35, 36, 37, 38, 39, 40, 41, -1, + -1, -1, -1, 9, 10, 11, 12, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, -1, 61, 62, + 26, 27, 65, -1, -1, -1, -1, 33, 34, 35, + 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, + 9, 10, 11, 12, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, -1, 61, 62, 26, 27, 65, + -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, + 39, 40, 41, -1, -1, -1, -1, 9, 10, 11, + 12, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, -1, 61, 62, 26, 27, 65, -1, -1, -1, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, -1, -1, 9, 10, 11, 12, -1, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, -1, 61, + 26, 27, -1, 65, -1, -1, -1, 33, 34, 35, + 36, 37, 38, 39, 40, 41, -1, -1, -1, 9, + 10, 11, 12, -1, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, -1, 61, 26, 27, -1, 65, + -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, + 40, 41, -1, -1, -1, 9, 10, 11, 12, -1, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + -1, 61, 26, 27, -1, 65, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, + -1, 9, 10, 11, 12, -1, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, -1, 61, 26, 27, + -1, 65, -1, -1, -1, 33, 34, 35, 36, 37, + 38, 39, 40, 41, -1, -1, -1, 9, 10, 11, + 12, -1, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, -1, 61, 26, 27, -1, 65, -1, -1, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, -1, -1, 9, 10, 11, 12, -1, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, -1, 61, + 26, 27, -1, 65, -1, -1, -1, 33, 34, 35, + 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, + 9, 10, 11, 12, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, -1, 61, 62, 26, 27, -1, + -1, -1, -1, -1, 33, 34, 35, 36, 37, 38, + 39, 40, 41, -1, -1, -1, -1, 9, 10, 11, + 12, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, -1, 61, 62, 26, 27, -1, -1, -1, -1, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, -1, -1, -1, 9, 10, 11, 12, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, -1, 61, + 62, 26, 27, -1, -1, -1, -1, -1, 33, 34, + 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, + -1, 9, 10, 11, 12, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, -1, 61, 62, 26, 27, + -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, + 38, 39, 40, 41, -1, -1, -1, -1, 9, 10, + 11, 12, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, -1, 61, 62, 26, 27, -1, -1, -1, + -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, + 41, -1, -1, -1, -1, 9, 10, 11, 12, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, -1, + 61, 62, 26, 27, -1, -1, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, + -1, -1, -1, -1, -1, -1, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, -1, 61, 62, 9, 10, 11, 12, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 25, 26, -1, -1, -1, - -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, - -1, -1, -1, -1, -1, -1, -1, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, -1, 58, 59, - 9, 10, 11, 12, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 25, 26, -1, -1, - -1, -1, -1, 32, 33, 34, 35, 36, 37, 38, - 39, -1, -1, -1, -1, -1, -1, -1, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, -1, 58, - 59, 9, 10, 11, 12, -1, -1, -1, -1, -1, - -1, -1, 20, 21, -1, -1, 24, 25, 26, -1, - -1, -1, -1, -1, 32, 33, 34, 35, 36, 37, - 38, 39, -1, -1, -1, -1, -1, -1, -1, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, - 58, 9, 10, 11, 12, -1, -1, -1, -1, -1, - -1, -1, 20, 21, -1, -1, -1, 25, 26, -1, - -1, -1, -1, -1, 32, 33, 34, 35, 36, 37, - 38, 39, -1, -1, -1, -1, -1, -1, -1, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, - 58, 9, 10, 11, 12, -1, -1, -1, -1, -1, - -1, 19, -1, -1, -1, -1, -1, 25, 26, -1, - -1, -1, -1, -1, 32, 33, 34, 35, 36, 37, - 38, 39, -1, -1, -1, 9, 10, 11, 12, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, - 58, 25, 26, -1, -1, -1, -1, -1, 32, 33, - 34, 35, 36, 37, 38, 39, -1, -1, -1, -1, - 44, -1, -1, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, -1, 58, 9, 10, 11, 12, -1, + -1, 21, 22, -1, -1, 25, 26, 27, -1, -1, + -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, + 40, 41, -1, -1, -1, -1, -1, -1, -1, -1, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + -1, 61, 9, 10, 11, 12, -1, -1, -1, -1, + -1, -1, -1, -1, 21, 22, -1, -1, -1, 26, + 27, -1, -1, -1, -1, -1, 33, 34, 35, 36, + 37, 38, 39, 40, 41, -1, -1, -1, -1, -1, + -1, -1, -1, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, -1, 61, 9, 10, 11, 12, -1, + -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, + -1, -1, 26, 27, -1, -1, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, + -1, 9, 10, 11, 12, -1, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, -1, 61, 26, 27, + -1, -1, -1, -1, -1, 33, 34, 35, 36, 37, + 38, 39, 40, 41, -1, -1, -1, -1, -1, 47, + -1, -1, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, -1, 61, 9, 10, 11, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 24, 25, 26, -1, -1, -1, -1, -1, 32, 33, - 34, 35, 36, 37, 38, 39, -1, -1, -1, -1, - -1, -1, -1, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, -1, 58, 9, 10, 11, 12, -1, - -1, -1, -1, -1, -1, 19, -1, -1, -1, -1, - -1, 25, 26, -1, -1, -1, -1, -1, 32, 33, - 34, 35, 36, 37, 38, 39, -1, -1, -1, 9, - 10, 11, 12, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, -1, 58, 25, 26, -1, -1, -1, - -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, - -1, -1, -1, 9, 10, 11, 12, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, -1, 58, 25, - 26, -1, -1, -1, -1, -1, 32, 33, 34, 35, - 36, 37, 38, 39, -1, -1, -1, 9, 10, 11, - -1, -1, -1, 49, 50, 51, 52, 53, 54, 55, - 56, -1, 58, 25, 26, -1, -1, -1, -1, -1, - 32, 33, 34, 35, 36, 37, 38, 39, -1, -1, - 10, 11, -1, -1, -1, -1, -1, 49, 50, 51, - 52, 53, 54, 55, 56, 25, 58, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 38, 39, + 25, 26, 27, -1, -1, -1, -1, -1, 33, 34, + 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, + -1, -1, -1, -1, -1, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, -1, 61, 9, 10, 11, + 12, -1, -1, -1, -1, -1, -1, -1, 20, -1, + -1, -1, -1, -1, 26, 27, -1, -1, -1, -1, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, -1, -1, 9, 10, 11, 12, -1, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, -1, 61, + 26, 27, -1, -1, -1, -1, -1, 33, 34, 35, + 36, 37, 38, 39, 40, 41, -1, -1, -1, 9, + 10, 11, 12, -1, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, -1, 61, 26, 27, -1, -1, + -1, -1, -1, 33, 34, 35, 36, 37, 38, 39, + 40, 41, -1, -1, -1, 9, 10, 11, -1, -1, + -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, + -1, 61, 26, 27, -1, -1, -1, -1, -1, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 10, 11, + -1, -1, -1, -1, -1, -1, -1, -1, 52, 53, + 54, 55, 56, 57, 58, 59, -1, 61, -1, -1, + -1, 33, -1, -1, -1, -1, -1, -1, 40, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 50, 51, 52, 53, 54, 55, 56, 4, 58, -1, + -1, 53, 54, 55, 56, 57, 58, 59, 4, 61, + -1, -1, -1, -1, -1, -1, -1, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 4, -1, -1, -1, -1, -1, -1, -1, -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 4, -1, -1, -1, -1, - -1, -1, -1, -1, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 4, -1, -1, -1, -1, -1, -1, - -1, -1, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31 + 27, 28, 29, 30, 31, 32, 4, -1, -1, -1, + -1, -1, -1, -1, -1, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = +static const yytype_int8 yystos[] = { - 0, 15, 70, 71, 4, 5, 6, 7, 8, 14, - 18, 22, 23, 27, 29, 30, 41, 53, 60, 62, - 64, 65, 67, 74, 78, 81, 87, 0, 16, 17, - 72, 75, 76, 60, 58, 41, 4, 74, 87, 87, - 74, 62, 1, 62, 82, 74, 1, 74, 4, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 96, 1, - 4, 7, 81, 1, 66, 74, 1, 4, 60, 62, - 81, 96, 97, 98, 9, 10, 11, 12, 25, 26, - 32, 33, 34, 35, 36, 37, 38, 39, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, - 74, 5, 13, 64, 65, 77, 81, 77, 73, 74, - 78, 72, 59, 74, 74, 88, 89, 83, 60, 63, - 19, 13, 13, 28, 4, 4, 84, 61, 61, 1, - 58, 66, 66, 48, 63, 68, 63, 74, 4, 96, - 63, 63, 68, 48, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 58, 62, - 65, 67, 90, 91, 92, 65, 81, 1, 63, 66, - 74, 13, 73, 59, 59, 61, 84, 4, 62, 79, - 80, 74, 1, 74, 91, 91, 1, 74, 47, 42, - 43, 45, 1, 97, 53, 86, 87, 86, 61, 63, - 86, 86, 97, 4, 92, 93, 1, 4, 60, 62, - 81, 94, 95, 96, 40, 47, 74, 58, 66, 74, - 58, 63, 66, 4, 62, 89, 45, 4, 96, 59, - 61, 59, 20, 21, 24, 85, 60, 60, 74, 74, - 86, 47, 63, 86, 48, 66, 63, 63, 74, 4, - 63, 48, 68, 63, 92, 74, 66, 66, 66, 74, - 58, 4, 80, 63, 74, 74, 74, 74, 44, 86, - 86, 92, 92, 92, 61, 63, 92, 95, 92, 58, - 58, 58, 66, 74, 24, 19, 59, 59, 63, 92, - 58, 59, 74, 74, 74, 92, 85, 61, 59, 61, - 74, 61 + 0, 16, 73, 74, 4, 5, 6, 7, 8, 14, + 15, 19, 23, 24, 28, 30, 31, 44, 56, 63, + 64, 67, 68, 70, 77, 81, 84, 90, 0, 17, + 18, 75, 78, 79, 63, 61, 44, 4, 63, 77, + 90, 90, 63, 77, 64, 1, 64, 85, 77, 1, + 77, 4, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 99, 1, 4, 7, 84, 1, 69, 77, + 1, 4, 63, 64, 84, 99, 100, 101, 9, 10, + 11, 12, 26, 27, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 61, 62, 77, 5, 13, 67, 68, + 80, 84, 80, 76, 77, 81, 75, 62, 77, 77, + 91, 92, 86, 63, 66, 64, 20, 13, 13, 77, + 29, 4, 4, 87, 65, 65, 1, 61, 69, 69, + 51, 66, 71, 66, 77, 4, 99, 66, 66, 71, + 51, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 61, 64, 68, 70, + 93, 94, 95, 68, 84, 1, 66, 69, 77, 13, + 76, 62, 62, 65, 87, 4, 43, 64, 82, 83, + 77, 65, 1, 77, 94, 94, 62, 1, 77, 50, + 45, 46, 48, 1, 100, 56, 89, 90, 89, 65, + 66, 89, 89, 100, 4, 95, 96, 1, 4, 63, + 64, 84, 97, 98, 99, 42, 50, 77, 61, 69, + 77, 61, 66, 69, 4, 64, 92, 48, 4, 4, + 99, 62, 65, 62, 4, 21, 22, 25, 88, 63, + 63, 77, 77, 77, 89, 50, 66, 89, 51, 69, + 66, 66, 77, 4, 66, 51, 71, 66, 95, 77, + 69, 69, 69, 77, 61, 4, 83, 66, 66, 77, + 77, 77, 77, 62, 65, 47, 89, 89, 95, 95, + 95, 65, 66, 95, 98, 95, 61, 61, 61, 69, + 77, 77, 25, 20, 62, 62, 77, 66, 95, 61, + 62, 62, 77, 77, 77, 65, 95, 77, 88, 65, + 62, 65, 77, 65 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = +static const yytype_int8 yyr1[] = { - 0, 69, 70, 70, 71, 71, 72, 72, 73, 73, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, - 75, 76, 76, 76, 77, 78, 78, 79, 79, 80, - 80, 80, 82, 81, 83, 81, 84, 84, 84, 85, - 85, 86, 86, 86, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 88, 88, 89, 90, 90, - 91, 91, 92, 92, 92, 93, 93, 94, 94, 95, - 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 97, 97, 97, 97, 98, - 98, 98, 98, 98, 98, 98, 98, 98, 98, 98 + 0, 72, 73, 73, 74, 74, 75, 75, 76, 76, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 78, 78, 79, 79, 79, 80, 81, + 81, 82, 82, 83, 83, 83, 83, 85, 84, 86, + 84, 87, 87, 87, 88, 88, 89, 89, 89, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 91, 91, 92, 93, 93, 94, 94, 95, 95, 95, + 96, 96, 97, 97, 98, 98, 98, 98, 98, 98, + 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 100, 100, 100, 100, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = +static const yytype_int8 yyr2[] = { 0, 2, 3, 3, 0, 3, 0, 2, 0, 2, - 2, 5, 9, 11, 9, 5, 5, 4, 4, 2, - 4, 5, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 1, 2, - 3, 5, 4, 2, 1, 5, 8, 1, 3, 2, - 2, 1, 0, 4, 0, 5, 0, 2, 4, 5, - 3, 3, 2, 1, 1, 1, 3, 2, 3, 2, - 4, 3, 2, 1, 3, 2, 2, 3, 5, 4, - 6, 5, 4, 3, 7, 6, 6, 6, 5, 5, - 1, 1, 1, 3, 3, 2, 3, 2, 2, 1, - 4, 3, 3, 4, 3, 1, 3, 1, 3, 1, - 3, 1, 2, 3, 3, 1, 3, 1, 3, 2, - 4, 3, 3, 3, 5, 3, 1, 1, 1, 1, + 2, 9, 5, 9, 11, 9, 5, 5, 4, 6, + 8, 4, 2, 4, 5, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 1, 2, 3, 5, 4, 2, 1, 5, + 8, 1, 3, 2, 2, 2, 1, 0, 4, 0, + 5, 0, 2, 4, 5, 3, 3, 2, 1, 1, + 1, 3, 2, 3, 2, 4, 3, 2, 1, 3, + 2, 2, 3, 5, 4, 6, 5, 4, 3, 7, + 6, 6, 6, 5, 5, 1, 1, 1, 3, 3, + 2, 3, 2, 2, 1, 4, 3, 3, 4, 3, + 1, 3, 1, 3, 1, 3, 1, 2, 3, 3, + 1, 3, 1, 3, 2, 4, 3, 3, 3, 5, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 3, 3, 3, - 3, 3, 1, 4, 2, 2, 1, 1, 5, 3 + 1, 0, 1, 3, 3, 3, 3, 3, 1, 4, + 2, 2, 1, 1, 5, 3 }; @@ -1599,7 +1712,9 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YY if (yytype < YYNTOKENS) YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -1625,7 +1740,7 @@ yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE `------------------------------------------------------------------*/ static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) @@ -1648,12 +1763,12 @@ do { \ `------------------------------------------------*/ static void -yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) { - unsigned long yylno = yyrline[yyrule]; + int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) @@ -1705,13 +1820,13 @@ int yydebug; # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) # else /* Return the length of YYSTR. */ -static YYSIZE_T +static YYPTRDIFF_T yystrlen (const char *yystr) { - YYSIZE_T yylen; + YYPTRDIFF_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; @@ -1747,12 +1862,12 @@ yystpcpy (char *yydest, const char *yysrc) backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ -static YYSIZE_T +static YYPTRDIFF_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { - YYSIZE_T yyn = 0; + YYPTRDIFF_T yyn = 0; char const *yyp = yystr; for (;;) @@ -1783,10 +1898,10 @@ yytnamerr (char *yyres, const char *yystr) do_not_strip_quotes: ; } - if (! yyres) + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else return yystrlen (yystr); - - return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres); } # endif @@ -1799,19 +1914,19 @@ yytnamerr (char *yyres, const char *yystr) *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + yy_state_t *yyssp, int yytoken) { - YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); - YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; - /* Arguments of yyformat. */ + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ + /* Actual size of YYARG. */ int yycount = 0; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then @@ -1839,6 +1954,8 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; + YYPTRDIFF_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + yysize = yysize0; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { @@ -1863,7 +1980,8 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } yyarg[yycount++] = yytname[yyx]; { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) yysize = yysize1; else @@ -1890,7 +2008,9 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + /* Don't count the "%s"s in the final size, but reserve room for + the terminator. */ + YYPTRDIFF_T yysize1 = yysize + (yystrlen (yyformat) - 2 * yycount) + 1; if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) yysize = yysize1; else @@ -1920,8 +2040,8 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } else { - yyp++; - yyformat++; + ++yyp; + ++yyformat; } } return 0; @@ -1949,189 +2069,189 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocatio switch (yytype) { case 4: /* IDENT */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1955 "src/parser.c" /* yacc.c:1257 */ +#line 36 "src/parser.y" + { jv_free(((*yyvaluep).literal)); } +#line 2075 "src/parser.c" break; case 5: /* FIELD */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1961 "src/parser.c" /* yacc.c:1257 */ +#line 36 "src/parser.y" + { jv_free(((*yyvaluep).literal)); } +#line 2081 "src/parser.c" break; case 6: /* LITERAL */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1967 "src/parser.c" /* yacc.c:1257 */ +#line 36 "src/parser.y" + { jv_free(((*yyvaluep).literal)); } +#line 2087 "src/parser.c" break; case 7: /* FORMAT */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1973 "src/parser.c" /* yacc.c:1257 */ +#line 36 "src/parser.y" + { jv_free(((*yyvaluep).literal)); } +#line 2093 "src/parser.c" break; - case 42: /* QQSTRING_TEXT */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1979 "src/parser.c" /* yacc.c:1257 */ + case 45: /* QQSTRING_TEXT */ +#line 36 "src/parser.y" + { jv_free(((*yyvaluep).literal)); } +#line 2099 "src/parser.c" break; - case 71: /* Module */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1985 "src/parser.c" /* yacc.c:1257 */ + case 74: /* Module */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2105 "src/parser.c" break; - case 72: /* Imports */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1991 "src/parser.c" /* yacc.c:1257 */ + case 75: /* Imports */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2111 "src/parser.c" break; - case 73: /* FuncDefs */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1997 "src/parser.c" /* yacc.c:1257 */ + case 76: /* FuncDefs */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2117 "src/parser.c" break; - case 74: /* Exp */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2003 "src/parser.c" /* yacc.c:1257 */ + case 77: /* Exp */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2123 "src/parser.c" break; - case 75: /* Import */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2009 "src/parser.c" /* yacc.c:1257 */ + case 78: /* Import */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2129 "src/parser.c" break; - case 76: /* ImportWhat */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2015 "src/parser.c" /* yacc.c:1257 */ + case 79: /* ImportWhat */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2135 "src/parser.c" break; - case 77: /* ImportFrom */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2021 "src/parser.c" /* yacc.c:1257 */ + case 80: /* ImportFrom */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2141 "src/parser.c" break; - case 78: /* FuncDef */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2027 "src/parser.c" /* yacc.c:1257 */ + case 81: /* FuncDef */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2147 "src/parser.c" break; - case 79: /* Params */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2033 "src/parser.c" /* yacc.c:1257 */ + case 82: /* Params */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2153 "src/parser.c" break; - case 80: /* Param */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2039 "src/parser.c" /* yacc.c:1257 */ + case 83: /* Param */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2159 "src/parser.c" break; - case 81: /* String */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2045 "src/parser.c" /* yacc.c:1257 */ + case 84: /* String */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2165 "src/parser.c" break; - case 84: /* QQString */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2051 "src/parser.c" /* yacc.c:1257 */ + case 87: /* QQString */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2171 "src/parser.c" break; - case 85: /* ElseBody */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2057 "src/parser.c" /* yacc.c:1257 */ + case 88: /* ElseBody */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2177 "src/parser.c" break; - case 86: /* ExpD */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2063 "src/parser.c" /* yacc.c:1257 */ + case 89: /* ExpD */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2183 "src/parser.c" break; - case 87: /* Term */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2069 "src/parser.c" /* yacc.c:1257 */ + case 90: /* Term */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2189 "src/parser.c" break; - case 88: /* Args */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2075 "src/parser.c" /* yacc.c:1257 */ + case 91: /* Args */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2195 "src/parser.c" break; - case 89: /* Arg */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2081 "src/parser.c" /* yacc.c:1257 */ + case 92: /* Arg */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2201 "src/parser.c" break; - case 90: /* RepPatterns */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2087 "src/parser.c" /* yacc.c:1257 */ + case 93: /* RepPatterns */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2207 "src/parser.c" break; - case 91: /* Patterns */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2093 "src/parser.c" /* yacc.c:1257 */ + case 94: /* Patterns */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2213 "src/parser.c" break; - case 92: /* Pattern */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2099 "src/parser.c" /* yacc.c:1257 */ + case 95: /* Pattern */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2219 "src/parser.c" break; - case 93: /* ArrayPats */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2105 "src/parser.c" /* yacc.c:1257 */ + case 96: /* ArrayPats */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2225 "src/parser.c" break; - case 94: /* ObjPats */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2111 "src/parser.c" /* yacc.c:1257 */ + case 97: /* ObjPats */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2231 "src/parser.c" break; - case 95: /* ObjPat */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2117 "src/parser.c" /* yacc.c:1257 */ + case 98: /* ObjPat */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2237 "src/parser.c" break; - case 96: /* Keyword */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 2123 "src/parser.c" /* yacc.c:1257 */ + case 99: /* Keyword */ +#line 36 "src/parser.y" + { jv_free(((*yyvaluep).literal)); } +#line 2243 "src/parser.c" break; - case 97: /* MkDict */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2129 "src/parser.c" /* yacc.c:1257 */ + case 100: /* MkDict */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2249 "src/parser.c" break; - case 98: /* MkDictPair */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2135 "src/parser.c" /* yacc.c:1257 */ + case 101: /* MkDictPair */ +#line 37 "src/parser.y" + { block_free(((*yyvaluep).blk)); } +#line 2255 "src/parser.c" break; default: @@ -2171,7 +2291,7 @@ YYLTYPE yylloc = yyloc_default; /* Number of syntax errors so far. */ int yynerrs; - int yystate; + yy_state_fast_t yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; @@ -2184,9 +2304,9 @@ YYLTYPE yylloc = yyloc_default; to reallocate them elsewhere. */ /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss; + yy_state_t *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; @@ -2201,7 +2321,7 @@ YYLTYPE yylloc = yyloc_default; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; - YYSIZE_T yystacksize; + YYPTRDIFF_T yystacksize; int yyn; int yyresult; @@ -2216,7 +2336,7 @@ YYLTYPE yylloc = yyloc_default; /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) @@ -2250,10 +2370,14 @@ YYLTYPE yylloc = yyloc_default; /*--------------------------------------------------------------------. -| yynewstate -- set current state (the top of the stack) to yystate. | +| yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: - *yyssp = (yytype_int16) yystate; + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE @@ -2261,15 +2385,15 @@ YYLTYPE yylloc = yyloc_default; #else { /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1); + YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ + yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the @@ -2277,9 +2401,9 @@ YYLTYPE yylloc = yyloc_default; conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yyls1, yysize * YYSIZEOF (*yylsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; @@ -2294,9 +2418,10 @@ YYLTYPE yylloc = yyloc_default; yystacksize = YYMAXDEPTH; { - yytype_int16 *yyss1 = yyss; + yy_state_t *yyss1 = yyss; union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); @@ -2312,16 +2437,16 @@ YYLTYPE yylloc = yyloc_default; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long) yystacksize)); + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) YYACCEPT; @@ -2381,15 +2506,14 @@ YYLTYPE yylloc = yyloc_default; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token. */ - yychar = YYEMPTY; - yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; + + /* Discard the shifted token. */ + yychar = YYEMPTY; goto yynewstate; @@ -2426,33 +2550,49 @@ YYLTYPE yylloc = yyloc_default; YY_REDUCE_PRINT (yyn); switch (yyn) { - case 2: -#line 306 "src/parser.y" /* yacc.c:1667 */ - { - *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), gen_op_simple(TOP), (yyvsp[0].blk)); + case 2: +#line 310 "src/parser.y" + { + + // it looks pretty when the boilerplate code calls to @main + // but it's counter-productive: the call introduces an unneded frame + + // block main = gen_function("@main", gen_noop(), $3); + // block call_main = block_bind_referenced( + // main, + // gen_location(@$, locations, gen_call("@main", gen_noop())), + // OP_IS_CALL_PSEUDO); + + block main_loop = BLOCK ( + gen_op_simple(START), + (yyvsp[0].blk), // call_main + gen_op_simple(TAIL_OUT) + ); + + *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), gen_marker(TOP), main_loop); } -#line 2435 "src/parser.c" /* yacc.c:1667 */ +#line 2575 "src/parser.c" break; case 3: -#line 309 "src/parser.y" /* yacc.c:1667 */ - { +#line 329 "src/parser.y" + { *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } -#line 2443 "src/parser.c" /* yacc.c:1667 */ +#line 2583 "src/parser.c" break; case 4: -#line 314 "src/parser.y" /* yacc.c:1667 */ - { +#line 334 "src/parser.y" + { (yyval.blk) = gen_noop(); } -#line 2451 "src/parser.c" /* yacc.c:1667 */ +#line 2591 "src/parser.c" break; case 5: -#line 317 "src/parser.y" /* yacc.c:1667 */ - { +#line 337 "src/parser.y" + { if (!block_is_const((yyvsp[-1].blk))) { FAIL((yyloc), "Module metadata must be constant"); (yyval.blk) = gen_noop(); @@ -2461,375 +2601,421 @@ YYLTYPE yylloc = yyloc_default; (yyval.blk) = gen_module((yyvsp[-1].blk)); } } -#line 2465 "src/parser.c" /* yacc.c:1667 */ +#line 2605 "src/parser.c" break; case 6: -#line 328 "src/parser.y" /* yacc.c:1667 */ - { +#line 348 "src/parser.y" + { (yyval.blk) = gen_noop(); } -#line 2473 "src/parser.c" /* yacc.c:1667 */ +#line 2613 "src/parser.c" break; case 7: -#line 331 "src/parser.y" /* yacc.c:1667 */ - { +#line 351 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-1].blk), (yyvsp[0].blk)); } -#line 2481 "src/parser.c" /* yacc.c:1667 */ +#line 2621 "src/parser.c" break; case 8: -#line 336 "src/parser.y" /* yacc.c:1667 */ - { +#line 356 "src/parser.y" + { (yyval.blk) = gen_noop(); } -#line 2489 "src/parser.c" /* yacc.c:1667 */ +#line 2629 "src/parser.c" break; case 9: -#line 339 "src/parser.y" /* yacc.c:1667 */ - { +#line 359 "src/parser.y" + { (yyval.blk) = block_join((yyvsp[-1].blk), (yyvsp[0].blk)); } -#line 2497 "src/parser.c" /* yacc.c:1667 */ +#line 2637 "src/parser.c" break; case 10: -#line 344 "src/parser.y" /* yacc.c:1667 */ - { +#line 364 "src/parser.y" + { (yyval.blk) = block_bind_referenced((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO); } -#line 2505 "src/parser.c" /* yacc.c:1667 */ +#line 2645 "src/parser.c" break; case 11: -#line 348 "src/parser.y" /* yacc.c:1667 */ - { - (yyval.blk) = gen_destructure((yyvsp[-4].blk), (yyvsp[-2].blk), (yyvsp[0].blk)); +#line 368 "src/parser.y" + { + /* coexp(body) */ + block coexp = gen_call("coexp", gen_lambda((yyvsp[-2].blk))); + /* as $IDENT | */ + block covar = gen_op_var_fresh(STOREV, jv_string_value((yyvsp[-4].literal))); + /* def IDENT: $IDENT | fhread; */ + block codef = gen_function(jv_string_value((yyvsp[-4].literal)), gen_noop(), BLOCK(gen_op_unbound(LOADV, jv_string_value((yyvsp[-4].literal))), gen_call("fhread", gen_noop()))); + + /* Now bind $6 so it sees the codef */ + block b = block_bind_referenced(codef, (yyvsp[0].blk), OP_IS_CALL_PSEUDO | OP_HAS_BINDING); + + /* Now bind that so it sees the variable $IDENT */ + b = block_bind_referenced(covar, b, OP_HAS_VARIABLE); + + /* Now do the rest of the binding for a $IDENT | Exp */ + covar = block_take_block(&b); + (yyval.blk) = gen_destructure(coexp, covar, b); + jv_free((yyvsp[-4].literal)); } -#line 2513 "src/parser.c" /* yacc.c:1667 */ +#line 2669 "src/parser.c" break; case 12: -#line 351 "src/parser.y" /* yacc.c:1667 */ - { - (yyval.blk) = gen_reduce((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); +#line 388 "src/parser.y" + { + (yyval.blk) = gen_destructure((yyvsp[-4].blk), (yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2521 "src/parser.c" /* yacc.c:1667 */ +#line 2677 "src/parser.c" break; case 13: -#line 355 "src/parser.y" /* yacc.c:1667 */ - { - (yyval.blk) = gen_foreach((yyvsp[-9].blk), (yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); +#line 391 "src/parser.y" + { + (yyval.blk) = gen_reduce((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); } -#line 2529 "src/parser.c" /* yacc.c:1667 */ +#line 2685 "src/parser.c" break; case 14: -#line 359 "src/parser.y" /* yacc.c:1667 */ - { - (yyval.blk) = gen_foreach((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); +#line 395 "src/parser.y" + { + (yyval.blk) = gen_foreach((yyvsp[-9].blk), (yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); } -#line 2537 "src/parser.c" /* yacc.c:1667 */ +#line 2693 "src/parser.c" break; case 15: -#line 363 "src/parser.y" /* yacc.c:1667 */ - { - (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); +#line 399 "src/parser.y" + { + (yyval.blk) = gen_foreach((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); } -#line 2545 "src/parser.c" /* yacc.c:1667 */ +#line 2701 "src/parser.c" break; case 16: -#line 366 "src/parser.y" /* yacc.c:1667 */ - { - (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); +#line 403 "src/parser.y" + { + (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } -#line 2553 "src/parser.c" /* yacc.c:1667 */ +#line 2709 "src/parser.c" break; case 17: -#line 369 "src/parser.y" /* yacc.c:1667 */ - { - FAIL((yyloc), "Possibly unterminated 'if' statement"); - (yyval.blk) = (yyvsp[-2].blk); +#line 406 "src/parser.y" + { + (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); } -#line 2562 "src/parser.c" /* yacc.c:1667 */ +#line 2717 "src/parser.c" break; case 18: -#line 374 "src/parser.y" /* yacc.c:1667 */ - { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, $4); - (yyval.blk) = gen_try((yyvsp[-2].blk), gen_try_handler((yyvsp[0].blk))); +#line 409 "src/parser.y" + { + FAIL((yyloc), "Possibly unterminated 'if' statement"); + (yyval.blk) = (yyvsp[-2].blk); } -#line 2571 "src/parser.c" /* yacc.c:1667 */ +#line 2726 "src/parser.c" break; case 19: -#line 378 "src/parser.y" /* yacc.c:1667 */ - { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, gen_op_simple(BACKTRACK)); - (yyval.blk) = gen_try((yyvsp[0].blk), gen_op_simple(BACKTRACK)); +#line 414 "src/parser.y" + { + (yyval.blk) = gen_try((yyvsp[-3].blk), (yyvsp[-1].blk)); } -#line 2580 "src/parser.c" /* yacc.c:1667 */ +#line 2734 "src/parser.c" break; case 20: -#line 382 "src/parser.y" /* yacc.c:1667 */ - { +#line 417 "src/parser.y" + { + (yyval.blk) = BLOCK(gen_call("_try_finally", BLOCK(gen_lambda((yyvsp[-5].blk)), gen_lambda((yyvsp[-3].blk)), gen_lambda((yyvsp[-1].blk))))); +} +#line 2742 "src/parser.c" + break; + + case 21: +#line 420 "src/parser.y" + { + (yyval.blk) = gen_try((yyvsp[-2].blk), (yyvsp[0].blk)); +} +#line 2750 "src/parser.c" + break; + + case 22: +#line 423 "src/parser.y" + { + (yyval.blk) = gen_try((yyvsp[0].blk), gen_op_simple(BACKTRACK)); +} +#line 2758 "src/parser.c" + break; + + case 23: +#line 426 "src/parser.y" + { FAIL((yyloc), "Possibly unterminated 'try' statement"); (yyval.blk) = (yyvsp[-2].blk); } -#line 2589 "src/parser.c" /* yacc.c:1667 */ +#line 2767 "src/parser.c" break; - case 21: -#line 387 "src/parser.y" /* yacc.c:1667 */ - { + case 24: +#line 431 "src/parser.y" + { jv v = jv_string_fmt("*label-%s", jv_string_value((yyvsp[-2].literal))); (yyval.blk) = gen_location((yyloc), locations, gen_label(jv_string_value(v), (yyvsp[0].blk))); jv_free((yyvsp[-2].literal)); jv_free(v); } -#line 2600 "src/parser.c" /* yacc.c:1667 */ +#line 2778 "src/parser.c" break; - case 22: -#line 394 "src/parser.y" /* yacc.c:1667 */ - { + case 25: +#line 438 "src/parser.y" + { (yyval.blk) = gen_try((yyvsp[-1].blk), gen_op_simple(BACKTRACK)); } -#line 2608 "src/parser.c" /* yacc.c:1667 */ +#line 2786 "src/parser.c" break; - case 23: -#line 398 "src/parser.y" /* yacc.c:1667 */ - { + case 26: +#line 442 "src/parser.y" + { (yyval.blk) = gen_call("_assign", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } -#line 2616 "src/parser.c" /* yacc.c:1667 */ +#line 2794 "src/parser.c" break; - case 24: -#line 402 "src/parser.y" /* yacc.c:1667 */ - { + case 27: +#line 446 "src/parser.y" + { (yyval.blk) = gen_or((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2624 "src/parser.c" /* yacc.c:1667 */ +#line 2802 "src/parser.c" break; - case 25: -#line 406 "src/parser.y" /* yacc.c:1667 */ - { + case 28: +#line 450 "src/parser.y" + { (yyval.blk) = gen_and((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2632 "src/parser.c" /* yacc.c:1667 */ +#line 2810 "src/parser.c" break; - case 26: -#line 410 "src/parser.y" /* yacc.c:1667 */ - { + case 29: +#line 454 "src/parser.y" + { (yyval.blk) = gen_definedor((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2640 "src/parser.c" /* yacc.c:1667 */ +#line 2818 "src/parser.c" break; - case 27: -#line 414 "src/parser.y" /* yacc.c:1667 */ - { + case 30: +#line 458 "src/parser.y" + { (yyval.blk) = gen_definedor_assign((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2648 "src/parser.c" /* yacc.c:1667 */ +#line 2826 "src/parser.c" break; - case 28: -#line 418 "src/parser.y" /* yacc.c:1667 */ - { + case 31: +#line 462 "src/parser.y" + { (yyval.blk) = gen_call("_modify", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } -#line 2656 "src/parser.c" /* yacc.c:1667 */ +#line 2834 "src/parser.c" break; - case 29: -#line 422 "src/parser.y" /* yacc.c:1667 */ - { + case 32: +#line 466 "src/parser.y" + { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2664 "src/parser.c" /* yacc.c:1667 */ +#line 2842 "src/parser.c" break; - case 30: -#line 426 "src/parser.y" /* yacc.c:1667 */ - { + case 33: +#line 470 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); +} +#line 2850 "src/parser.c" + break; + + case 34: +#line 474 "src/parser.y" + { (yyval.blk) = gen_both((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2672 "src/parser.c" /* yacc.c:1667 */ +#line 2858 "src/parser.c" break; - case 31: -#line 430 "src/parser.y" /* yacc.c:1667 */ - { + case 35: +#line 478 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } -#line 2680 "src/parser.c" /* yacc.c:1667 */ +#line 2866 "src/parser.c" break; - case 32: -#line 434 "src/parser.y" /* yacc.c:1667 */ - { + case 36: +#line 482 "src/parser.y" + { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } -#line 2688 "src/parser.c" /* yacc.c:1667 */ +#line 2874 "src/parser.c" break; - case 33: -#line 438 "src/parser.y" /* yacc.c:1667 */ - { + case 37: +#line 486 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); } -#line 2696 "src/parser.c" /* yacc.c:1667 */ +#line 2882 "src/parser.c" break; - case 34: -#line 442 "src/parser.y" /* yacc.c:1667 */ - { + case 38: +#line 490 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } -#line 2704 "src/parser.c" /* yacc.c:1667 */ +#line 2890 "src/parser.c" break; - case 35: -#line 446 "src/parser.y" /* yacc.c:1667 */ - { + case 39: +#line 494 "src/parser.y" + { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } -#line 2712 "src/parser.c" /* yacc.c:1667 */ +#line 2898 "src/parser.c" break; - case 36: -#line 450 "src/parser.y" /* yacc.c:1667 */ - { + case 40: +#line 498 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } -#line 2720 "src/parser.c" /* yacc.c:1667 */ +#line 2906 "src/parser.c" break; - case 37: -#line 454 "src/parser.y" /* yacc.c:1667 */ - { + case 41: +#line 502 "src/parser.y" + { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } -#line 2728 "src/parser.c" /* yacc.c:1667 */ +#line 2914 "src/parser.c" break; - case 38: -#line 458 "src/parser.y" /* yacc.c:1667 */ - { + case 42: +#line 506 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '/'); if (block_is_const_inf((yyval.blk))) FAIL((yyloc), "Division by zero?"); } -#line 2738 "src/parser.c" /* yacc.c:1667 */ +#line 2924 "src/parser.c" break; - case 39: -#line 464 "src/parser.y" /* yacc.c:1667 */ - { + case 43: +#line 512 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '%'); if (block_is_const_inf((yyval.blk))) FAIL((yyloc), "Remainder by zero?"); } -#line 2748 "src/parser.c" /* yacc.c:1667 */ +#line 2934 "src/parser.c" break; - case 40: -#line 470 "src/parser.y" /* yacc.c:1667 */ - { + case 44: +#line 518 "src/parser.y" + { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '/'); } -#line 2756 "src/parser.c" /* yacc.c:1667 */ +#line 2942 "src/parser.c" break; - case 41: -#line 474 "src/parser.y" /* yacc.c:1667 */ - { + case 45: +#line 522 "src/parser.y" + { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '%'); } -#line 2764 "src/parser.c" /* yacc.c:1667 */ +#line 2950 "src/parser.c" break; - case 42: -#line 478 "src/parser.y" /* yacc.c:1667 */ - { + case 46: +#line 526 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), EQ); } -#line 2772 "src/parser.c" /* yacc.c:1667 */ +#line 2958 "src/parser.c" break; - case 43: -#line 482 "src/parser.y" /* yacc.c:1667 */ - { + case 47: +#line 530 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), NEQ); } -#line 2780 "src/parser.c" /* yacc.c:1667 */ +#line 2966 "src/parser.c" break; - case 44: -#line 486 "src/parser.y" /* yacc.c:1667 */ - { + case 48: +#line 534 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '<'); } -#line 2788 "src/parser.c" /* yacc.c:1667 */ +#line 2974 "src/parser.c" break; - case 45: -#line 490 "src/parser.y" /* yacc.c:1667 */ - { + case 49: +#line 538 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '>'); } -#line 2796 "src/parser.c" /* yacc.c:1667 */ +#line 2982 "src/parser.c" break; - case 46: -#line 494 "src/parser.y" /* yacc.c:1667 */ - { + case 50: +#line 542 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), LESSEQ); } -#line 2804 "src/parser.c" /* yacc.c:1667 */ +#line 2990 "src/parser.c" break; - case 47: -#line 498 "src/parser.y" /* yacc.c:1667 */ - { + case 51: +#line 546 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), GREATEREQ); } -#line 2812 "src/parser.c" /* yacc.c:1667 */ +#line 2998 "src/parser.c" break; - case 48: -#line 502 "src/parser.y" /* yacc.c:1667 */ - { + case 52: +#line 550 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } -#line 2820 "src/parser.c" /* yacc.c:1667 */ +#line 3006 "src/parser.c" break; - case 49: -#line 507 "src/parser.y" /* yacc.c:1667 */ - { + case 53: +#line 555 "src/parser.y" + { (yyval.blk) = (yyvsp[-1].blk); } -#line 2828 "src/parser.c" /* yacc.c:1667 */ +#line 3014 "src/parser.c" break; - case 50: -#line 510 "src/parser.y" /* yacc.c:1667 */ - { + case 54: +#line 558 "src/parser.y" + { if (!block_is_const((yyvsp[-1].blk))) { FAIL((yyloc), "Module metadata must be constant"); (yyval.blk) = gen_noop(); @@ -2844,12 +3030,12 @@ YYLTYPE yylloc = yyloc_default; (yyval.blk) = gen_import_meta((yyvsp[-2].blk), (yyvsp[-1].blk)); } } -#line 2848 "src/parser.c" /* yacc.c:1667 */ +#line 3034 "src/parser.c" break; - case 51: -#line 527 "src/parser.y" /* yacc.c:1667 */ - { + case 55: +#line 575 "src/parser.y" + { jv v = block_const((yyvsp[-3].blk)); // XXX Make gen_import take only blocks and the int is_data so we // don't have to free so much stuff here @@ -2858,35 +3044,35 @@ YYLTYPE yylloc = yyloc_default; jv_free((yyvsp[0].literal)); jv_free(v); } -#line 2862 "src/parser.c" /* yacc.c:1667 */ +#line 3048 "src/parser.c" break; - case 52: -#line 536 "src/parser.y" /* yacc.c:1667 */ - { + case 56: +#line 584 "src/parser.y" + { jv v = block_const((yyvsp[-2].blk)); (yyval.blk) = gen_import(jv_string_value(v), jv_string_value((yyvsp[0].literal)), 0); block_free((yyvsp[-2].blk)); jv_free((yyvsp[0].literal)); jv_free(v); } -#line 2874 "src/parser.c" /* yacc.c:1667 */ +#line 3060 "src/parser.c" break; - case 53: -#line 543 "src/parser.y" /* yacc.c:1667 */ - { + case 57: +#line 591 "src/parser.y" + { jv v = block_const((yyvsp[0].blk)); (yyval.blk) = gen_import(jv_string_value(v), NULL, 0); block_free((yyvsp[0].blk)); jv_free(v); } -#line 2885 "src/parser.c" /* yacc.c:1667 */ +#line 3071 "src/parser.c" break; - case 54: -#line 551 "src/parser.y" /* yacc.c:1667 */ - { + case 58: +#line 599 "src/parser.y" + { if (!block_is_const((yyvsp[0].blk))) { FAIL((yyloc), "Import path must be constant"); (yyval.blk) = gen_const(jv_string("")); @@ -2895,183 +3081,192 @@ YYLTYPE yylloc = yyloc_default; (yyval.blk) = (yyvsp[0].blk); } } -#line 2899 "src/parser.c" /* yacc.c:1667 */ +#line 3085 "src/parser.c" break; - case 55: -#line 562 "src/parser.y" /* yacc.c:1667 */ - { + case 59: +#line 610 "src/parser.y" + { (yyval.blk) = gen_function(jv_string_value((yyvsp[-3].literal)), gen_noop(), (yyvsp[-1].blk)); jv_free((yyvsp[-3].literal)); } -#line 2908 "src/parser.c" /* yacc.c:1667 */ +#line 3094 "src/parser.c" break; - case 56: -#line 567 "src/parser.y" /* yacc.c:1667 */ - { + case 60: +#line 615 "src/parser.y" + { (yyval.blk) = gen_function(jv_string_value((yyvsp[-6].literal)), (yyvsp[-4].blk), (yyvsp[-1].blk)); jv_free((yyvsp[-6].literal)); } -#line 2917 "src/parser.c" /* yacc.c:1667 */ +#line 3103 "src/parser.c" break; - case 57: -#line 573 "src/parser.y" /* yacc.c:1667 */ - { + case 61: +#line 621 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } -#line 2925 "src/parser.c" /* yacc.c:1667 */ +#line 3111 "src/parser.c" break; - case 58: -#line 576 "src/parser.y" /* yacc.c:1667 */ - { + case 62: +#line 624 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2933 "src/parser.c" /* yacc.c:1667 */ +#line 3119 "src/parser.c" break; - case 59: -#line 581 "src/parser.y" /* yacc.c:1667 */ - { + case 63: +#line 629 "src/parser.y" + { (yyval.blk) = gen_param_regular(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 2942 "src/parser.c" /* yacc.c:1667 */ +#line 3128 "src/parser.c" break; - case 60: -#line 585 "src/parser.y" /* yacc.c:1667 */ - { + case 64: +#line 633 "src/parser.y" + { (yyval.blk) = gen_param_regular(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 2951 "src/parser.c" /* yacc.c:1667 */ +#line 3137 "src/parser.c" break; - case 61: -#line 589 "src/parser.y" /* yacc.c:1667 */ - { + case 65: +#line 637 "src/parser.y" + { + (yyval.blk) = gen_param_coexpr(jv_string_value((yyvsp[0].literal))); + jv_free((yyvsp[0].literal)); +} +#line 3146 "src/parser.c" + break; + + case 66: +#line 641 "src/parser.y" + { (yyval.blk) = gen_param(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 2960 "src/parser.c" /* yacc.c:1667 */ +#line 3155 "src/parser.c" break; - case 62: -#line 596 "src/parser.y" /* yacc.c:1667 */ - { (yyval.literal) = jv_string("text"); } -#line 2966 "src/parser.c" /* yacc.c:1667 */ + case 67: +#line 648 "src/parser.y" + { (yyval.literal) = jv_string("text"); } +#line 3161 "src/parser.c" break; - case 63: -#line 596 "src/parser.y" /* yacc.c:1667 */ - { + case 68: +#line 648 "src/parser.y" + { (yyval.blk) = (yyvsp[-1].blk); jv_free((yyvsp[-2].literal)); } -#line 2975 "src/parser.c" /* yacc.c:1667 */ +#line 3170 "src/parser.c" break; - case 64: -#line 600 "src/parser.y" /* yacc.c:1667 */ - { (yyval.literal) = (yyvsp[-1].literal); } -#line 2981 "src/parser.c" /* yacc.c:1667 */ + case 69: +#line 652 "src/parser.y" + { (yyval.literal) = (yyvsp[-1].literal); } +#line 3176 "src/parser.c" break; - case 65: -#line 600 "src/parser.y" /* yacc.c:1667 */ - { + case 70: +#line 652 "src/parser.y" + { (yyval.blk) = (yyvsp[-1].blk); jv_free((yyvsp[-2].literal)); } -#line 2990 "src/parser.c" /* yacc.c:1667 */ +#line 3185 "src/parser.c" break; - case 66: -#line 607 "src/parser.y" /* yacc.c:1667 */ - { + case 71: +#line 659 "src/parser.y" + { (yyval.blk) = gen_const(jv_string("")); } -#line 2998 "src/parser.c" /* yacc.c:1667 */ +#line 3193 "src/parser.c" break; - case 67: -#line 610 "src/parser.y" /* yacc.c:1667 */ - { + case 72: +#line 662 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-1].blk), gen_const((yyvsp[0].literal)), '+'); } -#line 3006 "src/parser.c" /* yacc.c:1667 */ +#line 3201 "src/parser.c" break; - case 68: -#line 613 "src/parser.y" /* yacc.c:1667 */ - { + case 73: +#line 665 "src/parser.y" + { (yyval.blk) = gen_binop((yyvsp[-3].blk), gen_format((yyvsp[-1].blk), jv_copy((yyvsp[-4].literal))), '+'); } -#line 3014 "src/parser.c" /* yacc.c:1667 */ +#line 3209 "src/parser.c" break; - case 69: -#line 619 "src/parser.y" /* yacc.c:1667 */ - { + case 74: +#line 671 "src/parser.y" + { (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } -#line 3022 "src/parser.c" /* yacc.c:1667 */ +#line 3217 "src/parser.c" break; - case 70: -#line 622 "src/parser.y" /* yacc.c:1667 */ - { + case 75: +#line 674 "src/parser.y" + { (yyval.blk) = (yyvsp[-1].blk); } -#line 3030 "src/parser.c" /* yacc.c:1667 */ +#line 3225 "src/parser.c" break; - case 71: -#line 627 "src/parser.y" /* yacc.c:1667 */ - { + case 76: +#line 679 "src/parser.y" + { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3038 "src/parser.c" /* yacc.c:1667 */ +#line 3233 "src/parser.c" break; - case 72: -#line 630 "src/parser.y" /* yacc.c:1667 */ - { + case 77: +#line 682 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); } -#line 3046 "src/parser.c" /* yacc.c:1667 */ +#line 3241 "src/parser.c" break; - case 73: -#line 633 "src/parser.y" /* yacc.c:1667 */ - { + case 78: +#line 685 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } -#line 3054 "src/parser.c" /* yacc.c:1667 */ +#line 3249 "src/parser.c" break; - case 74: -#line 639 "src/parser.y" /* yacc.c:1667 */ + case 79: +#line 691 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3062 "src/parser.c" /* yacc.c:1667 */ +#line 3257 "src/parser.c" break; - case 75: -#line 642 "src/parser.y" /* yacc.c:1667 */ + case 80: +#line 694 "src/parser.y" { (yyval.blk) = gen_call("recurse", gen_noop()); } -#line 3070 "src/parser.c" /* yacc.c:1667 */ +#line 3265 "src/parser.c" break; - case 76: -#line 645 "src/parser.y" /* yacc.c:1667 */ - { + case 81: +#line 697 "src/parser.y" + { jv v = jv_string_fmt("*label-%s", jv_string_value((yyvsp[0].literal))); // impossible symbol (yyval.blk) = gen_location((yyloc), locations, BLOCK(gen_op_unbound(LOADV, jv_string_value(v)), @@ -3079,269 +3274,269 @@ YYLTYPE yylloc = yyloc_default; jv_free(v); jv_free((yyvsp[0].literal)); } -#line 3083 "src/parser.c" /* yacc.c:1667 */ +#line 3278 "src/parser.c" break; - case 77: -#line 653 "src/parser.y" /* yacc.c:1667 */ - { + case 82: +#line 705 "src/parser.y" + { FAIL((yyloc), "break requires a label to break to"); (yyval.blk) = gen_noop(); } -#line 3092 "src/parser.c" /* yacc.c:1667 */ +#line 3287 "src/parser.c" break; - case 78: -#line 657 "src/parser.y" /* yacc.c:1667 */ - { + case 83: +#line 709 "src/parser.y" + { (yyval.blk) = gen_index_opt((yyvsp[-2].blk), gen_const((yyvsp[-1].literal))); } -#line 3100 "src/parser.c" /* yacc.c:1667 */ +#line 3295 "src/parser.c" break; - case 79: -#line 660 "src/parser.y" /* yacc.c:1667 */ - { + case 84: +#line 712 "src/parser.y" + { (yyval.blk) = gen_index_opt(gen_noop(), gen_const((yyvsp[-1].literal))); } -#line 3108 "src/parser.c" /* yacc.c:1667 */ +#line 3303 "src/parser.c" break; - case 80: -#line 663 "src/parser.y" /* yacc.c:1667 */ - { + case 85: +#line 715 "src/parser.y" + { (yyval.blk) = gen_index_opt((yyvsp[-3].blk), (yyvsp[-1].blk)); } -#line 3116 "src/parser.c" /* yacc.c:1667 */ +#line 3311 "src/parser.c" break; - case 81: -#line 666 "src/parser.y" /* yacc.c:1667 */ - { + case 86: +#line 718 "src/parser.y" + { (yyval.blk) = gen_index_opt(gen_noop(), (yyvsp[-1].blk)); } -#line 3124 "src/parser.c" /* yacc.c:1667 */ +#line 3319 "src/parser.c" break; - case 82: -#line 669 "src/parser.y" /* yacc.c:1667 */ - { + case 87: +#line 721 "src/parser.y" + { (yyval.blk) = gen_index((yyvsp[-1].blk), gen_const((yyvsp[0].literal))); } -#line 3132 "src/parser.c" /* yacc.c:1667 */ +#line 3327 "src/parser.c" break; - case 83: -#line 672 "src/parser.y" /* yacc.c:1667 */ - { + case 88: +#line 724 "src/parser.y" + { (yyval.blk) = gen_index(gen_noop(), gen_const((yyvsp[0].literal))); } -#line 3140 "src/parser.c" /* yacc.c:1667 */ +#line 3335 "src/parser.c" break; - case 84: -#line 675 "src/parser.y" /* yacc.c:1667 */ - { + case 89: +#line 727 "src/parser.y" + { (yyval.blk) = gen_index((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3148 "src/parser.c" /* yacc.c:1667 */ +#line 3343 "src/parser.c" break; - case 85: -#line 678 "src/parser.y" /* yacc.c:1667 */ - { + case 90: +#line 730 "src/parser.y" + { (yyval.blk) = gen_index(gen_noop(), (yyvsp[0].blk)); } -#line 3156 "src/parser.c" /* yacc.c:1667 */ +#line 3351 "src/parser.c" break; - case 86: -#line 681 "src/parser.y" /* yacc.c:1667 */ - { + case 91: +#line 733 "src/parser.y" + { FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } -#line 3165 "src/parser.c" /* yacc.c:1667 */ +#line 3360 "src/parser.c" break; - case 87: -#line 685 "src/parser.y" /* yacc.c:1667 */ - { + case 92: +#line 737 "src/parser.y" + { jv_free((yyvsp[-1].literal)); FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } -#line 3175 "src/parser.c" /* yacc.c:1667 */ +#line 3370 "src/parser.c" break; - case 88: -#line 691 "src/parser.y" /* yacc.c:1667 */ - { + case 93: +#line 743 "src/parser.y" + { (yyval.blk) = gen_index_opt((yyvsp[-4].blk), (yyvsp[-2].blk)); } -#line 3183 "src/parser.c" /* yacc.c:1667 */ +#line 3378 "src/parser.c" break; - case 89: -#line 694 "src/parser.y" /* yacc.c:1667 */ - { + case 94: +#line 746 "src/parser.y" + { (yyval.blk) = gen_index((yyvsp[-3].blk), (yyvsp[-1].blk)); } -#line 3191 "src/parser.c" /* yacc.c:1667 */ +#line 3386 "src/parser.c" break; - case 90: -#line 697 "src/parser.y" /* yacc.c:1667 */ - { + case 95: +#line 749 "src/parser.y" + { (yyval.blk) = gen_index_opt((yyvsp[-5].blk), (yyvsp[-2].blk)); } -#line 3199 "src/parser.c" /* yacc.c:1667 */ +#line 3394 "src/parser.c" break; - case 91: -#line 700 "src/parser.y" /* yacc.c:1667 */ - { + case 96: +#line 752 "src/parser.y" + { (yyval.blk) = gen_index((yyvsp[-4].blk), (yyvsp[-1].blk)); } -#line 3207 "src/parser.c" /* yacc.c:1667 */ +#line 3402 "src/parser.c" break; - case 92: -#line 703 "src/parser.y" /* yacc.c:1667 */ - { + case 97: +#line 755 "src/parser.y" + { (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH_OPT)); } -#line 3215 "src/parser.c" /* yacc.c:1667 */ +#line 3410 "src/parser.c" break; - case 93: -#line 706 "src/parser.y" /* yacc.c:1667 */ - { + case 98: +#line 758 "src/parser.y" + { (yyval.blk) = block_join((yyvsp[-2].blk), gen_op_simple(EACH)); } -#line 3223 "src/parser.c" /* yacc.c:1667 */ +#line 3418 "src/parser.c" break; - case 94: -#line 709 "src/parser.y" /* yacc.c:1667 */ - { + case 99: +#line 761 "src/parser.y" + { (yyval.blk) = gen_slice_index((yyvsp[-6].blk), (yyvsp[-4].blk), (yyvsp[-2].blk), INDEX_OPT); } -#line 3231 "src/parser.c" /* yacc.c:1667 */ +#line 3426 "src/parser.c" break; - case 95: -#line 712 "src/parser.y" /* yacc.c:1667 */ - { + case 100: +#line 764 "src/parser.y" + { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), gen_const(jv_null()), INDEX_OPT); } -#line 3239 "src/parser.c" /* yacc.c:1667 */ +#line 3434 "src/parser.c" break; - case 96: -#line 715 "src/parser.y" /* yacc.c:1667 */ - { + case 101: +#line 767 "src/parser.y" + { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), gen_const(jv_null()), (yyvsp[-2].blk), INDEX_OPT); } -#line 3247 "src/parser.c" /* yacc.c:1667 */ +#line 3442 "src/parser.c" break; - case 97: -#line 718 "src/parser.y" /* yacc.c:1667 */ - { + case 102: +#line 770 "src/parser.y" + { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), INDEX); } -#line 3255 "src/parser.c" /* yacc.c:1667 */ +#line 3450 "src/parser.c" break; - case 98: -#line 721 "src/parser.y" /* yacc.c:1667 */ - { + case 103: +#line 773 "src/parser.y" + { (yyval.blk) = gen_slice_index((yyvsp[-4].blk), (yyvsp[-2].blk), gen_const(jv_null()), INDEX); } -#line 3263 "src/parser.c" /* yacc.c:1667 */ +#line 3458 "src/parser.c" break; - case 99: -#line 724 "src/parser.y" /* yacc.c:1667 */ - { + case 104: +#line 776 "src/parser.y" + { (yyval.blk) = gen_slice_index((yyvsp[-4].blk), gen_const(jv_null()), (yyvsp[-1].blk), INDEX); } -#line 3271 "src/parser.c" /* yacc.c:1667 */ +#line 3466 "src/parser.c" break; - case 100: -#line 727 "src/parser.y" /* yacc.c:1667 */ - { + case 105: +#line 779 "src/parser.y" + { (yyval.blk) = gen_const((yyvsp[0].literal)); } -#line 3279 "src/parser.c" /* yacc.c:1667 */ +#line 3474 "src/parser.c" break; - case 101: -#line 730 "src/parser.y" /* yacc.c:1667 */ - { + case 106: +#line 782 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } -#line 3287 "src/parser.c" /* yacc.c:1667 */ +#line 3482 "src/parser.c" break; - case 102: -#line 733 "src/parser.y" /* yacc.c:1667 */ - { + case 107: +#line 785 "src/parser.y" + { (yyval.blk) = gen_format(gen_noop(), (yyvsp[0].literal)); } -#line 3295 "src/parser.c" /* yacc.c:1667 */ +#line 3490 "src/parser.c" break; - case 103: -#line 736 "src/parser.y" /* yacc.c:1667 */ - { + case 108: +#line 788 "src/parser.y" + { (yyval.blk) = (yyvsp[-1].blk); } -#line 3303 "src/parser.c" /* yacc.c:1667 */ +#line 3498 "src/parser.c" break; - case 104: -#line 739 "src/parser.y" /* yacc.c:1667 */ - { + case 109: +#line 791 "src/parser.y" + { (yyval.blk) = gen_collect((yyvsp[-1].blk)); } -#line 3311 "src/parser.c" /* yacc.c:1667 */ +#line 3506 "src/parser.c" break; - case 105: -#line 742 "src/parser.y" /* yacc.c:1667 */ - { + case 110: +#line 794 "src/parser.y" + { (yyval.blk) = gen_const(jv_array()); } -#line 3319 "src/parser.c" /* yacc.c:1667 */ +#line 3514 "src/parser.c" break; - case 106: -#line 745 "src/parser.y" /* yacc.c:1667 */ - { + case 111: +#line 797 "src/parser.y" + { block o = gen_const_object((yyvsp[-1].blk)); if (o.first != NULL) (yyval.blk) = o; else (yyval.blk) = BLOCK(gen_subexp(gen_const(jv_object())), (yyvsp[-1].blk), gen_op_simple(POP)); } -#line 3331 "src/parser.c" /* yacc.c:1667 */ +#line 3526 "src/parser.c" break; - case 107: -#line 752 "src/parser.y" /* yacc.c:1667 */ - { + case 112: +#line 804 "src/parser.y" + { (yyval.blk) = gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal)))); jv_free((yyvsp[0].literal)); } -#line 3340 "src/parser.c" /* yacc.c:1667 */ +#line 3535 "src/parser.c" break; - case 108: -#line 756 "src/parser.y" /* yacc.c:1667 */ - { + case 113: +#line 808 "src/parser.y" + { if (strcmp(jv_string_value((yyvsp[0].literal)), "__loc__") == 0) { (yyval.blk) = gen_const(JV_OBJECT(jv_string("file"), jv_copy(locations->fname), jv_string("line"), jv_number(locfile_get_line(locations, (yyloc).start) + 1))); @@ -3350,12 +3545,12 @@ YYLTYPE yylloc = yyloc_default; } jv_free((yyvsp[0].literal)); } -#line 3354 "src/parser.c" /* yacc.c:1667 */ +#line 3549 "src/parser.c" break; - case 109: -#line 765 "src/parser.y" /* yacc.c:1667 */ - { + case 114: +#line 817 "src/parser.y" + { const char *s = jv_string_value((yyvsp[0].literal)); if (strcmp(s, "false") == 0) (yyval.blk) = gen_const(jv_false()); @@ -3367,199 +3562,199 @@ YYLTYPE yylloc = yyloc_default; (yyval.blk) = gen_location((yyloc), locations, gen_call(s, gen_noop())); jv_free((yyvsp[0].literal)); } -#line 3371 "src/parser.c" /* yacc.c:1667 */ +#line 3566 "src/parser.c" break; - case 110: -#line 777 "src/parser.y" /* yacc.c:1667 */ - { + case 115: +#line 829 "src/parser.y" + { (yyval.blk) = gen_call(jv_string_value((yyvsp[-3].literal)), (yyvsp[-1].blk)); (yyval.blk) = gen_location((yylsp[-3]), locations, (yyval.blk)); jv_free((yyvsp[-3].literal)); } -#line 3381 "src/parser.c" /* yacc.c:1667 */ +#line 3576 "src/parser.c" break; - case 111: -#line 782 "src/parser.y" /* yacc.c:1667 */ - { (yyval.blk) = gen_noop(); } -#line 3387 "src/parser.c" /* yacc.c:1667 */ + case 116: +#line 834 "src/parser.y" + { (yyval.blk) = gen_noop(); } +#line 3582 "src/parser.c" break; - case 112: -#line 783 "src/parser.y" /* yacc.c:1667 */ - { (yyval.blk) = gen_noop(); } -#line 3393 "src/parser.c" /* yacc.c:1667 */ + case 117: +#line 835 "src/parser.y" + { (yyval.blk) = gen_noop(); } +#line 3588 "src/parser.c" break; - case 113: -#line 784 "src/parser.y" /* yacc.c:1667 */ - { (yyval.blk) = (yyvsp[-3].blk); } -#line 3399 "src/parser.c" /* yacc.c:1667 */ + case 118: +#line 836 "src/parser.y" + { (yyval.blk) = (yyvsp[-3].blk); } +#line 3594 "src/parser.c" break; - case 114: -#line 785 "src/parser.y" /* yacc.c:1667 */ - { (yyval.blk) = gen_noop(); } -#line 3405 "src/parser.c" /* yacc.c:1667 */ + case 119: +#line 837 "src/parser.y" + { (yyval.blk) = gen_noop(); } +#line 3600 "src/parser.c" break; - case 115: -#line 788 "src/parser.y" /* yacc.c:1667 */ + case 120: +#line 840 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3413 "src/parser.c" /* yacc.c:1667 */ +#line 3608 "src/parser.c" break; - case 116: -#line 791 "src/parser.y" /* yacc.c:1667 */ - { + case 121: +#line 843 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3421 "src/parser.c" /* yacc.c:1667 */ +#line 3616 "src/parser.c" break; - case 117: -#line 796 "src/parser.y" /* yacc.c:1667 */ + case 122: +#line 848 "src/parser.y" { (yyval.blk) = gen_lambda((yyvsp[0].blk)); } -#line 3429 "src/parser.c" /* yacc.c:1667 */ +#line 3624 "src/parser.c" break; - case 118: -#line 801 "src/parser.y" /* yacc.c:1667 */ - { + case 123: +#line 853 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-2].blk), gen_destructure_alt((yyvsp[0].blk))); } -#line 3437 "src/parser.c" /* yacc.c:1667 */ +#line 3632 "src/parser.c" break; - case 119: -#line 804 "src/parser.y" /* yacc.c:1667 */ - { + case 124: +#line 856 "src/parser.y" + { (yyval.blk) = gen_destructure_alt((yyvsp[0].blk)); } -#line 3445 "src/parser.c" /* yacc.c:1667 */ +#line 3640 "src/parser.c" break; - case 120: -#line 809 "src/parser.y" /* yacc.c:1667 */ - { + case 125: +#line 861 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3453 "src/parser.c" /* yacc.c:1667 */ +#line 3648 "src/parser.c" break; - case 121: -#line 812 "src/parser.y" /* yacc.c:1667 */ - { + case 126: +#line 864 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } -#line 3461 "src/parser.c" /* yacc.c:1667 */ +#line 3656 "src/parser.c" break; - case 122: -#line 817 "src/parser.y" /* yacc.c:1667 */ - { + case 127: +#line 869 "src/parser.y" + { (yyval.blk) = gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 3470 "src/parser.c" /* yacc.c:1667 */ +#line 3665 "src/parser.c" break; - case 123: -#line 821 "src/parser.y" /* yacc.c:1667 */ - { + case 128: +#line 873 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); } -#line 3478 "src/parser.c" /* yacc.c:1667 */ +#line 3673 "src/parser.c" break; - case 124: -#line 824 "src/parser.y" /* yacc.c:1667 */ - { + case 129: +#line 876 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); } -#line 3486 "src/parser.c" /* yacc.c:1667 */ +#line 3681 "src/parser.c" break; - case 125: -#line 829 "src/parser.y" /* yacc.c:1667 */ - { + case 130: +#line 881 "src/parser.y" + { (yyval.blk) = gen_array_matcher(gen_noop(), (yyvsp[0].blk)); } -#line 3494 "src/parser.c" /* yacc.c:1667 */ +#line 3689 "src/parser.c" break; - case 126: -#line 832 "src/parser.y" /* yacc.c:1667 */ - { + case 131: +#line 884 "src/parser.y" + { (yyval.blk) = gen_array_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3502 "src/parser.c" /* yacc.c:1667 */ +#line 3697 "src/parser.c" break; - case 127: -#line 837 "src/parser.y" /* yacc.c:1667 */ - { + case 132: +#line 889 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } -#line 3510 "src/parser.c" /* yacc.c:1667 */ +#line 3705 "src/parser.c" break; - case 128: -#line 840 "src/parser.y" /* yacc.c:1667 */ - { + case 133: +#line 892 "src/parser.y" + { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3518 "src/parser.c" /* yacc.c:1667 */ +#line 3713 "src/parser.c" break; - case 129: -#line 845 "src/parser.y" /* yacc.c:1667 */ - { + case 134: +#line 897 "src/parser.y" + { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[0].literal)), gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal)))); } -#line 3526 "src/parser.c" /* yacc.c:1667 */ +#line 3721 "src/parser.c" break; - case 130: -#line 848 "src/parser.y" /* yacc.c:1667 */ - { + case 135: +#line 900 "src/parser.y" + { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), BLOCK(gen_op_simple(DUP), gen_op_unbound(STOREV, jv_string_value((yyvsp[-2].literal))), (yyvsp[0].blk))); } -#line 3534 "src/parser.c" /* yacc.c:1667 */ +#line 3729 "src/parser.c" break; - case 131: -#line 851 "src/parser.y" /* yacc.c:1667 */ - { + case 136: +#line 903 "src/parser.y" + { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 3542 "src/parser.c" /* yacc.c:1667 */ +#line 3737 "src/parser.c" break; - case 132: -#line 854 "src/parser.y" /* yacc.c:1667 */ - { + case 137: +#line 906 "src/parser.y" + { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 3550 "src/parser.c" /* yacc.c:1667 */ +#line 3745 "src/parser.c" break; - case 133: -#line 857 "src/parser.y" /* yacc.c:1667 */ - { + case 138: +#line 909 "src/parser.y" + { (yyval.blk) = gen_object_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3558 "src/parser.c" /* yacc.c:1667 */ +#line 3753 "src/parser.c" break; - case 134: -#line 860 "src/parser.y" /* yacc.c:1667 */ - { + case 139: +#line 912 "src/parser.y" + { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { FAIL((yyloc), jv_string_value(msg)); @@ -3567,277 +3762,285 @@ YYLTYPE yylloc = yyloc_default; jv_free(msg); (yyval.blk) = gen_object_matcher((yyvsp[-3].blk), (yyvsp[0].blk)); } -#line 3571 "src/parser.c" /* yacc.c:1667 */ +#line 3766 "src/parser.c" break; - case 135: -#line 868 "src/parser.y" /* yacc.c:1667 */ - { + case 140: +#line 920 "src/parser.y" + { FAIL((yyloc), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } -#line 3580 "src/parser.c" /* yacc.c:1667 */ +#line 3775 "src/parser.c" break; - case 136: -#line 874 "src/parser.y" /* yacc.c:1667 */ - { + case 141: +#line 926 "src/parser.y" + { (yyval.literal) = jv_string("as"); } -#line 3588 "src/parser.c" /* yacc.c:1667 */ +#line 3783 "src/parser.c" break; - case 137: -#line 877 "src/parser.y" /* yacc.c:1667 */ - { + case 142: +#line 929 "src/parser.y" + { (yyval.literal) = jv_string("def"); } -#line 3596 "src/parser.c" /* yacc.c:1667 */ +#line 3791 "src/parser.c" break; - case 138: -#line 880 "src/parser.y" /* yacc.c:1667 */ - { + case 143: +#line 932 "src/parser.y" + { + (yyval.literal) = jv_string("codef"); +} +#line 3799 "src/parser.c" + break; + + case 144: +#line 935 "src/parser.y" + { (yyval.literal) = jv_string("module"); } -#line 3604 "src/parser.c" /* yacc.c:1667 */ +#line 3807 "src/parser.c" break; - case 139: -#line 883 "src/parser.y" /* yacc.c:1667 */ - { + case 145: +#line 938 "src/parser.y" + { (yyval.literal) = jv_string("import"); } -#line 3612 "src/parser.c" /* yacc.c:1667 */ +#line 3815 "src/parser.c" break; - case 140: -#line 886 "src/parser.y" /* yacc.c:1667 */ - { + case 146: +#line 941 "src/parser.y" + { (yyval.literal) = jv_string("include"); } -#line 3620 "src/parser.c" /* yacc.c:1667 */ +#line 3823 "src/parser.c" break; - case 141: -#line 889 "src/parser.y" /* yacc.c:1667 */ - { + case 147: +#line 944 "src/parser.y" + { (yyval.literal) = jv_string("if"); } -#line 3628 "src/parser.c" /* yacc.c:1667 */ +#line 3831 "src/parser.c" break; - case 142: -#line 892 "src/parser.y" /* yacc.c:1667 */ - { + case 148: +#line 947 "src/parser.y" + { (yyval.literal) = jv_string("then"); } -#line 3636 "src/parser.c" /* yacc.c:1667 */ +#line 3839 "src/parser.c" break; - case 143: -#line 895 "src/parser.y" /* yacc.c:1667 */ - { + case 149: +#line 950 "src/parser.y" + { (yyval.literal) = jv_string("else"); } -#line 3644 "src/parser.c" /* yacc.c:1667 */ +#line 3847 "src/parser.c" break; - case 144: -#line 898 "src/parser.y" /* yacc.c:1667 */ - { + case 150: +#line 953 "src/parser.y" + { (yyval.literal) = jv_string("elif"); } -#line 3652 "src/parser.c" /* yacc.c:1667 */ +#line 3855 "src/parser.c" break; - case 145: -#line 901 "src/parser.y" /* yacc.c:1667 */ - { + case 151: +#line 956 "src/parser.y" + { (yyval.literal) = jv_string("reduce"); } -#line 3660 "src/parser.c" /* yacc.c:1667 */ +#line 3863 "src/parser.c" break; - case 146: -#line 904 "src/parser.y" /* yacc.c:1667 */ - { + case 152: +#line 959 "src/parser.y" + { (yyval.literal) = jv_string("foreach"); } -#line 3668 "src/parser.c" /* yacc.c:1667 */ +#line 3871 "src/parser.c" break; - case 147: -#line 907 "src/parser.y" /* yacc.c:1667 */ - { + case 153: +#line 962 "src/parser.y" + { (yyval.literal) = jv_string("end"); } -#line 3676 "src/parser.c" /* yacc.c:1667 */ +#line 3879 "src/parser.c" break; - case 148: -#line 910 "src/parser.y" /* yacc.c:1667 */ - { + case 154: +#line 965 "src/parser.y" + { (yyval.literal) = jv_string("and"); } -#line 3684 "src/parser.c" /* yacc.c:1667 */ +#line 3887 "src/parser.c" break; - case 149: -#line 913 "src/parser.y" /* yacc.c:1667 */ - { + case 155: +#line 968 "src/parser.y" + { (yyval.literal) = jv_string("or"); } -#line 3692 "src/parser.c" /* yacc.c:1667 */ +#line 3895 "src/parser.c" break; - case 150: -#line 916 "src/parser.y" /* yacc.c:1667 */ - { + case 156: +#line 971 "src/parser.y" + { (yyval.literal) = jv_string("try"); } -#line 3700 "src/parser.c" /* yacc.c:1667 */ +#line 3903 "src/parser.c" break; - case 151: -#line 919 "src/parser.y" /* yacc.c:1667 */ - { + case 157: +#line 974 "src/parser.y" + { (yyval.literal) = jv_string("catch"); } -#line 3708 "src/parser.c" /* yacc.c:1667 */ +#line 3911 "src/parser.c" break; - case 152: -#line 922 "src/parser.y" /* yacc.c:1667 */ - { + case 158: +#line 977 "src/parser.y" + { (yyval.literal) = jv_string("label"); } -#line 3716 "src/parser.c" /* yacc.c:1667 */ +#line 3919 "src/parser.c" break; - case 153: -#line 925 "src/parser.y" /* yacc.c:1667 */ - { + case 159: +#line 980 "src/parser.y" + { (yyval.literal) = jv_string("break"); } -#line 3724 "src/parser.c" /* yacc.c:1667 */ +#line 3927 "src/parser.c" break; - case 154: -#line 928 "src/parser.y" /* yacc.c:1667 */ - { + case 160: +#line 983 "src/parser.y" + { (yyval.literal) = jv_string("__loc__"); } -#line 3732 "src/parser.c" /* yacc.c:1667 */ +#line 3935 "src/parser.c" break; - case 155: -#line 933 "src/parser.y" /* yacc.c:1667 */ - { + case 161: +#line 988 "src/parser.y" + { (yyval.blk)=gen_noop(); } -#line 3740 "src/parser.c" /* yacc.c:1667 */ +#line 3943 "src/parser.c" break; - case 156: -#line 936 "src/parser.y" /* yacc.c:1667 */ - { (yyval.blk) = (yyvsp[0].blk); } -#line 3746 "src/parser.c" /* yacc.c:1667 */ + case 162: +#line 991 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } +#line 3949 "src/parser.c" break; - case 157: -#line 937 "src/parser.y" /* yacc.c:1667 */ - { (yyval.blk)=block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3752 "src/parser.c" /* yacc.c:1667 */ + case 163: +#line 992 "src/parser.y" + { (yyval.blk)=block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } +#line 3955 "src/parser.c" break; - case 158: -#line 938 "src/parser.y" /* yacc.c:1667 */ - { (yyval.blk) = (yyvsp[0].blk); } -#line 3758 "src/parser.c" /* yacc.c:1667 */ + case 164: +#line 993 "src/parser.y" + { (yyval.blk) = (yyvsp[0].blk); } +#line 3961 "src/parser.c" break; - case 159: -#line 941 "src/parser.y" /* yacc.c:1667 */ - { + case 165: +#line 996 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 3766 "src/parser.c" /* yacc.c:1667 */ +#line 3969 "src/parser.c" break; - case 160: -#line 944 "src/parser.y" /* yacc.c:1667 */ - { + case 166: +#line 999 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 3774 "src/parser.c" /* yacc.c:1667 */ +#line 3977 "src/parser.c" break; - case 161: -#line 947 "src/parser.y" /* yacc.c:1667 */ - { + case 167: +#line 1002 "src/parser.y" + { (yyval.blk) = gen_dictpair((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3782 "src/parser.c" /* yacc.c:1667 */ +#line 3985 "src/parser.c" break; - case 162: -#line 950 "src/parser.y" /* yacc.c:1667 */ - { + case 168: +#line 1005 "src/parser.y" + { (yyval.blk) = gen_dictpair((yyvsp[0].blk), BLOCK(gen_op_simple(POP), gen_op_simple(DUP2), gen_op_simple(DUP2), gen_op_simple(INDEX))); } -#line 3791 "src/parser.c" /* yacc.c:1667 */ +#line 3994 "src/parser.c" break; - case 163: -#line 954 "src/parser.y" /* yacc.c:1667 */ - { + case 169: +#line 1009 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[-2].literal)))), (yyvsp[0].blk)); } -#line 3800 "src/parser.c" /* yacc.c:1667 */ +#line 4003 "src/parser.c" break; - case 164: -#line 958 "src/parser.y" /* yacc.c:1667 */ - { + case 170: +#line 1013 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_const((yyvsp[0].literal)), gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal))))); } -#line 3809 "src/parser.c" /* yacc.c:1667 */ +#line 4012 "src/parser.c" break; - case 165: -#line 962 "src/parser.y" /* yacc.c:1667 */ - { + case 171: +#line 1017 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_const((yyvsp[0].literal)), gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal))))); } -#line 3818 "src/parser.c" /* yacc.c:1667 */ +#line 4021 "src/parser.c" break; - case 166: -#line 966 "src/parser.y" /* yacc.c:1667 */ - { + case 172: +#line 1021 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } -#line 3827 "src/parser.c" /* yacc.c:1667 */ +#line 4030 "src/parser.c" break; - case 167: -#line 970 "src/parser.y" /* yacc.c:1667 */ - { + case 173: +#line 1025 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } -#line 3836 "src/parser.c" /* yacc.c:1667 */ +#line 4039 "src/parser.c" break; - case 168: -#line 974 "src/parser.y" /* yacc.c:1667 */ - { + case 174: +#line 1029 "src/parser.y" + { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { FAIL((yyloc), jv_string_value(msg)); @@ -3845,20 +4048,21 @@ YYLTYPE yylloc = yyloc_default; jv_free(msg); (yyval.blk) = gen_dictpair((yyvsp[-3].blk), (yyvsp[0].blk)); } -#line 3849 "src/parser.c" /* yacc.c:1667 */ +#line 4052 "src/parser.c" break; - case 169: -#line 982 "src/parser.y" /* yacc.c:1667 */ - { + case 175: +#line 1037 "src/parser.y" + { FAIL((yyloc), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } -#line 3858 "src/parser.c" /* yacc.c:1667 */ +#line 4061 "src/parser.c" break; -#line 3862 "src/parser.c" /* yacc.c:1667 */ +#line 4065 "src/parser.c" + default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -3922,7 +4126,7 @@ YYLTYPE yylloc = yyloc_default; { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + yymsg = YY_CAST (char *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); if (!yymsg) { yymsg = yymsgbuf; @@ -4095,7 +4299,7 @@ YYLTYPE yylloc = yyloc_default; #endif return yyresult; } -#line 986 "src/parser.y" /* yacc.c:1918 */ +#line 1041 "src/parser.y" int jq_parse(struct locfile* locations, block* answer) { diff --git a/src/parser.h b/src/parser.h index 4d14e954f9..6a5bffba28 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.5. */ /* Bison interface for Yacc-like parsers in C @@ -44,7 +44,7 @@ extern int yydebug; #endif /* "%code requires" blocks. */ -#line 11 "src/parser.y" /* yacc.c:1927 */ +#line 11 "src/parser.y" #include "locfile.h" struct lexer_param; @@ -61,7 +61,7 @@ struct lexer_param; } \ } while (0) -#line 65 "src/parser.h" /* yacc.c:1927 */ +#line 65 "src/parser.h" /* Token type. */ #ifndef YYTOKENTYPE @@ -80,39 +80,42 @@ struct lexer_param; DEFINEDOR = 267, AS = 268, DEF = 269, - MODULE = 270, - IMPORT = 271, - INCLUDE = 272, - IF = 273, - THEN = 274, - ELSE = 275, - ELSE_IF = 276, - REDUCE = 277, - FOREACH = 278, - END = 279, - AND = 280, - OR = 281, - TRY = 282, - CATCH = 283, - LABEL = 284, - BREAK = 285, - LOC = 286, - SETPIPE = 287, - SETPLUS = 288, - SETMINUS = 289, - SETMULT = 290, - SETDIV = 291, - SETDEFINEDOR = 292, - LESSEQ = 293, - GREATEREQ = 294, - ALTERNATION = 295, - QQSTRING_START = 296, - QQSTRING_TEXT = 297, - QQSTRING_INTERP_START = 298, - QQSTRING_INTERP_END = 299, - QQSTRING_END = 300, - FUNCDEF = 301, - NONOPT = 302 + CODEF = 270, + MODULE = 271, + IMPORT = 272, + INCLUDE = 273, + IF = 274, + THEN = 275, + ELSE = 276, + ELSE_IF = 277, + REDUCE = 278, + FOREACH = 279, + END = 280, + AND = 281, + OR = 282, + TRY = 283, + CATCH = 284, + LABEL = 285, + BREAK = 286, + LOC = 287, + HIGHPRECPIPE = 288, + SETPIPE = 289, + SETPLUS = 290, + SETMINUS = 291, + SETMULT = 292, + SETDIV = 293, + SETDEFINEDOR = 294, + LESSEQ = 295, + GREATEREQ = 296, + ALTERNATION = 297, + COEXPR = 298, + QQSTRING_START = 299, + QQSTRING_TEXT = 300, + QQSTRING_INTERP_START = 301, + QQSTRING_INTERP_END = 302, + QQSTRING_END = 303, + FUNCDEF = 304, + NONOPT = 305 }; #endif /* Tokens. */ @@ -128,53 +131,55 @@ struct lexer_param; #define DEFINEDOR 267 #define AS 268 #define DEF 269 -#define MODULE 270 -#define IMPORT 271 -#define INCLUDE 272 -#define IF 273 -#define THEN 274 -#define ELSE 275 -#define ELSE_IF 276 -#define REDUCE 277 -#define FOREACH 278 -#define END 279 -#define AND 280 -#define OR 281 -#define TRY 282 -#define CATCH 283 -#define LABEL 284 -#define BREAK 285 -#define LOC 286 -#define SETPIPE 287 -#define SETPLUS 288 -#define SETMINUS 289 -#define SETMULT 290 -#define SETDIV 291 -#define SETDEFINEDOR 292 -#define LESSEQ 293 -#define GREATEREQ 294 -#define ALTERNATION 295 -#define QQSTRING_START 296 -#define QQSTRING_TEXT 297 -#define QQSTRING_INTERP_START 298 -#define QQSTRING_INTERP_END 299 -#define QQSTRING_END 300 -#define FUNCDEF 301 -#define NONOPT 302 +#define CODEF 270 +#define MODULE 271 +#define IMPORT 272 +#define INCLUDE 273 +#define IF 274 +#define THEN 275 +#define ELSE 276 +#define ELSE_IF 277 +#define REDUCE 278 +#define FOREACH 279 +#define END 280 +#define AND 281 +#define OR 282 +#define TRY 283 +#define CATCH 284 +#define LABEL 285 +#define BREAK 286 +#define LOC 287 +#define HIGHPRECPIPE 288 +#define SETPIPE 289 +#define SETPLUS 290 +#define SETMINUS 291 +#define SETMULT 292 +#define SETDIV 293 +#define SETDEFINEDOR 294 +#define LESSEQ 295 +#define GREATEREQ 296 +#define ALTERNATION 297 +#define COEXPR 298 +#define QQSTRING_START 299 +#define QQSTRING_TEXT 300 +#define QQSTRING_INTERP_START 301 +#define QQSTRING_INTERP_END 302 +#define QQSTRING_END 303 +#define FUNCDEF 304 +#define NONOPT 305 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - union YYSTYPE { -#line 31 "src/parser.y" /* yacc.c:1927 */ +#line 31 "src/parser.y" jv literal; block blk; -#line 176 "src/parser.h" /* yacc.c:1927 */ -}; +#line 181 "src/parser.h" +}; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 diff --git a/src/parser.y b/src/parser.y index e223adab53..ec49e4f64d 100644 --- a/src/parser.y +++ b/src/parser.y @@ -58,6 +58,7 @@ struct lexer_param; %token DEFINEDOR "//" %token AS "as" %token DEF "def" +%token CODEF "codef" %token MODULE "module" %token IMPORT "import" %token INCLUDE "include" @@ -75,6 +76,7 @@ struct lexer_param; %token LABEL "label" %token BREAK "break" %token LOC "__loc__" +%token HIGHPRECPIPE ">|" %token SETPIPE "|=" %token SETPLUS "+=" %token SETMINUS "-=" @@ -84,6 +86,7 @@ struct lexer_param; %token LESSEQ "<=" %token GREATEREQ ">=" %token ALTERNATION "?//" +%token COEXPR "@@" %token QQSTRING_START %token QQSTRING_TEXT @@ -110,6 +113,7 @@ struct lexer_param; %precedence '?' %precedence "try" %precedence "catch" +%right HIGHPRECPIPE %type Exp Term @@ -303,8 +307,24 @@ static block gen_update(block object, block val, int optype) { %% TopLevel: -Module Imports Exp { - *answer = BLOCK($1, $2, gen_op_simple(TOP), $3); +Module Imports Exp { + + // it looks pretty when the boilerplate code calls to @main + // but it's counter-productive: the call introduces an unneded frame + + // block main = gen_function("@main", gen_noop(), $3); + // block call_main = block_bind_referenced( + // main, + // gen_location(@$, locations, gen_call("@main", gen_noop())), + // OP_IS_CALL_PSEUDO); + + block main_loop = BLOCK ( + gen_op_simple(START), + $3, // call_main + gen_op_simple(TAIL_OUT) + ); + + *answer = BLOCK($1, $2, gen_marker(TOP), main_loop); } | Module Imports FuncDefs { *answer = BLOCK($1, $2, $3); @@ -345,6 +365,26 @@ FuncDef Exp %prec FUNCDEF { $$ = block_bind_referenced($1, $2, OP_IS_CALL_PSEUDO); } | +"codef" '(' '$' ')' IDENT ':' Exp ';' %prec FUNCDEF Exp { + /* coexp(body) */ + block coexp = gen_call("coexp", gen_lambda($7)); + /* as $IDENT | */ + block covar = gen_op_var_fresh(STOREV, jv_string_value($5)); + /* def IDENT: $IDENT | fhread; */ + block codef = gen_function(jv_string_value($5), gen_noop(), BLOCK(gen_op_unbound(LOADV, jv_string_value($5)), gen_call("fhread", gen_noop()))); + + /* Now bind $6 so it sees the codef */ + block b = block_bind_referenced(codef, $9, OP_IS_CALL_PSEUDO | OP_HAS_BINDING); + + /* Now bind that so it sees the variable $IDENT */ + b = block_bind_referenced(covar, b, OP_HAS_VARIABLE); + + /* Now do the rest of the binding for a $IDENT | Exp */ + covar = block_take_block(&b); + $$ = gen_destructure(coexp, covar, b); + jv_free($5); +} | + Term "as" Patterns '|' Exp { $$ = gen_destructure($1, $3, $5); } | @@ -371,12 +411,16 @@ Term "as" Patterns '|' Exp { $$ = $2; } | +"try" '(' Exp ';' Exp ')' { + $$ = gen_try($3, $5); +} | +"try" '(' Exp ';' Exp ';' Exp ')' { + $$ = BLOCK(gen_call("_try_finally", BLOCK(gen_lambda($3), gen_lambda($5), gen_lambda($7)))); +} | "try" Exp "catch" Exp { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, $4); - $$ = gen_try($2, gen_try_handler($4)); + $$ = gen_try($2, $4); } | "try" Exp { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, gen_op_simple(BACKTRACK)); $$ = gen_try($2, gen_op_simple(BACKTRACK)); } | "try" Exp "catch" error { @@ -423,6 +467,10 @@ Exp '|' Exp { $$ = block_join($1, $3); } | +Exp ">|" Exp { + $$ = block_join($1, $3); +} | + Exp ',' Exp { $$ = gen_both($1, $3); } | @@ -586,6 +634,10 @@ Param: $$ = gen_param_regular(jv_string_value($2)); jv_free($2); } | +"@@" IDENT { + $$ = gen_param_coexpr(jv_string_value($2)); + jv_free($2); +} | IDENT { $$ = gen_param(jv_string_value($1)); jv_free($1); @@ -877,6 +929,9 @@ Keyword: "def" { $$ = jv_string("def"); } | +"codef" { + $$ = jv_string("codef"); +} | "module" { $$ = jv_string("module"); } | diff --git a/src/util.c b/src/util.c index 1f2aac114b..1ac397867d 100644 --- a/src/util.c +++ b/src/util.c @@ -38,6 +38,9 @@ void *alloca (size_t); #include #include #include +#else +#include +#include #endif @@ -456,3 +459,700 @@ jv jq_util_input_next_input(jq_util_input_state *state) { } return value; } + +#ifdef WIN32 +/* + * For CreateProcess() calls we need to encode an argv into a command-line. + * + * See https://stackoverflow.com/questions/31838469/! + */ +static int quote_arg(char **cmdline, size_t *cmdlinesz, const char *arg) { + size_t cmdlen = strlen(*cmdline); + size_t arglen = strlen(arg); + size_t nbackslashes = 0; + size_t newsz; + const char *p; + char *tmp; + + if (strpbrk(arg, " \t\n\v\"") == NULL) { + /* No quoting needed */ + if (cmdlen + arglen + 2 >= *cmdlinesz) { + newsz = cmdlen + arglen + 128; + if ((tmp = realloc(*cmdline, newsz)) == NULL) + return ENOMEM; + memset(tmp + cmdlen, 0, newsz - cmdlen); + *cmdline = tmp; + *cmdlinesz = newsz; + } + + /* Add " ${arg}" */ + (*cmdline)[cmdlen] = ' '; + memcpy((*cmdline) + cmdlen + 1, arg, arglen); + return 0; + } + + /* Quoting needed */ + if (cmdlen + 3 * arglen + 2 >= *cmdlinesz) { + newsz = cmdlen + 3 * arglen + 128; + if ((tmp = realloc(*cmdline, newsz)) == NULL) + return ENOMEM; + memset(tmp + cmdlen, 0, newsz - cmdlen); + *cmdline = tmp; + *cmdlinesz = newsz; + } + + /* Add " \"" */ + (*cmdline)[cmdlen++] = ' '; + (*cmdline)[cmdlen++] = '"'; + + for (p = arg; *p; p++) { + for (p++; *p && *p == '\\'; p++) + nbackslashes++; + if (*p == '"') { + /* output 2 * nbackslashes */ + while (nbackslashes) { + (*cmdline)[cmdlen++] = '\\'; + (*cmdline)[cmdlen++] = '\\'; + } + /* output "\\\"" */ + (*cmdline)[cmdlen++] = '\\'; + (*cmdline)[cmdlen++] = '"'; + } else { + /* output nbackslashes */ + while (nbackslashes) + (*cmdline)[cmdlen++] = '\\'; + (*cmdline)[cmdlen++] = *p; + } + nbackslashes = 0; + } + + while (nbackslashes) { + /* arg ended in a sequence of backslashes */ + (*cmdline)[cmdlen++] = '\\'; + (*cmdline)[cmdlen++] = '\\'; + } + + (*cmdline)[cmdlen++] = '"'; + return 0; +} + +static char *encode_argv(char **argv) { + size_t cmdlinesz = 0; + size_t i; + char *cmdline = NULL; + + for (i = 0; argv[i]; i++) { + if (quote_arg(&cmdline, &cmdlinesz, argv[i])) { + free(cmdline); + return NULL; + } + } + return cmdline; +} + +jv jq_spawn_process(jq_state *jq, jv file, jv file_actions, jv attrs, jv argv, jv env) { + /* + * XXX Finish + * + * Similar to the non-WIN32 version... but see + * + * https://github.com/rprichard/win32-console-docs + * + * Basically: + * + * - encode the argv as one string + * - support only stdin/out/err redirections + * - open files or make pipes the usual way, except using _pipe() + * - get HANDLEs for FDs using _get_osfhandle() + * - setup STARTUPINFO struct with STARTF_USESTDHANDLES if we're redirecting I/O + * - call CreateProcess() + * - fdopen() our ends of pipes + * - ... + */ +} +#else + +struct pipes { + int pin[2]; + int pout[2]; + int perr[2]; +}; + +static int jv2oflags(int *oflagsp, int fd, jv oflags, jv *res) { + *oflagsp = 0; + + if (!jv_is_valid(oflags)) { + if (fd == STDIN_FILENO) + *oflagsp = O_RDONLY; + else + *oflagsp = O_WRONLY | O_CREAT; + return 0; + } + if (jv_get_kind(oflags) != JV_KIND_ARRAY) { + *res = jv_invalid_with_msg(jv_string("spawn file actions oflags must be array of O_* flag names")); + jv_free(oflags); + return EINVAL; + } + + jv_array_foreach(oflags, i, oflag) { + const char *s; + + if (jv_get_kind(oflag) != JV_KIND_STRING) { + *res = jv_invalid_with_msg(jv_string("spawn file actions oflags must be array of O_* flag names")); + jv_free(oflags); + jv_free(oflag); + return EINVAL; + } + s = jv_string_value(oflag); + if (strcmp(s, "O_RDONLY") == 0) + *oflagsp |= O_RDONLY; + else if (strcmp(s, "O_WRONLY") == 0) + *oflagsp |= O_WRONLY; + else if (strcmp(s, "O_RDWR") == 0) + *oflagsp |= O_RDWR; + else if (strcmp(s, "O_CREAT") == 0) + *oflagsp |= O_CREAT; + else if (strcmp(s, "O_EXCL") == 0) + *oflagsp |= O_EXCL; + else if (strcmp(s, "O_APPEND") == 0) + *oflagsp |= O_APPEND; + else if (strcmp(s, "O_TRUNC") == 0) + *oflagsp |= O_TRUNC; + else { + jv_free(oflags); + jv_free(oflag); + *res = jv_invalid_with_msg(jv_string("spawn file actions oflags: only O_RDONLY, " + "O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_APPEND, and " + "O_TRUNC supported")); + return EINVAL; + } + } + jv_free(oflags); + return 0; +} + +static int jv2mode(mode_t *modep, jv mode, jv *res) { + *modep = 0600; + if (!jv_is_valid(mode)) + return 0; + if (jv_get_kind(mode) != JV_KIND_NUMBER) { + *res = jv_invalid_with_msg(jv_string("spawn file actions mode must be a 16-bit unsigned number")); + jv_free(mode); + return EINVAL; + } + *modep = jv_number_value(mode); + if (jv_number_value(mode) != (double)*modep) { + *res = jv_invalid_with_msg(jv_string("spawn file actions mode must be a 16-bit unsigned number")); + jv_free(mode); + return EINVAL; + } + jv_free(mode); + return 0; +} + +/* + * This is an insane function :( + * + * The goal is to allow "file actions" of various types: + * + * - {f: "stdin/out/err"} --> setup a pipe for stdin/out/err + * - {f: 0/1/2} --> setup a pipe for stdin/out/err + * - {f: , target: -1} --> setup a close action + * - {f: , target: } --> setup a dup2 action + * - {f: ..., target: , + * oflags: [], mode: } --> setup an open action + * + * has to be an array of O_* flag names + * + * XXX We really want something like posix_spawn_file_actions_addclosefrom(), + * or something similar. Might need to have an exec helper, perhaps jq itself + * as an exec helper, to make it so. + */ +static int jv2pfac(jq_state *jq, jv fac, struct pipes *p, posix_spawn_file_actions_t *pfacs, jv *res) { + static int devnull = -1; + int fd = -1; + + if (devnull == -1 && (devnull = open("/dev/null", O_RDWR)) == -1) { + jv_free(fac); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not open /dev/null: %s", strerror(errno)))), + EINVAL; + } + if (jv_get_kind(fac) != JV_KIND_OBJECT) { + jv_free(fac); + return (*res = jv_invalid_with_msg(jv_string("spawn file action descriptors must be objects"))), + EINVAL; + } + + jv v = jv_object_get(jv_copy(fac), jv_string("f")); + if (!jv_is_valid(v)) { + jv_free(fac); + return (*res = jv_invalid_with_msg(jv_string("spawn file action descriptors must have f field"))), + EINVAL; + } + if (jv_get_kind(v) == JV_KIND_STRING) { + if (!(strcmp(jv_string_value(v), "stdin") == 0 && ((fd = STDIN_FILENO), 1)) && + !(strcmp(jv_string_value(v), "stdout") == 0 && (fd = STDOUT_FILENO)) && + !(strcmp(jv_string_value(v), "stderr") == 0 && (fd = STDERR_FILENO)) ) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string("spawn file action descriptors must have f field with stdin/stdout/stderr or fd number"))), + EINVAL; + } + } else if (jv_get_kind(v) == JV_KIND_NUMBER) { + fd = jv_number_value(v); + if (fd < 0) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string("spawn file action descriptors must have f field with stdin/stdout/stderr or fd number"))), + EINVAL; + } + } else { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string("spawn file action descriptors must have f field with stdin/stdout/stderr or fd number"))), + EINVAL; + } + jv_free(v); + + v = jv_object_get(jv_copy(fac), jv_string("target")); + if (jv_get_kind(v) == JV_KIND_NULL) { + /* null -> /dev/null */ + if ((errno = posix_spawn_file_actions_adddup2(pfacs, devnull, fd))) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not set up spawn /dev/null fd: %s (%d)", + strerror(errno), errno))), + errno; + } + } else if (jv_get_kind(v) == JV_KIND_NUMBER) { + int target = jv_number_value(v); + + if (target < 0) + errno = posix_spawn_file_actions_addclose(pfacs, fd); + else + errno = posix_spawn_file_actions_adddup2(pfacs, target, fd); + if (errno) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not set up spawn pipe actions: %s (%d)", + strerror(errno), errno))), + errno; + } + } else if (jv_get_kind(v) == JV_KIND_INVALID) { + int *pp = NULL; + /* No target -> pipe */ + if ((fd == STDIN_FILENO && (pp = p->pin) && p->pin[0] != -1) || + (fd == STDOUT_FILENO && (pp = p->pout) && p->pout[0] != -1) || + (fd == STDERR_FILENO && (pp = p->perr) && p->perr[0] != -1)) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string("duplicate spawn file action descriptors"))), + EINVAL; + } + if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string("only stdin/out/err can have pipes"))), + EINVAL; + } + if (pipe(pp) == -1) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not create pipe: %s (%d)", + strerror(errno), errno))), + errno; + } + if (fd == STDIN_FILENO) { + errno = posix_spawn_file_actions_adddup2(pfacs, p->pin[0], STDIN_FILENO); + if (errno == 0) + errno = posix_spawn_file_actions_addclose(pfacs, p->pin[0]); + if (errno == 0) + errno = posix_spawn_file_actions_addclose(pfacs, p->pin[1]); + if (errno) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not set up spawn pipe actions: %s (%d)", + strerror(errno), errno))), + errno; + } + } else if (fd == STDOUT_FILENO) { + errno = posix_spawn_file_actions_adddup2(pfacs, p->pout[1], STDOUT_FILENO); + if (errno == 0) + errno = posix_spawn_file_actions_addclose(pfacs, p->pout[0]); + if (errno == 0) + errno = posix_spawn_file_actions_addclose(pfacs, p->pout[1]); + if (errno) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not set up spawn pipe actions: %s (%d)", + strerror(errno), errno))), + errno; + } + } else if (fd == STDERR_FILENO) { + errno = posix_spawn_file_actions_adddup2(pfacs, p->perr[1], STDERR_FILENO); + if (errno == 0) + errno = posix_spawn_file_actions_addclose(pfacs, p->perr[0]); + if (errno == 0) + errno = posix_spawn_file_actions_addclose(pfacs, p->perr[1]); + if (errno) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not set up spawn pipe actions: %s (%d)", + strerror(errno), errno))), + errno; + } + } + } else if (jv_get_kind(v) == JV_KIND_STRING) { + mode_t mode; + int oflags; + + if (jv2oflags(&oflags, fd, jv_object_get(jv_copy(fac), jv_string("oflags")), res) || + jv2mode(&mode, jv_object_get(jv_copy(fac), jv_string("mode")), res)) { + jv_free(fac); + jv_free(v); + return EINVAL; + } + + *res = jq_io_policy_check(jq, JV_OBJECT(jv_string("kind"), jv_string("fileaction"), + jv_string("action"), jv_copy(fac))); + if (jv_get_kind(*res) != JV_KIND_TRUE) { + jv_free(fac); + jv_free(v); + return EACCES; + } + + if (fd == STDIN_FILENO) + oflags = O_RDONLY; + else if ((fd == STDOUT_FILENO || fd == STDERR_FILENO) && !(oflags & O_WRONLY)) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string("invalid oflags for stdout or stderr"))), + EINVAL; + } + + errno = posix_spawn_file_actions_addopen(pfacs, fd, jv_string_value(v), oflags, mode); + if (errno) { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string_fmt("could not set up spawn pipe actions: %s (%d)", + strerror(errno), errno))), + errno; + } + } else { + jv_free(fac); + jv_free(v); + return (*res = jv_invalid_with_msg(jv_string("spawn file action descriptors can only have target field with path string or fd number"))), + EINVAL; + } + + *res = jv_true(); + jv_free(fac); + jv_free(v); + return 0; +} + +static int jv2attrflags(short *flagsp, jv flags, jv *res) { + *flagsp = 0; + + if (jv_get_kind(flags) != JV_KIND_ARRAY) { + *res = jv_invalid_with_msg(jv_string("spawn attribute flags must be array of flag names")); + jv_free(flags); + return EINVAL; + } + jv_array_foreach(flags, i, flag) { + if (jv_get_kind(flag) != JV_KIND_STRING) { + *res = jv_invalid_with_msg(jv_string("spawn attribute flags must be array of flag names")); + jv_free(flags); + return EINVAL; + } + const char *s = jv_string_value(flag); + if (strcmp(s, "RESETIDS") == 0) *flagsp |= POSIX_SPAWN_RESETIDS; + else if (strcmp(s, "SETPGROUP") == 0) *flagsp |= POSIX_SPAWN_SETPGROUP; + else if (strcmp(s, "SETSIGDEF") == 0) *flagsp |= POSIX_SPAWN_SETSIGDEF; + else if (strcmp(s, "SETSIGMASK") == 0) *flagsp |= POSIX_SPAWN_SETSIGMASK; + else { + *res = jv_invalid_with_msg(jv_string_fmt("spawn attribute flag %s not supported", s)); + jv_free(flags); + jv_free(flag); + return EINVAL; + } + jv_free(flag); + } + jv_free(flags); + return 0; +} + +static int jv2sigset(sigset_t *ssp, jv ss, jv *res) { + (void) sigemptyset(ssp); + + if (jv_get_kind(ss) != JV_KIND_ARRAY) { + *res = jv_invalid_with_msg(jv_string("spawn attribute sigset must be array of signal names")); + jv_free(ss); + return EINVAL; + } + jv_array_foreach(ss, i, signame) { + if (jv_get_kind(signame) != JV_KIND_STRING) { + *res = jv_invalid_with_msg(jv_string("spawn attribute sigset must be array of signal names")); + jv_free(ss); + return EINVAL; + } + const char *s = jv_string_value(signame); +#define sig1(name) \ + do { if (strcmp(s, #name) == 0) { sigaddset(ssp, name); jv_free(signame); continue; } } while (0) + sig1(SIGHUP); + sig1(SIGINT); + sig1(SIGQUIT); + sig1(SIGILL); + sig1(SIGTRAP); +#ifdef SIGIOT + sig1(SIGIOT); +#endif + sig1(SIGBUS); + sig1(SIGFPE); + sig1(SIGKILL); + sig1(SIGUSR1); + sig1(SIGSEGV); + sig1(SIGUSR2); + sig1(SIGPIPE); + sig1(SIGALRM); + sig1(SIGTERM); +#ifdef SIGSTKFLT + sig1(SIGSTKFLT); +#endif + sig1(SIGCHLD); + sig1(SIGCONT); + sig1(SIGSTOP); + sig1(SIGTSTP); + sig1(SIGTTIN); + sig1(SIGTTOU); + sig1(SIGURG); +#ifdef SIGSTKFLT + sig1(SIGXCPU); +#endif +#ifdef SIGXFSZ + sig1(SIGXFSZ); +#endif +#ifdef SIGVTALRM + sig1(SIGVTALRM); +#endif +#ifdef SIGPROF + sig1(SIGPROF); +#endif +#ifdef SIGWINCH + sig1(SIGWINCH); +#endif +#ifdef SIGPOLL + sig1(SIGPOLL); +#endif +#ifdef SIGPWR + sig1(SIGPWR); +#endif +#ifdef SIGSYS + sig1(SIGSYS); +#endif + *res = jv_invalid_with_msg(jv_string_fmt("spawn attribute signal %s not supported", s)); + jv_free(signame); + jv_free(ss); + return EINVAL; + } + jv_free(ss); + return 0; +} + +static int jv2pattr(jv attr, posix_spawnattr_t *pattrs, jv *res) { + int ret; + + if (jv_get_kind(attr) != JV_KIND_OBJECT) { + *res = jv_invalid_with_msg(jv_string("spawn attributes must be objects")); + jv_free(attr); + return EINVAL; + } + jv v = jv_object_get(jv_copy(attr), jv_string("value")); + attr = jv_object_get(attr, jv_string("attr")); + + if (jv_get_kind(attr) != JV_KIND_STRING) { + *res = jv_invalid_with_msg(jv_string("spawn attributes names must be strings")); + jv_free(attr); + return EINVAL; + } + + const char *s = jv_string_value(attr); + if (strcmp(s, "flags") == 0) { + short flags; + + if (jv2attrflags(&flags, v, res)) { + jv_free(attr); + return EINVAL; + } + if ((ret = posix_spawnattr_setflags(pattrs, flags))) { + *res = jv_invalid_with_msg(jv_string_fmt("could not set spawn flags: %s", strerror(ret))); + jv_free(attr); + return ret; + } + } else if (strcmp(s, "pgroup") == 0) { + if (jv_get_kind(v) != JV_KIND_NUMBER) { + *res = jv_invalid_with_msg(jv_string("spawn pgroup attribute must be numeric")); + jv_free(attr); + return EINVAL; + } + if ((ret = posix_spawnattr_setpgroup(pattrs, jv_number_value(v)))) { + *res = jv_invalid_with_msg(jv_string_fmt("could not set spawn pgroup: %s", strerror(ret))); + jv_free(v); + jv_free(attr); + return ret; + } + jv_free(v); + } else if (strcmp(s, "sigdefault") == 0 || strcmp(s, "sigmask") == 0) { + sigset_t ss; + + if (!jv2sigset(&ss, v, res)) { + jv_free(attr); + return EINVAL; + } + if (strcmp(s, "sigdefault") == 0 && (ret = posix_spawnattr_setsigdefault(pattrs, &ss))) { + *res = jv_invalid_with_msg(jv_string_fmt("could not set spawn sigdefault: %s", strerror(ret))); + jv_free(attr); + return ret; + } else if (strcmp(s, "sigmask") == 0 && (ret = posix_spawnattr_setsigmask(pattrs, &ss))) { + *res = jv_invalid_with_msg(jv_string_fmt("could not set spawn sigmask: %s", strerror(ret))); + jv_free(attr); + return ret; + } + } else { + *res = jv_invalid_with_msg(jv_string_fmt("spawn attribute %s not supported", s)); + jv_free(attr); + return EINVAL; + } + + return 0; +} + +static const char **jv2charvec(jv vec, jv *res) { + const char **charvec; + size_t n = 0; + + if ((charvec = calloc(jv_array_length(vec) + 1, sizeof(charvec[0])))) { + jv_array_foreach(vec, i, v) { + if (jv_get_kind(v) != JV_KIND_STRING) { + jv_free(v); + free(charvec); + *res = jv_invalid_with_msg(jv_string("argument vector must be an array of strings")); + return NULL; + } + charvec[i] = jv_string_value(v); + jv_free(v); // we still have a reference via vec + n++; + } + jv_free(vec); + charvec[n] = NULL; + } + return charvec; +} + +#ifndef WIN32 +# ifdef __APPLE__ +# include +# define environ (*_NSGetEnviron()) +# else + extern char ** environ; +# endif +#endif + +jv jq_spawn_process(jq_state *jq, jv file, jv file_actions, jv attrs, jv argv, jv env) { + posix_spawn_file_actions_t pfacs; + posix_spawnattr_t pattrs; + struct pipes p; + const char **argvp = NULL; + const char **envp = NULL; + pid_t pid; + int ret; + jv res = jv_invalid(); + + p.pin[0] = p.pin[1] = p.pout[0] = p.pout[1] = p.perr[0] = p.perr[1] = -1; + + if ((ret = posix_spawn_file_actions_init(&pfacs))) { + res = jv_invalid_with_msg(jv_string_fmt("Could not spawn process: %s", strerror(ret))); + goto out3; + } + if ((ret = posix_spawnattr_init(&pattrs))) { + res = jv_invalid_with_msg(jv_string_fmt("Could not spawn process: %s", strerror(ret))); + goto out2; + } + + if (jv_get_kind(file) != JV_KIND_STRING) { + res = jv_invalid_with_msg(jv_string("spawn file must be a string")); + goto out; + } + if (jv_get_kind(argv) != JV_KIND_ARRAY) { + res = jv_invalid_with_msg(jv_string("argument vector must be an array of strings")); + goto out; + } + res = jq_io_policy_check(jq, JV_OBJECT(jv_string("kind"), jv_string("spawn"), + jv_string("file"), jv_copy(file), + jv_string("file_actions"), jv_copy(file_actions), + jv_string("attributes"), jv_copy(attrs), + jv_string("argv"), jv_copy(argv), + jv_string("env"), jv_copy(env))); + if (jv_get_kind(res) != JV_KIND_TRUE) + goto out; + if ((argvp = jv2charvec(jv_copy(argv), &res)) == NULL) + goto out; + if (jv_get_kind(env) != JV_KIND_NULL && jv_get_kind(env) != JV_KIND_ARRAY) { + res = jv_invalid_with_msg(jv_string("environment vector must be an array of strings")); + goto out; + } + if (jv_get_kind(env) == JV_KIND_ARRAY && (envp = jv2charvec(jv_copy(env), &res)) == NULL) + goto out; + + if (jv_get_kind(file_actions) == JV_KIND_ARRAY) { + jv_array_foreach(file_actions, i, v) { + if (jv2pfac(jq, v, &p, &pfacs, &res)) + goto out; + } + } + + if (jv_get_kind(attrs) == JV_KIND_ARRAY) { + jv_array_foreach(attrs, i, v) { + if (jv2pattr(jv_copy(v), &pattrs, &res)) + goto out; + } + } + + if ((ret = posix_spawnp(&pid, jv_string_value(file), &pfacs, &pattrs, + (char * const *)argvp, + envp ? (char * const *)envp : environ))) { + res = jv_invalid_with_msg(jv_string_fmt("Could not spawn process: %s", strerror(ret))); + goto out; + } + + res = JV_OBJECT(jv_string("pid"), jv_number(pid), + jv_string("ppid"), jv_number(getpid()), + jv_string("pgroup"), jv_number(getpgid(pid))); + if (p.pin[0] != -1) + res = jv_object_set(res, jv_string("stdin"), JV_ARRAY(jv_number(p.pin[0]), jv_number(p.pin[1]))); + if (p.pout[0] != -1) + res = jv_object_set(res, jv_string("stdout"), JV_ARRAY(jv_number(p.pout[0]), jv_number(p.pout[1]))); + if (p.perr[0] != -1) + res = jv_object_set(res, jv_string("stderr"), JV_ARRAY(jv_number(p.perr[0]), jv_number(p.perr[1]))); + +out: +out2: +out3: + jv_free(file_actions); + jv_free(attrs); + jv_free(argv); + jv_free(env); + free(argvp); + free(envp); + if (jv_get_kind(res) == JV_KIND_INVALID) { + (void) close(p.pin[0]); + (void) close(p.pin[1]); + (void) close(p.pout[0]); + (void) close(p.pout[1]); + (void) close(p.perr[0]); + (void) close(p.perr[1]); + } + return res; + +} +#endif diff --git a/src/util.h b/src/util.h index 5a94c39ff9..ab81e6523f 100644 --- a/src/util.h +++ b/src/util.h @@ -12,6 +12,7 @@ #endif #include "jv.h" +#include "jq.h" #ifndef HAVE_MKSTEMP int mkstemp(char *template); @@ -20,6 +21,7 @@ int mkstemp(char *template); jv expand_path(jv); jv get_home(void); jv jq_realpath(jv); +jv jq_spawn_process(jq_state *, jv, jv, jv, jv, jv); /* * The Windows CRT and console are something else. In order for the diff --git a/tests/jq.test b/tests/jq.test index 1e0ce071d6..e5bb1a61f2 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -741,19 +741,19 @@ null # Destructuring DUP/POP issues .[] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] -# Runtime error: "jq: Cannot index array with string \"c\"" +%%ERROR: "Cannot index array with string \"a\"" .[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] -# Runtime error: "jq: Cannot index array with string \"c\"" +%%ERROR: "Cannot index array with string \"a\"" [[3],[4],[5],6][] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a null -# Runtime error: "jq: Cannot index array with string \"c\"" +%%ERROR: "Cannot index array with string \"a\"" [[3],[4],[5],6] | .[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a null -# Runtime error: "jq: Cannot index array with string \"c\"" +%%ERROR: "Cannot index array with string \"a\"" .[] | . as {a:$a} ?// {a:$a} ?// $a | $a [[3],[4],[5],6] @@ -1715,4 +1715,28 @@ false . |= try . catch . 1 -1 \ No newline at end of file +1 + +# try/catch catches more than it should #1859 +(try . catch .) | error +"foo" +%%ERROR: "foo" + +.[]|(try (if .=="hi" then . else error end) catch empty) | "\(.) there!" +["hi","ho"] +"hi there!" + +.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end +["hi","ho"] +"hi there!" +%%ERROR: "ho" + +try (try error catch "inner catch \(.)") catch "outer catch \(.)" +"foo" +"inner catch foo" + +try ((try error catch "inner catch \(.)")|error) catch "outer catch \(.)" +"foo" +"outer catch inner catch foo" + + diff --git a/tests/modules/somod/somod.c b/tests/modules/somod/somod.c new file mode 100644 index 0000000000..66d91f4ed2 --- /dev/null +++ b/tests/modules/somod/somod.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef JQ_PLUGIN +#error "JQ_PLUGIN not defined!" +#endif +#include + +static jv f_add1(jq_state *jq, jv input) { + if (jv_get_kind(input) == JV_KIND_NUMBER) { + double n = jv_number_value(input); + + return jv_free(input), jv_number(n + 1); + } + if (jv_get_kind(input) == JV_KIND_STRING) + return jv_string_concat(input, jv_string("1")); + if (jv_get_kind(input) == JV_KIND_ARRAY) + return jv_array_append(input, jv_number(1)); + return jv_invalid_with_msg(jv_string("add1 only works for numbers, strings, and arrays")); +} + +static jv f_urandomn(jq_state *jq, jv input) { + int fd = open("/dev/urandom", O_RDONLY); + uint64_t n; + jv r; + + jv_free(input); + + if (fd == -1) + return jv_invalid_with_msg(jv_string_fmt("Could not open /dev/urandom: %s", + strerror(errno))); + + if (read(fd, &n, sizeof(n)) != sizeof(n)) + return jv_invalid_with_msg(jv_string("Could not read enough bytes from /dev/urandom")); + + r = jv_number(n & ~((1ULL<<53)-1)); + (void) close(fd); + return r; +} + +struct cfunction my_cfuncs[] = { + { (cfunction_ptr)f_add1, "_add1", 1, 1, 1}, + { (cfunction_ptr)f_urandomn, "_urandomn", 1, 0, 0}, +}; + +int jq_plugin_init(int min_abi, + int max_abi, + struct jq_state *jq, + const char **err, + const char **contents, + size_t *contentssz, + struct cfunction **cf, + size_t *ncf) + +{ + *contents = *err = 0; + *ncf = *contentssz = 0; + *cf = 0; + + if (JQ_CURRENT_ABI < min_abi || JQ_CURRENT_ABI > max_abi) { + *err = "Wrong ABI version"; + return 1; + } + + /* + * Show this works too, allowing modules to have trivial .jq files + * and all the jq code in .c files + */ + *contents = + "module {\"cfunctions\":\"somod\"};" + "def add1: _add1;" + "def urandn: _urandomn;" + "def add2: add1 | add1;" + "def saddr: . + (urandn | tostring);"; + *contentssz = strlen(*contents); + *cf = my_cfuncs; + *ncf = sizeof(my_cfuncs) / sizeof(my_cfuncs[0]); + return 0; +} diff --git a/tests/modules/somod/somod.jq b/tests/modules/somod/somod.jq new file mode 100644 index 0000000000..c03244601c --- /dev/null +++ b/tests/modules/somod/somod.jq @@ -0,0 +1,3 @@ +module {"cfunctions":"somod"}; +def add1: _add1; +def urandn: _urandomn; diff --git a/tests/shtest b/tests/shtest index 8ed62b2213..85b8d63218 100755 --- a/tests/shtest +++ b/tests/shtest @@ -19,6 +19,10 @@ if [ -f "$JQBASEDIR/.libs/libinject_errors.so" ]; then ) fi +# Rudimentary test of I/O +printf '["a"]{"b":1}\n'| + $VALGRIND $Q $JQ -cne --io 'include "jq/io";"/dev/stdin"|slurpfile== [["a"],{b:1}]' > /dev/null + printf 'a\0b\nc\0d\ne' > $d/input $VALGRIND $Q $JQ -Rse '. == "a\u0000b\nc\u0000d\ne"' $d/input $VALGRIND $Q $JQ -Rne '[inputs] == ["a\u0000b", "c\u0000d", "e"]' $d/input @@ -150,6 +154,13 @@ cmp $d/out $d/expected printf "[1,2][3,4]\n" | $JQ -cs add > $d/out 2>&1 cmp $d/out $d/expected +## Test dlopen/LoadLibrary +if expr match "`file $JQ`" '.*ELF'; then + cp -p $JQBASEDIR/.libs/somod.so $JQBASEDIR/tests/modules/somod/somod.so + $VALGRIND $Q $JQ -L $JQBASEDIR/tests/modules -n 'include "somod"; "HELLO DLOPEN! \(1|add1)"' +else + echo "No dlopen support" +fi ## Test streaming parser