From d5b8959ea5941b3f0f363eb1cf6986192b8ef9e9 Mon Sep 17 00:00:00 2001 From: Jeroen Date: Mon, 18 Sep 2017 21:39:05 +0200 Subject: [PATCH 1/4] Unbundle libjq --- .Rbuildignore | 2 +- .gitignore | 1 + .travis.yml | 13 +- DESCRIPTION | 16 +- cleanup | 2 + configure | 65 + src/Makevars | 37 - src/Makevars.in | 7 + src/Makevars.win | 12 + src/config.h | 59 - src/jq/AUTHORS | 71 - src/jq/builtin.c | 1494 -------------- src/jq/builtin.h | 10 - src/jq/builtin.inc | 306 --- src/jq/bytecode.c | 161 -- src/jq/bytecode.h | 92 - src/jq/compile.c | 1232 ----------- src/jq/compile.h | 102 - src/jq/exec_stack.h | 112 - src/jq/execute.c | 1155 ----------- src/jq/inject_errors.c | 112 - src/jq/jq.h | 60 - src/jq/jq_parser.h | 9 - src/jq/jq_test.c | 346 ---- src/jq/jv.c | 1334 ------------ src/jq/jv.h | 265 --- src/jq/jv_alloc.c | 179 -- src/jq/jv_alloc.h | 27 - src/jq/jv_aux.c | 643 ------ src/jq/jv_dtoa.c | 4274 --------------------------------------- src/jq/jv_dtoa.h | 22 - src/jq/jv_file.c | 62 - src/jq/jv_parse.c | 858 -------- src/jq/jv_print.c | 353 ---- src/jq/jv_unicode.c | 120 -- src/jq/jv_unicode.h | 12 - src/jq/jv_utf8_tables.h | 37 - src/jq/lexer.c | 2442 ---------------------- src/jq/lexer.h | 362 ---- src/jq/libm.h | 301 --- src/jq/linker.c | 392 ---- src/jq/linker.h | 7 - src/jq/locfile.c | 91 - src/jq/locfile.h | 29 - src/jq/main.c | 587 ------ src/jq/opcode_list.h | 44 - src/jq/parser.c | 3915 ----------------------------------- src/jq/parser.h | 193 -- src/jq/util.c | 459 ----- src/jq/util.h | 63 - src/jq/version.h | 1 - src/jqr.c | 4 +- tools/winlibs.R | 8 + 53 files changed, 109 insertions(+), 22451 deletions(-) create mode 100755 cleanup create mode 100755 configure delete mode 100644 src/Makevars create mode 100644 src/Makevars.in create mode 100644 src/Makevars.win delete mode 100644 src/config.h delete mode 100644 src/jq/AUTHORS delete mode 100644 src/jq/builtin.c delete mode 100644 src/jq/builtin.h delete mode 100644 src/jq/builtin.inc delete mode 100644 src/jq/bytecode.c delete mode 100644 src/jq/bytecode.h delete mode 100644 src/jq/compile.c delete mode 100644 src/jq/compile.h delete mode 100644 src/jq/exec_stack.h delete mode 100644 src/jq/execute.c delete mode 100644 src/jq/inject_errors.c delete mode 100644 src/jq/jq.h delete mode 100644 src/jq/jq_parser.h delete mode 100644 src/jq/jq_test.c delete mode 100644 src/jq/jv.c delete mode 100644 src/jq/jv.h delete mode 100644 src/jq/jv_alloc.c delete mode 100644 src/jq/jv_alloc.h delete mode 100644 src/jq/jv_aux.c delete mode 100644 src/jq/jv_dtoa.c delete mode 100644 src/jq/jv_dtoa.h delete mode 100644 src/jq/jv_file.c delete mode 100644 src/jq/jv_parse.c delete mode 100644 src/jq/jv_print.c delete mode 100644 src/jq/jv_unicode.c delete mode 100644 src/jq/jv_unicode.h delete mode 100644 src/jq/jv_utf8_tables.h delete mode 100644 src/jq/lexer.c delete mode 100644 src/jq/lexer.h delete mode 100644 src/jq/libm.h delete mode 100644 src/jq/linker.c delete mode 100644 src/jq/linker.h delete mode 100644 src/jq/locfile.c delete mode 100644 src/jq/locfile.h delete mode 100644 src/jq/main.c delete mode 100644 src/jq/opcode_list.h delete mode 100644 src/jq/parser.c delete mode 100644 src/jq/parser.h delete mode 100644 src/jq/util.c delete mode 100644 src/jq/util.h delete mode 100644 src/jq/version.h create mode 100644 tools/winlibs.R diff --git a/.Rbuildignore b/.Rbuildignore index 87fc346..2d5e8f2 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -16,5 +16,5 @@ cran-comments.md ^src/.*\.a$ ^docker$ .github - +$src/Makevars$ ^cran-comments\.md$ diff --git a/.gitignore b/.gitignore index 3dc83f0..8e4557a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ jq-*.tar.gz jqr_*.tar.gz notes.md src/*.dll +src/Makevars diff --git a/.travis.yml b/.travis.yml index 2036820..beab3e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: r cache: packages -latex: false dist: trusty +latex: false matrix: include: @@ -14,17 +14,18 @@ matrix: env: R_CODECOV=true - os: osx osx_image: xcode8.3 + brew_packages: jq - os: osx osx_image: xcode7.3 + disable_homebrew: true addons: + sources: + - sourceline: 'ppa:opencpu/jq' apt: packages: - - r-cran-lazyeval - - r-cran-magrittr - - r-cran-testthat - - r-cran-jsonlite - - r-cran-knitr + - libjq-dev + - valgrind after_success: - if [[ "${R_CODECOV}" ]]; then R -e 'covr::codecov()'; fi diff --git a/DESCRIPTION b/DESCRIPTION index 2d53e14..6af3105 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,18 +9,10 @@ Depends: R (>= 3.1.2) License: MIT + file LICENSE LazyData: true -Authors@R: c(person("Rich", "FitzJohn", role = "aut", - email = "rich.fitzjohn@gmail.com"), - person("Jeroen", "Ooms", role = "aut"), - person("Scott", "Chamberlain", role = c("aut", "cre"), - email = "myrmecocystus@gmail.com"), - person("Stefan Milton Bache", role = "aut", - email = "stefan@stefanbache.dk"), - person("Stephen", "Dolan", role = c("aut","cph"), comment = "jq library"), - person(family = "jq contributors", role = "ctb", - comment = "jq library; authors listed in inst/AUTHORS.jq"), - person("Free Software Foundation", role = c("ctb","cph"), comment = "parser code in src/parser.c"), - person("David M", "Gay", role = c("ctb","cph"), comment = "code in src/jv_dtoa.c")) +Authors@R: c(person("Rich", "FitzJohn", role = "aut", email = "rich.fitzjohn@gmail.com"), + person("Jeroen", "Ooms", role = "aut", email = "jeroen@berkeley.edu"), + person("Scott", "Chamberlain", role = c("aut", "cre"), email = "myrmecocystus@gmail.com"), + person("Stefan Milton Bache", role = "aut", email = "stefan@stefanbache.dk")) VignetteBuilder: knitr URL: https://github.com/ropensci/jqr BugReports: https://github.com/ropensci/jqr/issues diff --git a/cleanup b/cleanup new file mode 100755 index 0000000..3c020d3 --- /dev/null +++ b/cleanup @@ -0,0 +1,2 @@ +#!/bin/sh +rm -f src/Makevars diff --git a/configure b/configure new file mode 100755 index 0000000..71e0404 --- /dev/null +++ b/configure @@ -0,0 +1,65 @@ +#!/bin/bash +# Anticonf (tm) script by Jeroen Ooms (2017) +# This script will query 'pkg-config' for the required cflags and ldflags. +# If pkg-config is unavailable or does not find the library, try setting +# INCLUDE_DIR and LIB_DIR manually via e.g: +# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib' + +# Library settings +PKG_DEB_NAME="libjq-dev" +PKG_RPM_NAME="jq-devel" +PKG_CSW_NAME="libjq_dev" +PKG_BREW_NAME="jq" +PKG_TEST_HEADER="" +PKG_LIBS="-ljq" +PKG_LIBS_STATIC="-ljq -lonig" +PKG_CFLAGS="" + +# Note that cflags may be empty in case of success +if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then + echo "Found INCLUDE_DIR and/or LIB_DIR!" + PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS" + PKG_LIBS="-L$LIB_DIR $PKG_LIBS" +elif [[ "$OSTYPE" == "darwin"* ]]; then + if [ $(command -v brew) ]; then + BREWDIR=$(brew --prefix) + else + # autobrew in /tmp + curl -sfL "https://jeroen.github.io/autobrew/$PKG_BREW_NAME" > autobrew + source autobrew + fi + PKG_CFLAGS="-I$BREWDIR/opt/$PKG_BREW_NAME/include" + PKG_LIBS="-L$BREWDIR/lib $PKG_LIBS" +fi + +# For debugging +echo "Using PKG_CFLAGS=$PKG_CFLAGS" +echo "Using PKG_LIBS=$PKG_LIBS" + +# Find compiler +CC=$(${R_HOME}/bin/R CMD config CC) +CFLAGS=$(${R_HOME}/bin/R CMD config CFLAGS) +CPPFLAGS=$(${R_HOME}/bin/R CMD config CPPFLAGS) + +# Test configuration +echo "#include $PKG_TEST_HEADER" | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E -xc - >/dev/null 2>&1 + +# Customize the error +if [ $? -ne 0 ]; then + echo "------------------------- ANTICONF ERROR ---------------------------" + echo "Configuration failed because $PKG_CONFIG_NAME was not found. Try installing:" + echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)" + echo " * rpm: $PKG_RPM_NAME (Fedora, EPEL)" + echo " * csw: $PKG_CSW_NAME (Solaris)" + echo " * brew: $PKG_BREW_NAME (OSX)" + echo "If $PKG_CONFIG_NAME is already installed set INCLUDE_DIR and LIB_DIR manually via:" + echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'" + echo "--------------------------------------------------------------------" + exit 1; +fi + +# Write to Makevars +sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars + +# Success +exit 0 diff --git a/src/Makevars b/src/Makevars deleted file mode 100644 index ec7aacb..0000000 --- a/src/Makevars +++ /dev/null @@ -1,37 +0,0 @@ -LIBJQ = \ - jq/locfile.o \ - jq/bytecode.o \ - jq/compile.o \ - jq/execute.o \ - jq/builtin.o \ - jq/jv.o \ - jq/jv_parse.o \ - jq/jv_print.o \ - jq/jv_dtoa.o \ - jq/jv_unicode.o \ - jq/jv_aux.o \ - jq/jv_file.o \ - jq/jv_alloc.o \ - jq/jq_test.o \ - jq/util.o \ - jq/linker.o \ - jq/parser.o \ - jq/lexer.o - -STATLIB=jq/libstatjq.a - -all: clean - -clean: - rm -f $(LIBJQ) $(OBJECTS) $(SHLIB) $(STATLIB) - -$(SHLIB): $(STATLIB) - -$(STATLIB): $(LIBJQ) - $(AR) rcs $(STATLIB) $(LIBJQ) - -PKG_CFLAGS=-include config.h -PKG_CPPFLAGS=-Ijq $(C_VISIBILITY) - -WINLIBS=$(subst 64,-lshlwapi,$(subst 32,64,$(WIN))) -PKG_LIBS=-Ljq -lstatjq $(WINLIBS) diff --git a/src/Makevars.in b/src/Makevars.in new file mode 100644 index 0000000..14e59cc --- /dev/null +++ b/src/Makevars.in @@ -0,0 +1,7 @@ +PKG_CPPFLAGS=@cflags@ +PKG_LIBS=@libs@ + +all: clean + +clean: + rm -f $(SHLIB) $(OBJECTS) diff --git a/src/Makevars.win b/src/Makevars.win new file mode 100644 index 0000000..5b88ac9 --- /dev/null +++ b/src/Makevars.win @@ -0,0 +1,12 @@ +PKG_CPPFLAGS = -I../windows/jq-1.5/include +PKG_LIBS = -L../windows/jq-1.5/lib${R_ARCH} -ljq -lonig -lshlwapi + +all: clean winlibs + +winlibs: + "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" + +clean: + rm -f $(OBJECTS) jqr.dll + +.PHONY: all clean winlibs diff --git a/src/config.h b/src/config.h deleted file mode 100644 index 5dbc36a..0000000 --- a/src/config.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifdef __sun -#include -#else -#define HAVE_MEMMEM -#define HAVE_TIMEGM -#define HAVE_TM_TM_GMT_OFF -#endif - -#ifdef WIN32 -#undef HAVE_MEMMEM -#define HAVE__ISATTY -#else -#define HAVE_MKSTEMP -#define HAVE_STRPTIME -#define HAVE_GMTIME_R -#endif - -#define HAVE_ALLOCA -#define HAVE_ISATTY -#define HAVE_STRFTIME -#define HAVE_GMTIME -#define HAVE_GETTIMEOFDAY -#define HAVE_ACOS -#define HAVE_ACOSH -#define HAVE_ASIN -#define HAVE_ASINH -#define HAVE_ATAN -#define HAVE_ATANH -#define HAVE_CBRT -#define HAVE_COS -#define HAVE_COSH -#define HAVE_EXP2 -#define HAVE_EXP -#define HAVE_FLOOR -#define HAVE_J0 -#define HAVE_J1 -#define HAVE_LOG10 -#define HAVE_LOG2 -#define HAVE_LOG -#define HAVE_SIN -#define HAVE_SINH -#define HAVE_SQRT -#define HAVE_TAN -#define HAVE_TANH -#define HAVE_TGAMMA -#define HAVE_Y0 -#define HAVE_Y1 -#define HAVE_POW -#define HAVE_ATAN2 -#define HAVE_HYPOT -#define HAVE_REMAINDER -#define HAVE___THREAD - -#include -#ifdef WORDS_BIGENDIAN - #define IEEE_MC68k -#else - #define IEEE_8087 -#endif diff --git a/src/jq/AUTHORS b/src/jq/AUTHORS deleted file mode 100644 index da04d5c..0000000 --- a/src/jq/AUTHORS +++ /dev/null @@ -1,71 +0,0 @@ -Created By: -Stephen Dolan - -Maintained by: -Nicolas Williams -William Langford - -Contributions by: -Aaron Peschel -Adam Lindberg -Alex Chamberlain -Andrew O'Brien - docs build -Andrew Rodland - bug fixes -Ankur - bug fixes -Anthony Shortland - rpmbuild target -Assaf Gordon - error handling -Brendan Macmillan - bug fixes, load library from ~/.jq -cdnbacon -Charles Merriam -Colin von Heuring -Damian Gryski -David Haguenauer -David R. MacIver - bug fixes -David Tolnay - destructuring, build improvements -Doug Luce - build -Eiichi Sato -Filippo Giunchedi - bug fixes -Filippo Valsorda - recursive object merge (`*`) -Hanfei Shen -i -Ian Miell -Jack Pearkes - update tutorial -James Andariese - Dockerfile -Jingwen Owen Ou - jqplay.org and link to it -jkleint -Joe Littlejohn - bug fixes -Joel Purra -Juan Guerrero - bug fixes -Kenny Shen - doc fixes -Kim De Mey - build -Kim Toms -LCD 47 -Lee Thompson - autoconf stuff, rpm -Marc Abramowitz -Marc Bruggmann -Markus Lanthaler - doc fixes -Maxime Biais - build -Michael Daines - add sqrt; doc fixes -Mike Fletcher -Mike McCabe - math (libm) functions -Nicolas Pouillard - add tests -Nicolas Williams - library-fication, autoconf stuff, exception handling, various -Peter van Dijk - doc fixes -Philipp Hagemeister - doc fixes -pkoppstein - various builtins, improvements -polyester - automake version update -Ryoichi KATO - doc fixes -Rémy Léone - add .travis.yml -Santiago Lapresta - join, arrays, all, any, other filters -Sebastian Freundt - build -Shay Elkin -Simon Elsbrock - Debian -Stefan Seemayer -Stephen Roantree -Stephen Shaw -Steven Maude -Steven Penny - Windows bug fixes -tal@whatexit.org -Travis Gockel -Zhiming Wang -13ren diff --git a/src/jq/builtin.c b/src/jq/builtin.c deleted file mode 100644 index 692c45c..0000000 --- a/src/jq/builtin.c +++ /dev/null @@ -1,1494 +0,0 @@ -#define _BSD_SOURCE -#define _GNU_SOURCE -#ifndef __sun__ -# define _XOPEN_SOURCE -# define _XOPEN_SOURCE_EXTENDED 1 -#else -# define _XPG6 -# define __EXTENSIONS__ -#endif -#include -#include -#include -#ifdef HAVE_ALLOCA_H -# include -#elif !defined alloca -# ifdef __GNUC__ -# define alloca __builtin_alloca -# elif defined _MSC_VER -# include -# define alloca _alloca -# elif !defined HAVE_ALLOCA -# ifdef __cplusplus -extern "C" -# endif -void *alloca (size_t); -# endif -#endif -#include -#include -#include -#include -#ifdef HAVE_ONIGURUMA -#include -#endif -#include -#include -#include "builtin.h" -#include "compile.h" -#include "jq_parser.h" -#include "bytecode.h" -#include "linker.h" -#include "locfile.h" -#include "jv_unicode.h" - -//Workaround for windows i386: https://sourceforge.net/p/mingw-w64/bugs/473/ - -#ifdef WIN32 -#ifdef WIN64 -#define timegm _mkgmtime -#else -time_t timegm(struct tm * a_tm) -{ - time_t ltime = mktime(a_tm); - struct tm tm_val; - gmtime_s(&tm_val, <ime); - int offset = (tm_val.tm_hour - a_tm->tm_hour); - if (offset > 12) - { - offset = 24 - offset; - } - time_t utc = mktime(a_tm) - offset * 3600; - return utc; -} -#endif -#endif - - -static jv type_error(jv bad, const char* msg) { - char errbuf[15]; - jv err = jv_invalid_with_msg(jv_string_fmt("%s (%s) %s", - jv_kind_name(jv_get_kind(bad)), - jv_dump_string_trunc(jv_copy(bad), errbuf, sizeof(errbuf)), - msg)); - jv_free(bad); - return err; -} - -static jv type_error2(jv bad1, jv bad2, const char* msg) { - char errbuf1[15],errbuf2[15]; - jv err = jv_invalid_with_msg(jv_string_fmt("%s (%s) and %s (%s) %s", - jv_kind_name(jv_get_kind(bad1)), - jv_dump_string_trunc(jv_copy(bad1), errbuf1, sizeof(errbuf1)), - jv_kind_name(jv_get_kind(bad2)), - jv_dump_string_trunc(jv_copy(bad2), errbuf2, sizeof(errbuf2)), - msg)); - jv_free(bad1); - jv_free(bad2); - return err; -} - -static jv f_plus(jq_state *jq, jv input, jv a, jv b) { - jv_free(input); - if (jv_get_kind(a) == JV_KIND_NULL) { - jv_free(a); - return b; - } else if (jv_get_kind(b) == JV_KIND_NULL) { - jv_free(b); - return a; - } else if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { - return jv_number(jv_number_value(a) + - jv_number_value(b)); - } else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) { - return jv_string_concat(a, b); - } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { - return jv_array_concat(a, b); - } else if (jv_get_kind(a) == JV_KIND_OBJECT && jv_get_kind(b) == JV_KIND_OBJECT) { - return jv_object_merge(a, b); - } else { - return type_error2(a, b, "cannot be added"); - } -} - -#define LIBM_DD(name) \ -static jv f_ ## name(jq_state *jq, jv input) { \ - if (jv_get_kind(input) != JV_KIND_NUMBER) { \ - return type_error(input, "number required"); \ - } \ - jv ret = jv_number(name(jv_number_value(input))); \ - jv_free(input); \ - return ret; \ -} -#define LIBM_DD_NO(name) - -#define LIBM_DDD(name) \ -static jv f_ ## name(jq_state *jq, jv input, jv a, jv b) { \ - if (jv_get_kind(a) != JV_KIND_NUMBER || jv_get_kind(b) != JV_KIND_NUMBER) \ - return type_error(input, "number required"); \ - jv_free(input); \ - jv ret = jv_number(name(jv_number_value(a), jv_number_value(b))); \ - jv_free(a); \ - jv_free(b); \ - return ret; \ -} -#define LIBM_DDD_NO(name) - -#define LIBM_DDDD(name) \ -static jv f_ ## name(jq_state *jq, jv input, jv a, jv b, jv c) { \ - if (jv_get_kind(a) != JV_KIND_NUMBER || jv_get_kind(b) != JV_KIND_NUMBER) \ - return type_error(input, "number required"); \ - jv_free(input); \ - jv ret = jv_number(name(jv_number_value(a), jv_number_value(b), jv_number_value(c))); \ - jv_free(a); \ - jv_free(b); \ - jv_free(c); \ - return ret; \ -} -#define LIBM_DDDD_NO(name) -#include "libm.h" -#undef LIBM_DDDD_NO -#undef LIBM_DDD_NO -#undef LIBM_DD_NO -#undef LIBM_DDDD -#undef LIBM_DDD -#undef LIBM_DD - -static jv f_negate(jq_state *jq, jv input) { - if (jv_get_kind(input) != JV_KIND_NUMBER) { - return type_error(input, "cannot be negated"); - } - jv ret = jv_number(-jv_number_value(input)); - jv_free(input); - return ret; -} - -static jv f_startswith(jq_state *jq, jv a, jv b) { - if (jv_get_kind(a) != JV_KIND_STRING || jv_get_kind(b) != JV_KIND_STRING) - return jv_invalid_with_msg(jv_string("startswith() requires string inputs")); - int alen = jv_string_length_bytes(jv_copy(a)); - int blen = jv_string_length_bytes(jv_copy(b)); - jv ret; - - if (blen <= alen && memcmp(jv_string_value(a), jv_string_value(b), blen) == 0) - ret = jv_true(); - else - ret = jv_false(); - jv_free(a); - jv_free(b); - return ret; -} - -static jv f_endswith(jq_state *jq, jv a, jv b) { - if (jv_get_kind(a) != JV_KIND_STRING || jv_get_kind(b) != JV_KIND_STRING) - return jv_invalid_with_msg(jv_string("endswith() requires string inputs")); - const char *astr = jv_string_value(a); - const char *bstr = jv_string_value(b); - size_t alen = jv_string_length_bytes(jv_copy(a)); - size_t blen = jv_string_length_bytes(jv_copy(b)); - jv ret;; - - if (alen < blen || - memcmp(astr + (alen - blen), bstr, blen) != 0) - ret = jv_false(); - else - ret = jv_true(); - jv_free(a); - jv_free(b); - return ret; -} - -static jv f_ltrimstr(jq_state *jq, jv input, jv left) { - if (jv_get_kind(f_startswith(jq, jv_copy(input), jv_copy(left))) != JV_KIND_TRUE) { - jv_free(left); - return input; - } - /* - * FIXME It'd be better to share the suffix with the original input -- - * that we could do, we just can't share prefixes. - */ - int prefixlen = jv_string_length_bytes(left); - jv res = jv_string_sized(jv_string_value(input) + prefixlen, - jv_string_length_bytes(jv_copy(input)) - prefixlen); - jv_free(input); - return res; -} - -static jv f_rtrimstr(jq_state *jq, jv input, jv right) { - if (jv_get_kind(f_endswith(jq, jv_copy(input), jv_copy(right))) == JV_KIND_TRUE) { - jv res = jv_string_sized(jv_string_value(input), - jv_string_length_bytes(jv_copy(input)) - jv_string_length_bytes(right)); - jv_free(input); - return res; - } - jv_free(right); - return input; -} - -static jv f_minus(jq_state *jq, jv input, jv a, jv b) { - jv_free(input); - if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { - return jv_number(jv_number_value(a) - jv_number_value(b)); - } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { - jv out = jv_array(); - jv_array_foreach(a, i, x) { - int include = 1; - jv_array_foreach(b, j, y) { - if (jv_equal(jv_copy(x), y)) { - include = 0; - break; - } - } - if (include) - out = jv_array_append(out, jv_copy(x)); - jv_free(x); - } - jv_free(a); - jv_free(b); - return out; - } else { - return type_error2(a, b, "cannot be subtracted"); - } -} - -static jv f_multiply(jq_state *jq, jv input, jv a, jv b) { - jv_kind ak = jv_get_kind(a); - jv_kind bk = jv_get_kind(b); - jv_free(input); - if (ak == JV_KIND_NUMBER && bk == JV_KIND_NUMBER) { - return jv_number(jv_number_value(a) * jv_number_value(b)); - } else if ((ak == JV_KIND_STRING && bk == JV_KIND_NUMBER) || - (ak == JV_KIND_NUMBER && bk == JV_KIND_STRING)) { - jv str = a; - jv num = b; - if (ak == JV_KIND_NUMBER) { - str = b; - num = a; - } - int n; - size_t alen = jv_string_length_bytes(jv_copy(str)); - jv res = str; - - for (n = jv_number_value(num) - 1; n > 0; n--) - res = jv_string_append_buf(res, jv_string_value(str), alen); - - jv_free(num); - if (n < 0) { - jv_free(str); - return jv_null(); - } - return res; - } else if (ak == JV_KIND_OBJECT && bk == JV_KIND_OBJECT) { - return jv_object_merge_recursive(a, b); - } else { - return type_error2(a, b, "cannot be multiplied"); - } -} - -static jv f_divide(jq_state *jq, jv input, jv a, jv b) { - jv_free(input); - if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { - if (jv_number_value(b) == 0.0) - return type_error2(a, b, "cannot be divided because the divisor is zero"); - return jv_number(jv_number_value(a) / jv_number_value(b)); - } else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) { - return jv_string_split(a, b); - } else { - return type_error2(a, b, "cannot be divided"); - } -} - -static jv f_mod(jq_state *jq, jv input, jv a, jv b) { - jv_free(input); - if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { - if ((intmax_t)jv_number_value(b) == 0) - return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero"); - return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b)); - } else { - return type_error2(a, b, "cannot be divided (remainder)"); - } -} - -static jv f_equal(jq_state *jq, jv input, jv a, jv b) { - jv_free(input); - return jv_bool(jv_equal(a, b)); -} - -static jv f_notequal(jq_state *jq, jv input, jv a, jv b) { - jv_free(input); - return jv_bool(!jv_equal(a, b)); -} - -enum cmp_op { - CMP_OP_LESS, - CMP_OP_GREATER, - CMP_OP_LESSEQ, - CMP_OP_GREATEREQ -}; - -static jv order_cmp(jv input, jv a, jv b, enum cmp_op op) { - jv_free(input); - int r = jv_cmp(a, b); - return jv_bool((op == CMP_OP_LESS && r < 0) || - (op == CMP_OP_LESSEQ && r <= 0) || - (op == CMP_OP_GREATEREQ && r >= 0) || - (op == CMP_OP_GREATER && r > 0)); -} - -static jv f_less(jq_state *jq, jv input, jv a, jv b) { - return order_cmp(input, a, b, CMP_OP_LESS); -} - -static jv f_greater(jq_state *jq, jv input, jv a, jv b) { - return order_cmp(input, a, b, CMP_OP_GREATER); -} - -static jv f_lesseq(jq_state *jq, jv input, jv a, jv b) { - return order_cmp(input, a, b, CMP_OP_LESSEQ); -} - -static jv f_greatereq(jq_state *jq, jv input, jv a, jv b) { - return order_cmp(input, a, b, CMP_OP_GREATEREQ); -} - -static jv f_contains(jq_state *jq, jv a, jv b) { - if (jv_get_kind(a) == jv_get_kind(b)) { - return jv_bool(jv_contains(a, b)); - } else { - return type_error2(a, b, "cannot have their containment checked"); - } -} - -static jv f_dump(jq_state *jq, jv input) { - return jv_dump_string(input, 0); -} - -static jv f_json_parse(jq_state *jq, jv input) { - if (jv_get_kind(input) != JV_KIND_STRING) - return type_error(input, "only strings can be parsed"); - jv res = jv_parse_sized(jv_string_value(input), - jv_string_length_bytes(jv_copy(input))); - jv_free(input); - return res; -} - -static jv f_tonumber(jq_state *jq, jv input) { - if (jv_get_kind(input) == JV_KIND_NUMBER) { - return input; - } - if (jv_get_kind(input) == JV_KIND_STRING) { - jv parsed = jv_parse(jv_string_value(input)); - if (!jv_is_valid(parsed) || jv_get_kind(parsed) == JV_KIND_NUMBER) { - jv_free(input); - return parsed; - } - } - return type_error(input, "cannot be parsed as a number"); -} - -static jv f_length(jq_state *jq, jv input) { - if (jv_get_kind(input) == JV_KIND_ARRAY) { - return jv_number(jv_array_length(input)); - } else if (jv_get_kind(input) == JV_KIND_OBJECT) { - return jv_number(jv_object_length(input)); - } else if (jv_get_kind(input) == JV_KIND_STRING) { - return jv_number(jv_string_length_codepoints(input)); - } else if (jv_get_kind(input) == JV_KIND_NUMBER) { - return jv_number(fabs(jv_number_value(input))); - } else if (jv_get_kind(input) == JV_KIND_NULL) { - jv_free(input); - return jv_number(0); - } else { - return type_error(input, "has no length"); - } -} - -static jv f_tostring(jq_state *jq, jv input) { - if (jv_get_kind(input) == JV_KIND_STRING) { - return input; - } else { - return jv_dump_string(input, 0); - } -} - -static jv f_utf8bytelength(jq_state *jq, jv input) { - if (jv_get_kind(input) != JV_KIND_STRING) - return type_error(input, "only strings have UTF-8 byte length"); - return jv_number(jv_string_length_bytes(input)); -} - -#define CHARS_ALPHANUM "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - -static jv escape_string(jv input, const char* escapings) { - - assert(jv_get_kind(input) == JV_KIND_STRING); - const char* lookup[128] = {0}; - const char* p = escapings; - lookup[0] = "\\0"; - while (*p) { - lookup[(int)*p] = p+1; - p++; - p += strlen(p); - p++; - } - - jv ret = jv_string(""); - const char* i = jv_string_value(input); - const char* end = i + jv_string_length_bytes(jv_copy(input)); - const char* cstart; - int c = 0; - while ((i = jvp_utf8_next((cstart = i), end, &c))) { - if (c < 128 && lookup[c]) { - ret = jv_string_append_str(ret, lookup[c]); - } else { - ret = jv_string_append_buf(ret, cstart, i - cstart); - } - } - jv_free(input); - return ret; - -} - -static jv f_format(jq_state *jq, jv input, jv fmt) { - if (jv_get_kind(fmt) != JV_KIND_STRING) { - jv_free(input); - return type_error(fmt, "is not a valid format"); - } - const char* fmt_s = jv_string_value(fmt); - if (!strcmp(fmt_s, "json")) { - jv_free(fmt); - return jv_dump_string(input, 0); - } else if (!strcmp(fmt_s, "text")) { - jv_free(fmt); - return f_tostring(jq, input); - } else if (!strcmp(fmt_s, "csv") || !strcmp(fmt_s, "tsv")) { - const char *quotes, *sep, *escapings; - const char *msg; - if (!strcmp(fmt_s, "csv")) { - msg = "cannot be csv-formatted, only array"; - quotes = "\""; - sep = ","; - escapings = "\"\"\"\0"; - } else { - msg = "cannot be tsv-formatted, only array"; - assert(!strcmp(fmt_s, "tsv")); - quotes = ""; - sep = "\t"; - escapings = "\t\\t\0\r\\r\0\n\\n\0\\\\\\\0"; - } - jv_free(fmt); - if (jv_get_kind(input) != JV_KIND_ARRAY) - return type_error(input, msg); - jv line = jv_string(""); - jv_array_foreach(input, i, x) { - if (i) line = jv_string_append_str(line, sep); - switch (jv_get_kind(x)) { - case JV_KIND_NULL: - /* null rendered as empty string */ - jv_free(x); - break; - case JV_KIND_TRUE: - case JV_KIND_FALSE: - line = jv_string_concat(line, jv_dump_string(x, 0)); - break; - case JV_KIND_NUMBER: - if (jv_number_value(x) != jv_number_value(x)) { - /* NaN, render as empty string */ - jv_free(x); - } else { - line = jv_string_concat(line, jv_dump_string(x, 0)); - } - break; - case JV_KIND_STRING: { - line = jv_string_append_str(line, quotes); - line = jv_string_concat(line, escape_string(x, escapings)); - line = jv_string_append_str(line, quotes); - break; - } - default: - jv_free(input); - jv_free(line); - return type_error(x, "is not valid in a csv row"); - } - } - jv_free(input); - return line; - } else if (!strcmp(fmt_s, "html")) { - jv_free(fmt); - return escape_string(f_tostring(jq, input), "&&\0<<\0>>\0''\0\""\0"); - } else if (!strcmp(fmt_s, "uri")) { - jv_free(fmt); - input = f_tostring(jq, input); - - int unreserved[128] = {0}; - const char* p = CHARS_ALPHANUM "-_.!~*'()"; - while (*p) unreserved[(int)*p++] = 1; - - jv line = jv_string(""); - const char* s = jv_string_value(input); - for (int i=0; i= 3 ? 3 : len-i; - for (int j=0; j<3; j++) { - code <<= 8; - code |= j < n ? (unsigned)data[i+j] : 0; - } - char buf[4]; - for (int j=0; j<4; j++) { - buf[j] = b64[(code >> (18 - j*6)) & 0x3f]; - } - if (n < 3) buf[3] = '='; - if (n < 2) buf[2] = '='; - line = jv_string_append_buf(line, buf, sizeof(buf)); - } - jv_free(input); - return line; - } else { - jv_free(input); - return jv_invalid_with_msg(jv_string_concat(fmt, jv_string(" is not a valid format"))); - } -} - -static jv f_keys(jq_state *jq, jv input) { - if (jv_get_kind(input) == JV_KIND_OBJECT || jv_get_kind(input) == JV_KIND_ARRAY) { - return jv_keys(input); - } else { - return type_error(input, "has no keys"); - } -} - -static jv f_keys_unsorted(jq_state *jq, jv input) { - if (jv_get_kind(input) == JV_KIND_OBJECT || jv_get_kind(input) == JV_KIND_ARRAY) { - return jv_keys_unsorted(input); - } else { - return type_error(input, "has no keys"); - } -} - -static jv f_sort(jq_state *jq, jv input){ - if (jv_get_kind(input) == JV_KIND_ARRAY) { - return jv_sort(input, jv_copy(input)); - } else { - return type_error(input, "cannot be sorted, as it is not an array"); - } -} - -static jv f_sort_by_impl(jq_state *jq, jv input, jv keys) { - if (jv_get_kind(input) == JV_KIND_ARRAY && - jv_get_kind(keys) == JV_KIND_ARRAY && - jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) { - return jv_sort(input, keys); - } else { - return type_error2(input, keys, "cannot be sorted, as they are not both arrays"); - } -} - -static jv f_group_by_impl(jq_state *jq, jv input, jv keys) { - if (jv_get_kind(input) == JV_KIND_ARRAY && - jv_get_kind(keys) == JV_KIND_ARRAY && - jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) { - return jv_group(input, keys); - } else { - return type_error2(input, keys, "cannot be sorted, as they are not both arrays"); - } -} - -#ifdef HAVE_ONIGURUMA -static int f_match_name_iter(const UChar* name, const UChar *name_end, int ngroups, - int *groups, regex_t *reg, void *arg) { - jv captures = *(jv*)arg; - for (int i = 0; i < ngroups; ++i) { - jv cap = jv_array_get(jv_copy(captures),groups[i]-1); - if (jv_get_kind(cap) == JV_KIND_OBJECT) { - cap = jv_object_set(cap, jv_string("name"), jv_string_sized((const char*)name, name_end-name)); - captures = jv_array_set(captures,groups[i]-1,cap); - } else { - jv_free(cap); - } - } - *(jv *)arg = captures; - return 0; -} - -static jv f_match(jq_state *jq, jv input, jv regex, jv modifiers, jv testmode) { - int test = jv_equal(testmode, jv_true()); - jv result; - int onigret; - int global = 0; - regex_t *reg; - OnigErrorInfo einfo; - OnigRegion* region; - - if (jv_get_kind(input) != JV_KIND_STRING) { - jv_free(regex); - jv_free(modifiers); - return type_error(input, "cannot be matched, as it is not a string"); - } - - if (jv_get_kind(regex) != JV_KIND_STRING) { - jv_free(input); - jv_free(modifiers); - return type_error(regex, "is not a string"); - } - - OnigOptionType options = ONIG_OPTION_CAPTURE_GROUP; - - if (jv_get_kind(modifiers) == JV_KIND_STRING) { - jv modarray = jv_string_explode(jv_copy(modifiers)); - jv_array_foreach(modarray, i, mod) { - switch ((int)jv_number_value(mod)) { - case 'g': - global = 1; - break; - case 'i': - options |= ONIG_OPTION_IGNORECASE; - break; - case 'x': - options |= ONIG_OPTION_EXTEND; - break; - case 'm': - options |= ONIG_OPTION_MULTILINE; - break; - case 's': - options |= ONIG_OPTION_SINGLELINE; - break; - case 'p': - options |= ONIG_OPTION_MULTILINE | ONIG_OPTION_SINGLELINE; - break; - case 'l': - options |= ONIG_OPTION_FIND_LONGEST; - break; - case 'n': - options |= ONIG_OPTION_FIND_NOT_EMPTY; - break; - default: - jv_free(input); - jv_free(regex); - jv_free(modarray); - return jv_invalid_with_msg(jv_string_concat(modifiers, - jv_string(" is not a valid modifier string"))); - } - } - jv_free(modarray); - } else if (jv_get_kind(modifiers) != JV_KIND_NULL) { - // If it isn't a string or null, then it is the wrong type... - jv_free(input); - jv_free(regex); - return type_error(modifiers, "is not a string"); - } - - jv_free(modifiers); - - onigret = onig_new(®, (const UChar*)jv_string_value(regex), - (const UChar*)(jv_string_value(regex) + jv_string_length_bytes(jv_copy(regex))), - options, ONIG_ENCODING_UTF8, ONIG_SYNTAX_PERL_NG, &einfo); - if (onigret != ONIG_NORMAL) { - UChar ebuf[ONIG_MAX_ERROR_MESSAGE_LEN]; - onig_error_code_to_str(ebuf, onigret, &einfo); - jv_free(input); - jv_free(regex); - return jv_invalid_with_msg(jv_string_concat(jv_string("Regex failure: "), - jv_string((char*)ebuf))); - } - result = test ? jv_false() : jv_array(); - const char *input_string = jv_string_value(input); - const UChar* start = (const UChar*)jv_string_value(input); - const unsigned long length = jv_string_length_bytes(jv_copy(input)); - const UChar* end = start + length; - region = onig_region_new(); - do { - onigret = onig_search(reg, - (const UChar*)jv_string_value(input), end, /* string boundaries */ - start, end, /* search boundaries */ - region, ONIG_OPTION_NONE); - if (onigret >= 0) { - if (test) { - result = jv_true(); - break; - } - - // Zero-width match - if (region->end[0] == region->beg[0]) { - unsigned long idx; - const char *fr = (const char*)input_string; - for (idx = 0; fr != input_string+region->beg[0]; idx++) { - fr += jvp_utf8_decode_length(*fr); - } - jv match = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx)); - match = jv_object_set(match, jv_string("length"), jv_number(0)); - match = jv_object_set(match, jv_string("string"), jv_string("")); - match = jv_object_set(match, jv_string("captures"), jv_array()); - result = jv_array_append(result, match); - start += 1; - continue; - } - - unsigned long idx; - unsigned long len; - const char *fr = (const char*)input_string; - - for (idx = len = 0; fr < input_string+region->end[0]; len++) { - if (fr == input_string+region->beg[0]) idx = len, len=0; - fr += jvp_utf8_decode_length(*fr); - } - - jv match = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx)); - - unsigned long blen = region->end[0]-region->beg[0]; - match = jv_object_set(match, jv_string("length"), jv_number(len)); - match = jv_object_set(match, jv_string("string"), jv_string_sized(input_string+region->beg[0],blen)); - jv captures = jv_array(); - for (int i = 1; i < region->num_regs; ++i) { - // Empty capture. - if (region->beg[i] == region->end[i]) { - // Didn't match. - jv cap; - if (region->beg[i] == -1) { - cap = jv_object_set(jv_object(), jv_string("offset"), jv_number(-1)); - cap = jv_object_set(cap, jv_string("string"), jv_null()); - } else { - fr = input_string; - for (idx = 0; fr != input_string+region->beg[i]; idx++) { - fr += jvp_utf8_decode_length(*fr); - } - cap = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx)); - cap = jv_object_set(cap, jv_string("string"), jv_string("")); - } - cap = jv_object_set(cap, jv_string("length"), jv_number(0)); - cap = jv_object_set(cap, jv_string("name"), jv_null()); - captures = jv_array_append(captures, cap); - continue; - } - fr = input_string; - for (idx = len = 0; fr != input_string+region->end[i]; len++) { - if (fr == input_string+region->beg[i]) idx = len, len=0; - fr += jvp_utf8_decode_length(*fr); - } - - blen = region->end[i]-region->beg[i]; - jv cap = jv_object_set(jv_object(), jv_string("offset"), jv_number(idx)); - cap = jv_object_set(cap, jv_string("length"), jv_number(len)); - cap = jv_object_set(cap, jv_string("string"), jv_string_sized(input_string+region->beg[i],blen)); - cap = jv_object_set(cap, jv_string("name"), jv_null()); - captures = jv_array_append(captures,cap); - } - onig_foreach_name(reg,f_match_name_iter,&captures); - match = jv_object_set(match, jv_string("captures"), captures); - result = jv_array_append(result, match); - start = (const UChar*)(input_string+region->end[0]); - onig_region_free(region,0); - } else if (onigret == ONIG_MISMATCH) { - break; - } else { /* Error */ - UChar ebuf[ONIG_MAX_ERROR_MESSAGE_LEN]; - onig_error_code_to_str(ebuf, onigret, einfo); - jv_free(result); - result = jv_invalid_with_msg(jv_string_concat(jv_string("Regex failure: "), - jv_string((char*)ebuf))); - break; - } - } while (global && start != end); - onig_region_free(region,1); - region = NULL; - if (region) - onig_region_free(region,1); - onig_free(reg); - jv_free(input); - jv_free(regex); - return result; -} -#else /* ! HAVE_ONIGURUMA */ -static jv f_match(jq_state *jq, jv input, jv regex, jv modifiers, jv testmode) { - return jv_invalid_with_msg(jv_string("jq was compiled without ONIGURUMA regex libary. match/test/sub and related functions are not available.")); -} -#endif /* HAVE_ONIGURUMA */ - -static jv minmax_by(jv values, jv keys, int is_min) { - if (jv_get_kind(values) != JV_KIND_ARRAY) - return type_error2(values, keys, "cannot be iterated over"); - if (jv_get_kind(keys) != JV_KIND_ARRAY) - return type_error2(values, keys, "cannot be iterated over"); - if (jv_array_length(jv_copy(values)) != jv_array_length(jv_copy(keys))) - return type_error2(values, keys, "have wrong length"); - - if (jv_array_length(jv_copy(values)) == 0) { - jv_free(values); - jv_free(keys); - return jv_null(); - } - jv ret = jv_array_get(jv_copy(values), 0); - jv retkey = jv_array_get(jv_copy(keys), 0); - for (int i=1; itm_year, a, 0); - tm->tm_year -= 1900; - TO_TM_FIELD(tm->tm_mon, a, 1); - TO_TM_FIELD(tm->tm_mday, a, 2); - TO_TM_FIELD(tm->tm_hour, a, 3); - TO_TM_FIELD(tm->tm_min, a, 4); - TO_TM_FIELD(tm->tm_sec, a, 5); - TO_TM_FIELD(tm->tm_wday, a, 6); - TO_TM_FIELD(tm->tm_yday, a, 7); - jv_free(a); - - // We use UTC everywhere (gettimeofday, gmtime) and UTC does not do DST. - // Setting tm_isdst to 0 is done by the memset. - // tm->tm_isdst = 0; - - // The standard permits the tm structure to contain additional members. We - // hope it is okay to initialize them to zero, because the standard does not - // provide an alternative. - - return 1; -} - -#undef TO_TM_FIELD - -static jv f_mktime(jq_state *jq, jv a) { - if (jv_get_kind(a) != JV_KIND_ARRAY) - return jv_invalid_with_msg(jv_string("mktime requires array inputs")); - if (jv_array_length(jv_copy(a)) < 6) - return jv_invalid_with_msg(jv_string("mktime requires parsed datetime inputs")); - struct tm tm; - if (!jv2tm(a, &tm)) - return jv_invalid_with_msg(jv_string("mktime requires parsed datetime inputs")); - time_t t = my_mktime(&tm); - if (t == (time_t)-1) - return jv_invalid_with_msg(jv_string("invalid gmtime representation")); - if (t == (time_t)-2) - return jv_invalid_with_msg(jv_string("mktime not supported on this platform")); - return jv_number(t); -} - -#ifdef HAVE_GMTIME_R -static jv f_gmtime(jq_state *jq, jv a) { - if (jv_get_kind(a) != JV_KIND_NUMBER) - return jv_invalid_with_msg(jv_string("gmtime() requires numeric inputs")); - struct tm tm, *tmp; - memset(&tm, 0, sizeof(tm)); - double fsecs = jv_number_value(a); - time_t secs = fsecs; - jv_free(a); - tmp = gmtime_r(&secs, &tm); - if (tmp == NULL) - return jv_invalid_with_msg(jv_string("errror converting number of seconds since epoch to datetime")); - a = tm2jv(tmp); - return jv_array_set(a, 5, jv_number(jv_number_value(jv_array_get(jv_copy(a), 5)) + (fsecs - floor(fsecs)))); -} -#elif defined HAVE_GMTIME -static jv f_gmtime(jq_state *jq, jv a) { - if (jv_get_kind(a) != JV_KIND_NUMBER) - return jv_invalid_with_msg(jv_string("gmtime requires numeric inputs")); - struct tm tm, *tmp; - memset(&tm, 0, sizeof(tm)); - double fsecs = jv_number_value(a); - time_t secs = fsecs; - jv_free(a); - tmp = gmtime(&secs); - if (tmp == NULL) - return jv_invalid_with_msg(jv_string("errror converting number of seconds since epoch to datetime")); - a = tm2jv(tmp); - return jv_array_set(a, 5, jv_number(jv_number_value(jv_array_get(jv_copy(a), 5)) + (fsecs - floor(fsecs)))); -} -#else -static jv f_gmtime(jq_state *jq, jv a) { - jv_free(a); - return jv_invalid_with_msg(jv_string("gmtime not implemented on this platform")); -} -#endif - -#ifdef HAVE_STRFTIME -static jv f_strftime(jq_state *jq, jv a, jv b) { - if (jv_get_kind(a) == JV_KIND_NUMBER) { - a = f_gmtime(jq, a); - } else if (jv_get_kind(a) != JV_KIND_ARRAY) { - return jv_invalid_with_msg(jv_string("strftime/1 requires parsed datetime inputs")); - } - struct tm tm; - if (!jv2tm(a, &tm)) - return jv_invalid_with_msg(jv_string("strftime/1 requires parsed datetime inputs")); \ - const char *fmt = jv_string_value(b); - size_t alloced = strlen(fmt) + 100; - char *buf = alloca(alloced); - size_t n = strftime(buf, alloced, fmt, &tm); - jv_free(b); - /* POSIX doesn't provide errno values for strftime() failures; weird */ - if (n == 0 || n > alloced) - return jv_invalid_with_msg(jv_string("strftime/1: unknown system failure")); - return jv_string(buf); -} -#else -static jv f_strftime(jq_state *jq, jv a) { - jv_free(a); - jv_free(b); - return jv_invalid_with_msg(jv_string("strftime/1 not implemented on this platform")); -} -#endif - -#ifdef HAVE_GETTIMEOFDAY -static jv f_now(jq_state *jq, jv a) { - jv_free(a); - struct timeval tv; - if (gettimeofday(&tv, NULL) == -1) - return jv_number(time(NULL)); - return jv_number(tv.tv_sec + tv.tv_usec / 1000000.0); -} -#else -static jv f_now(jq_state *jq, jv a) { - jv_free(a); - return jv_number(time(NULL)); -} -#endif - -static jv f_current_filename(jq_state *jq, jv a) { - jv_free(a); - - jv r = jq_util_input_get_current_filename(jq); - if (jv_is_valid(r)) - return r; - jv_free(r); - return jv_null(); -} -static jv f_current_line(jq_state *jq, jv a) { - jv_free(a); - return jq_util_input_get_current_line(jq); -} - -#define LIBM_DD(name) \ - {(cfunction_ptr)f_ ## name, "_" #name, 1}, -#define LIBM_DD_NO(name) - -#define LIBM_DDD(name) \ - {(cfunction_ptr)f_ ## name, "_" #name, 3}, -#define LIBM_DDD_NO(name) - -#define LIBM_DDDD(name) \ - {(cfunction_ptr)f_ ## name, "_" #name, 4}, -#define LIBM_DDDD_NO(name) - -static const struct cfunction function_list[] = { -#include "libm.h" - {(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", 2}, - {(cfunction_ptr)f_format, "format", 2}, - {(cfunction_ptr)f_env, "env", 1}, - {(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_mktime, "mktime", 1}, - {(cfunction_ptr)f_gmtime, "gmtime", 1}, - {(cfunction_ptr)f_now, "now", 1}, - {(cfunction_ptr)f_current_filename, "input_filename", 1}, - {(cfunction_ptr)f_current_line, "input_line_number", 1}, -}; -#undef LIBM_DDDD_NO -#undef LIBM_DDD_NO -#undef LIBM_DD_NO -#undef LIBM_DDDD -#undef LIBM_DDD -#undef LIBM_DD - -struct bytecoded_builtin { const char* name; block code; }; -static block bind_bytecoded_builtins(block b) { - block builtins = gen_noop(); - { - struct bytecoded_builtin builtin_defs[] = { - {"empty", gen_op_simple(BACKTRACK)}, - {"not", gen_condbranch(gen_const(jv_false()), - gen_const(jv_true()))} - }; - for (unsigned i=0; i", code, strlen(code)); - block funcs; - int nerrors = jq_parse_library(src, &funcs); - if (nerrors == 0) { - *bb = block_bind_referenced(funcs, *bb, OP_IS_CALL_PSEUDO); - } - locfile_free(src); - return nerrors; -} - -static int slurp_lib(jq_state *jq, block* bb) { - int nerrors = 0; - char* home = getenv("HOME"); - if (home) { // silently ignore no $HOME - jv filename = jv_string_append_str(jv_string(home), "/.jq"); - jv data = jv_load_file(jv_string_value(filename), 1); - if (jv_is_valid(data)) { - nerrors = builtins_bind_one(jq, bb, jv_string_value(data) ); - } - jv_free(filename); - jv_free(data); - } - return nerrors; -} - -int builtins_bind(jq_state *jq, block* bb) { - int nerrors = slurp_lib(jq, bb); - if (nerrors) { - block_free(*bb); - return nerrors; - } - nerrors = builtins_bind_one(jq, bb, jq_builtins); - assert(!nerrors); - *bb = bind_bytecoded_builtins(*bb); - *bb = gen_cbinding(function_list, sizeof(function_list)/sizeof(function_list[0]), *bb); - return nerrors; -} diff --git a/src/jq/builtin.h b/src/jq/builtin.h deleted file mode 100644 index bca9bae..0000000 --- a/src/jq/builtin.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef BUILTIN_H -#define BUILTIN_H - -#include "jq.h" -#include "bytecode.h" -#include "compile.h" - -int builtins_bind(jq_state *, block*); - -#endif diff --git a/src/jq/builtin.inc b/src/jq/builtin.inc deleted file mode 100644 index dee49ef..0000000 --- a/src/jq/builtin.inc +++ /dev/null @@ -1,306 +0,0 @@ -"def error: error(.);\n" -"def map(f): [.[] | f];\n" -"def select(f): if f then . else empty end;\n" -"def sort_by(f): _sort_by_impl(map([f]));\n" -"def group_by(f): _group_by_impl(map([f]));\n" -"def unique: group_by(.) | map(.[0]);\n" -"def unique_by(f): group_by(f) | map(.[0]);\n" -"def max_by(f): _max_by_impl(map([f]));\n" -"def min_by(f): _min_by_impl(map([f]));\n" -"def add: reduce .[] as $x (null; . + $x);\n" -"def del(f): delpaths([path(f)]);\n" -"def _assign(paths; value): value as $v | reduce path(paths) as $p (.; setpath($p; $v));\n" -"def _modify(paths; update): reduce path(paths) as $p (.; label $out | (setpath($p; getpath($p) | update) | ., break $out), delpaths([$p]));\n" -"def map_values(f): .[] |= f;\n" -"\n" -"# recurse\n" -"def recurse(f): def r: ., (f | r); r;\n" -"def recurse(f; cond): def r: ., (f | select(cond) | r); r;\n" -"def recurse: recurse(.[]?);\n" -"def recurse_down: recurse;\n" -"\n" -"def to_entries: [keys_unsorted[] as $k | {key: $k, value: .[$k]}];\n" -"def from_entries: map({(.key // .Key // .name // .Name): (if has(\"value\") then .value else .Value end)}) | add | .//={};\n" -"def with_entries(f): to_entries | map(f) | from_entries;\n" -"def reverse: [.[length - 1 - range(0;length)]];\n" -"def indices($i): if type == \"array\" and ($i|type) == \"array\" then .[$i]\n" -" elif type == \"array\" then .[[$i]]\n" -" elif type == \"string\" and ($i|type) == \"string\" then _strindices($i)\n" -" else .[$i] end;\n" -"def index($i): indices($i) | .[0]; # TODO: optimize\n" -"def rindex($i): indices($i) | .[-1:][0]; # TODO: optimize\n" -"def paths: path(recurse(if (type|. == \"array\" or . == \"object\") then .[] else empty end))|select(length > 0);\n" -"def paths(node_filter): . as $dot|paths|select(. as $p|$dot|getpath($p)|node_filter);\n" -"def any(generator; condition):\n" -" [label $out | foreach generator as $i\n" -" (false;\n" -" if . then break $out elif $i | condition then true else . end;\n" -" if . then . else empty end)] | length == 1;\n" -"def any(condition): any(.[]; condition);\n" -"def any: any(.);\n" -"def all(generator; condition):\n" -" [label $out | foreach generator as $i\n" -" (true;\n" -" if .|not then break $out elif $i | condition then . else false end;\n" -" if .|not then . else empty end)] | length == 0;\n" -"def all(condition): all(.[]; condition);\n" -"def all: all(.);\n" -"def isfinite: type == \"number\" and (isinfinite | not);\n" -"def arrays: select(type == \"array\");\n" -"def objects: select(type == \"object\");\n" -"def iterables: arrays, objects;\n" -"def booleans: select(type == \"boolean\");\n" -"def numbers: select(type == \"number\");\n" -"def normals: select(isnormal);\n" -"def finites: select(isfinite);\n" -"def strings: select(type == \"string\");\n" -"def nulls: select(type == \"null\");\n" -"def values: select(. != null);\n" -"def scalars: select(. == null or . == true or . == false or type == \"number\" or type == \"string\");\n" -"def scalars_or_empty: select(. == null or . == true or . == false or type == \"number\" or type == \"string\" or ((type==\"array\" or type==\"object\") and length==0));\n" -"def leaf_paths: paths(scalars);\n" -"def join($x): reduce .[] as $i (null;\n" -" (if .==null then \"\" else .+$x end) +\n" -" ($i | if type==\"boolean\" or type==\"number\" then tostring else .//\"\" end)\n" -" ) // \"\";\n" -"def _flatten($x): reduce .[] as $i ([]; if $i | type == \"array\" and $x != 0 then . + ($i | _flatten($x-1)) else . + [$i] end);\n" -"def flatten($x): if $x < 0 then error(\"flatten depth must not be negative\") else _flatten($x) end;\n" -"def flatten: _flatten(-1);\n" -"def range($x): range(0;$x);\n" -"def fromdateiso8601: strptime(\"%Y-%m-%dT%H:%M:%SZ\")|mktime;\n" -"def todateiso8601: strftime(\"%Y-%m-%dT%H:%M:%SZ\");\n" -"def fromdate: fromdateiso8601;\n" -"def todate: todateiso8601;\n" -"def match(re; mode): _match_impl(re; mode; false)|.[];\n" -"def match($val): ($val|type) as $vt | if $vt == \"string\" then match($val; null)\n" -" elif $vt == \"array\" and ($val | length) > 1 then match($val[0]; $val[1])\n" -" elif $vt == \"array\" and ($val | length) > 0 then match($val[0]; null)\n" -" else error( $vt + \" not a string or array\") end;\n" -"def test(re; mode): _match_impl(re; mode; true);\n" -"def test($val): ($val|type) as $vt | if $vt == \"string\" then test($val; null)\n" -" elif $vt == \"array\" and ($val | length) > 1 then test($val[0]; $val[1])\n" -" elif $vt == \"array\" and ($val | length) > 0 then test($val[0]; null)\n" -" else error( $vt + \" not a string or array\") end;\n" -"def capture(re; mods): match(re; mods) | reduce ( .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair ({}; . + $pair);\n" -"def capture($val): ($val|type) as $vt | if $vt == \"string\" then capture($val; null)\n" -" elif $vt == \"array\" and ($val | length) > 1 then capture($val[0]; $val[1])\n" -" elif $vt == \"array\" and ($val | length) > 0 then capture($val[0]; null)\n" -" else error( $vt + \" not a string or array\") end;\n" -"def scan(re):\n" -" match(re; \"g\")\n" -" | if (.captures|length > 0)\n" -" then [ .captures | .[] | .string ]\n" -" else .string\n" -" end ;\n" -"#\n" -"# If input is an array, then emit a stream of successive subarrays of length n (or less),\n" -"# and similarly for strings.\n" -"def _nwise(a; $n): if a|length <= $n then a else a[0:$n] , _nwise(a[$n:]; $n) end;\n" -"def _nwise($n): _nwise(.; $n);\n" -"#\n" -"# splits/1 produces a stream; split/1 is retained for backward compatibility.\n" -"def splits($re; flags): . as $s\n" -"# # multiple occurrences of \"g\" are acceptable\n" -" | [ match($re; \"g\" + flags) | (.offset, .offset + .length) ]\n" -" | [0] + . +[$s|length]\n" -" | _nwise(2)\n" -" | $s[.[0]:.[1] ] ;\n" -"def splits($re): splits($re; null);\n" -"#\n" -"# split emits an array for backward compatibility\n" -"def split($re; flags): [ splits($re; flags) ];\n" -"#\n" -"# If s contains capture variables, then create a capture object and pipe it to s\n" -"def sub($re; s):\n" -" . as $in\n" -" | [match($re)]\n" -" | if length == 0 then $in\n" -" else .[0]\n" -" | . as $r\n" -"# # create the \"capture\" object:\n" -" | reduce ( $r | .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair\n" -" ({}; . + $pair)\n" -" | $in[0:$r.offset] + s + $in[$r.offset+$r.length:]\n" -" end ;\n" -"#\n" -"# If s contains capture variables, then create a capture object and pipe it to s\n" -"def sub($re; s; flags):\n" -" def subg: [explode[] | select(. != 103)] | implode;\n" -" # \"fla\" should be flags with all occurrences of g removed; gs should be non-nil if flags has a g\n" -" def sub1(fla; gs):\n" -" def mysub:\n" -" . as $in\n" -" | [match($re; fla)]\n" -" | if length == 0 then $in\n" -" else .[0] as $edit\n" -" | ($edit | .offset + .length) as $len\n" -" # create the \"capture\" object:\n" -" | reduce ( $edit | .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair\n" -" ({}; . + $pair)\n" -" | $in[0:$edit.offset]\n" -" + s\n" -" + ($in[$len:] | if length > 0 and gs then mysub else . end)\n" -" end ;\n" -" mysub ;\n" -" (flags | index(\"g\")) as $gs\n" -" | (flags | if $gs then subg else . end) as $fla\n" -" | sub1($fla; $gs);\n" -"#\n" -"def sub($re; s): sub($re; s; \"\");\n" -"# repeated substitution of re (which may contain named captures)\n" -"def gsub($re; s; flags): sub($re; s; flags + \"g\");\n" -"def gsub($re; s): sub($re; s; \"g\");\n" -"\n" -"########################################################################\n" -"# range/3, with a `by` expression argument\n" -"def range($init; $upto; $by):\n" -" def _range:\n" -" if ($by > 0 and . < $upto) or ($by < 0 and . > $upto) then ., ((.+$by)|_range) else . end;\n" -" if $by == 0 then $init else $init|_range end | select(($by > 0 and . < $upto) or ($by < 0 and . > $upto));\n" -"# generic iterator/generator\n" -"def while(cond; update):\n" -" def _while:\n" -" if cond then ., (update | _while) else empty end;\n" -" _while;\n" -"def until(cond; next):\n" -" def _until:\n" -" if cond then . else (next|_until) end;\n" -" _until;\n" -"def limit($n; exp): if $n < 0 then exp else label $out | foreach exp as $item ([$n, null]; if .[0] < 1 then break $out else [.[0] -1, $item] end; .[1]) end;\n" -"def first(g): label $out | g | ., break $out;\n" -"def last(g): reduce g as $item (null; $item);\n" -"def nth($n; g): if $n < 0 then error(\"nth doesn't support negative indices\") else last(limit($n + 1; g)) end;\n" -"def first: .[0];\n" -"def last: .[-1];\n" -"def nth($n): .[$n];\n" -"def combinations:\n" -" if length == 0 then [] else\n" -" .[0][] as $x\n" -" | (.[1:] | combinations) as $y\n" -" | [$x] + $y\n" -" end;\n" -"def combinations(n):\n" -" . as $dot\n" -" | [range(n) | $dot]\n" -" | combinations;\n" -"# transpose a possibly jagged matrix, quickly;\n" -"# rows are padded with nulls so the result is always rectangular.\n" -"def transpose:\n" -" if . == [] then []\n" -" else . as $in\n" -" | (map(length) | max) as $max\n" -" | length as $length\n" -" | reduce range(0; $max) as $j\n" -" ([]; . + [reduce range(0;$length) as $i ([]; . + [ $in[$i][$j] ] )] )\n" -" end;\n" -"def in(xs): . as $x | xs | has($x);\n" -"def inside(xs): . as $x | xs | contains($x);\n" -"def input: _input;\n" -"def repeat(exp):\n" -" def _repeat:\n" -" exp, _repeat;\n" -" _repeat;\n" -"def inputs: try repeat(_input) catch if .==\"break\" then empty else .|error end;\n" -"# like ruby's downcase - only characters A to Z are affected\n" -"def ascii_downcase:\n" -" explode | map( if 65 <= . and . <= 90 then . + 32 else . end) | implode;\n" -"# like ruby's upcase - only characters a to z are affected\n" -"def ascii_upcase:\n" -" explode | map( if 97 <= . and . <= 122 then . - 32 else . end) | implode;\n" -"\n" -"# Streaming utilities\n" -"def truncate_stream(stream):\n" -" . as $n | null | stream | . as $input | if (.[0]|length) > $n then setpath([0];$input[0][1:]) else empty end;\n" -"def fromstream(i):\n" -" foreach i as $item (\n" -" [null,false,null,false];\n" -" if ($item[0]|length) == 0 then [null,false,.[2],.[3]]\n" -" elif ($item|length) == 1 and ($item[0]|length) < 2 then [null,false,.[0],.[1]]\n" -" else . end |\n" -" . as $state |\n" -" if ($item|length) > 1 and ($item[0]|length) > 0 then\n" -" [.[0]|setpath(($item|.[0]); ($item|.[1])),\n" -" true,\n" -" $state[2],\n" -" $state[3]]\n" -" else .\n" -" end;\n" -" if ($item[0]|length) == 1 and ($item|length == 1) and .[3] then .[2] else empty end,\n" -" if ($item[0]|length) == 0 then $item[1] else empty end\n" -" );\n" -"def tostream:\n" -" {string:true,number:true,boolean:true,null:true} as $leaf_types |\n" -" . as $dot |\n" -" if $leaf_types[$dot|type] or length==0 then [[],$dot]\n" -" else\n" -" # We really need a _streaming_ form of `keys`.\n" -" # We can use `range` for arrays, but not for objects.\n" -" keys as $keys |\n" -" $keys[-1] as $last|\n" -" ((# for each key\n" -" $keys[] | . as $key |\n" -" $dot[$key] | . as $dot |\n" -" # recurse on each key/value\n" -" tostream|.[0]|=[$key]+.),\n" -" # then add the closing marker\n" -" [[$last]])\n" -" end;\n" -"\n" -"\n" -"# Assuming the input array is sorted, bsearch/1 returns\n" -"# the index of the target if the target is in the input array; and otherwise\n" -"# (-1 - ix), where ix is the insertion point that would leave the array sorted.\n" -"# If the input is not sorted, bsearch will terminate but with irrelevant results.\n" -"def bsearch(target):\n" -" if length == 0 then -1\n" -" elif length == 1 then\n" -" if target == .[0] then 0 elif target < .[0] then -1 else -2 end\n" -" else . as $in\n" -" # state variable: [start, end, answer]\n" -" # where start and end are the upper and lower offsets to use.\n" -" | [0, length-1, null]\n" -" | until( .[0] > .[1] ;\n" -" if .[2] != null then (.[1] = -1) # i.e. break\n" -" else\n" -" ( ( (.[1] + .[0]) / 2 ) | floor ) as $mid\n" -" | $in[$mid] as $monkey\n" -" | if $monkey == target then (.[2] = $mid) # success\n" -" elif .[0] == .[1] then (.[1] = -1) # failure\n" -" elif $monkey < target then (.[0] = ($mid + 1))\n" -" else (.[1] = ($mid - 1))\n" -" end\n" -" end )\n" -" | if .[2] == null then # compute the insertion point\n" -" if $in[ .[0] ] < target then (-2 -.[0])\n" -" else (-1 -.[0])\n" -" end\n" -" else .[2]\n" -" end\n" -" end;\n" -"\n" -"# Apply f to composite entities recursively, and to atoms\n" -"def walk(f):\n" -" . as $in\n" -" | if type == \"object\" then\n" -" reduce keys[] as $key\n" -" ( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f\n" -" elif type == \"array\" then map( walk(f) ) | f\n" -" else f\n" -" end;\n" -"\n" -"# SQL-ish operators here:\n" -"def INDEX(stream; idx_expr):\n" -" reduce stream as $row ({};\n" -" .[$row|idx_expr|\n" -" if type != \"string\" then tojson\n" -" else .\n" -" end] |= $row);\n" -"def INDEX(idx_expr): INDEX(.[]; idx_expr);\n" -"def JOIN($idx; idx_expr):\n" -" [.[] | [., $idx[idx_expr]]];\n" -"def JOIN($idx; stream; idx_expr):\n" -" stream | [., $idx[idx_expr]];\n" -"def JOIN($idx; stream; idx_expr; join_expr):\n" -" stream | [., $idx[idx_expr]] | join_expr;\n" -"def IN(s): reduce (first(select(. == s)) | true) as $v (false; if . or $v then true else false end);\n" -"def IN(src; s): reduce (src|IN(s)) as $v (false; if . or $v then true else false end);\n" diff --git a/src/jq/bytecode.c b/src/jq/bytecode.c deleted file mode 100644 index 0ef154b..0000000 --- a/src/jq/bytecode.c +++ /dev/null @@ -1,161 +0,0 @@ -#include -#include -#include - -#include "bytecode.h" -#include "jv_alloc.h" - -// flags, length -#define NONE 0, 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 -#define BRANCH OP_HAS_BRANCH, 2 -#define CFUNC (OP_HAS_CFUNC | OP_HAS_BINDING), 3 -#define UFUNC (OP_HAS_UFUNC | OP_HAS_BINDING | OP_IS_CALL_PSEUDO), 4 -#define DEFINITION (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 -#define CLOSURE_REF_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2 - -#define OP(name, imm, in, out) \ - {name, #name, imm, in, out}, - -static const struct opcode_description opcode_descriptions[] = { -#include "opcode_list.h" -}; - -static const struct opcode_description invalid_opcode_description = { - -1, "#INVALID", 0, 0, 0, 0 -}; - - -const struct opcode_description* opcode_describe(opcode op) { - if ((int)op >= 0 && (int)op < NUM_OPCODES) { - return &opcode_descriptions[op]; - } else { - return &invalid_opcode_description; - } -} - - -int bytecode_operation_length(uint16_t* codeptr) { - int length = opcode_describe(*codeptr)->length; - if (*codeptr == CALL_JQ || *codeptr == TAIL_CALL_JQ) { - length += codeptr[1] * 2; - } - return length; -} - -static void dump_code(int indent, struct bytecode* bc) { - int pc = 0; - while (pc < bc->codelen) { - printf("%*s", indent, ""); - dump_operation(bc, bc->code + pc); - printf("\n"); - pc += bytecode_operation_length(bc->code + pc); - } -} - -static void symbol_table_free(struct symbol_table* syms) { - jv_mem_free(syms->cfunctions); - jv_free(syms->cfunc_names); - jv_mem_free(syms); -} - -void dump_disassembly(int indent, struct bytecode* bc) { - if (bc->nclosures > 0) { - printf("%*s[params: ", indent, ""); - jv params = jv_object_get(jv_copy(bc->debuginfo), jv_string("params")); - for (int i=0; inclosures; i++) { - if (i) printf(", "); - jv name = jv_array_get(jv_copy(params), i); - printf("%s", jv_string_value(name)); - jv_free(name); - } - jv_free(params); - printf("]\n"); - } - dump_code(indent, bc); - for (int i=0; insubfunctions; i++) { - struct bytecode* subfn = bc->subfunctions[i]; - jv name = jv_object_get(jv_copy(subfn->debuginfo), jv_string("name")); - printf("%*s%s:%d:\n", indent, "", jv_string_value(name), i); - jv_free(name); - dump_disassembly(indent+2, subfn); - } -} - -static struct bytecode* getlevel(struct bytecode* bc, int level) { - while (level > 0) { - bc = bc->parent; - level--; - } - return bc; -} - -void dump_operation(struct bytecode* bc, uint16_t* codeptr) { - int pc = codeptr - bc->code; - printf("%04d ", pc); - const struct opcode_description* op = opcode_describe(bc->code[pc++]); - printf("%s", op->name); - if (op->length > 1) { - uint16_t imm = bc->code[pc++]; - if (op->op == CALL_JQ || op->op == TAIL_CALL_JQ) { - for (int i=0; icode[pc++]; - uint16_t idx = bc->code[pc++]; - jv name; - if (idx & ARG_NEWCLOSURE) { - idx &= ~ARG_NEWCLOSURE; - name = jv_object_get(jv_copy(getlevel(bc,level)->subfunctions[idx]->debuginfo), - jv_string("name")); - } else { - name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,level)->debuginfo), - jv_string("params")), idx); - } - printf(" %s:%d", - jv_string_value(name), - idx); - jv_free(name); - if (level) { - printf("^%d", level); - } - } - } else if (op->op == CALL_BUILTIN) { - int func = bc->code[pc++]; - jv name = jv_array_get(jv_copy(bc->globals->cfunc_names), func); - printf(" %s", jv_string_value(name)); - jv_free(name); - } else if (op->flags & OP_HAS_BRANCH) { - printf(" %04d", pc + imm); - } else if (op->flags & OP_HAS_CONSTANT) { - printf(" "); - jv_dump(jv_array_get(jv_copy(bc->constants), imm), 0); - } else if (op->flags & OP_HAS_VARIABLE) { - uint16_t v = bc->code[pc++]; - jv name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,imm)->debuginfo), jv_string("locals")), v); - printf(" $%s:%d", - jv_string_value(name), - v); - jv_free(name); - if (imm) { - printf("^%d", imm); - } - } else { - printf(" %d", imm); - } - } -} - -void bytecode_free(struct bytecode* bc) { - if (!bc) - return; - jv_mem_free(bc->code); - jv_free(bc->constants); - for (int i=0; insubfunctions; i++) - bytecode_free(bc->subfunctions[i]); - if (!bc->parent) - symbol_table_free(bc->globals); - jv_mem_free(bc->subfunctions); - jv_free(bc->debuginfo); - jv_mem_free(bc); -} diff --git a/src/jq/bytecode.h b/src/jq/bytecode.h deleted file mode 100644 index 6cb49f7..0000000 --- a/src/jq/bytecode.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef BYTECODE_H -#define BYTECODE_H -#include - -#include "jv.h" - -typedef enum { -#define OP(name, imm, in, out) name, -#include "opcode_list.h" -#undef OP -} opcode; - -enum { - NUM_OPCODES = -#define OP(name, imm, in, out) +1 -#include "opcode_list.h" -#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, - // NOTE: Not actually part of any op -- a pseudo-op flag for special - // handling of `break`. - OP_BIND_WILDCARD = 2048, -}; -struct opcode_description { - opcode op; - const char* name; - - int flags; - - // length in 16-bit units - int length; - - int stack_in, stack_out; -}; - -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; - jv cfunc_names; -}; - -// The bytecode format matters in: -// execute.c - interpreter -// compile.c - compiler -// bytecode.c - disassembler - -#define ARG_NEWCLOSURE 0x1000 - -struct bytecode { - uint16_t* code; - int codelen; - - int nlocals; - int nclosures; - - jv constants; // JSON array of constants - struct symbol_table* globals; - - struct bytecode** subfunctions; - int nsubfunctions; - - struct bytecode* parent; - - jv debuginfo; -}; - -void dump_disassembly(int, struct bytecode* code); -void dump_operation(struct bytecode* bc, uint16_t* op); - -int bytecode_operation_length(uint16_t* codeptr); -void bytecode_free(struct bytecode* bc); - -#endif diff --git a/src/jq/compile.c b/src/jq/compile.c deleted file mode 100644 index a5c75c9..0000000 --- a/src/jq/compile.c +++ /dev/null @@ -1,1232 +0,0 @@ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE // for strdup -#endif -#include -#include -#include -#include -#include "compile.h" -#include "bytecode.h" -#include "locfile.h" -#include "jv_alloc.h" -#include "linker.h" - -/* - The intermediate representation for jq filters is as a sequence of - struct inst, which form a doubly-linked list via the next and prev - pointers. - - A "block" represents a sequence of "struct inst", which may be - empty. - - Blocks are generated by the parser bottom-up, so may have free - variables (refer to things not defined). See inst.bound_by and - inst.symbol. - */ -struct inst { - struct inst* next; - struct inst* prev; - - opcode op; - - struct { - uint16_t intval; - struct inst* target; - jv constant; - const struct cfunction* cfunc; - } imm; - - struct locfile* locfile; - location source; - - // Binding - // An instruction requiring binding (for parameters/variables/functions) - // is in one of three states: - // inst->bound_by = NULL - Unbound free variable - // inst->bound_by = inst - This instruction binds a variable - // inst->bound_by = other - Uses variable bound by other instruction - // Unbound instructions (references to other things that may or may not - // exist) are created by "gen_foo_unbound", and bindings are created by - // block_bind(definition, body), which binds all instructions in - // body which are unboudn and refer to "definition" by name. - struct inst* bound_by; - char* symbol; - - int nformals; - int nactuals; - - block subfn; // used by CLOSURE_CREATE (body of function) - block arglist; // used by CLOSURE_CREATE (formals) and CALL_JQ (arguments) - - // This instruction is compiled as part of which function? - // (only used during block_compile) - struct bytecode* compiled; - - int bytecode_pos; // position just after this insn -}; - -static inst* inst_new(opcode op) { - inst* i = jv_mem_alloc(sizeof(inst)); - i->next = i->prev = 0; - i->op = op; - i->bytecode_pos = -1; - i->bound_by = 0; - i->symbol = 0; - i->nformals = -1; - i->nactuals = -1; - i->subfn = gen_noop(); - i->arglist = gen_noop(); - i->source = UNKNOWN_LOCATION; - i->locfile = 0; - return i; -} - -static void inst_free(struct inst* i) { - jv_mem_free(i->symbol); - block_free(i->subfn); - block_free(i->arglist); - if (i->locfile) - locfile_free(i->locfile); - if (opcode_describe(i->op)->flags & OP_HAS_CONSTANT) { - jv_free(i->imm.constant); - } - jv_mem_free(i); -} - -static block inst_block(inst* i) { - block b = {i,i}; - return b; -} - -int block_is_single(block b) { - return b.first && b.first == b.last; -} - -static inst* block_take(block* b) { - if (b->first == 0) return 0; - inst* i = b->first; - if (i->next) { - i->next->prev = 0; - b->first = i->next; - i->next = 0; - } else { - b->first = 0; - b->last = 0; - } - return i; -} - -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 && - i->source.end == UNKNOWN_LOCATION.end) { - i->source = loc; - i->locfile = locfile_retain(l); - } - } - return b; -} - -block gen_noop() { - block b = {0,0}; - return b; -} - -int block_is_noop(block b) { - return (b.first == 0 && b.last == 0); -} - -block gen_op_simple(opcode op) { - assert(opcode_describe(op)->length == 1); - return inst_block(inst_new(op)); -} - - -block gen_const(jv constant) { - assert(opcode_describe(LOADK)->flags & OP_HAS_CONSTANT); - inst* i = inst_new(LOADK); - i->imm.constant = constant; - return inst_block(i); -} - -block gen_const_global(jv constant, const char *name) { - assert((opcode_describe(STORE_GLOBAL)->flags & (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING)) == - (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING)); - inst* i = inst_new(STORE_GLOBAL); - i->imm.constant = constant; - i->symbol = strdup(name); - return inst_block(i); -} - -int block_is_const(block b) { - return (block_is_single(b) && b.first->op == LOADK); -} - -int block_is_const_inf(block b) { - return (block_is_single(b) && b.first->op == LOADK && - jv_get_kind(b.first->imm.constant) == JV_KIND_NUMBER && - isinf(jv_number_value(b.first->imm.constant))); -} - -jv_kind block_const_kind(block b) { - assert(block_is_const(b)); - return jv_get_kind(b.first->imm.constant); -} - -jv block_const(block b) { - assert(block_is_const(b)); - return jv_copy(b.first->imm.constant); -} - -block gen_op_target(opcode op, block target) { - assert(opcode_describe(op)->flags & OP_HAS_BRANCH); - assert(target.last); - inst* i = inst_new(op); - i->imm.target = target.last; - return inst_block(i); -} - -block gen_op_targetlater(opcode op) { - assert(opcode_describe(op)->flags & OP_HAS_BRANCH); - inst* i = inst_new(op); - i->imm.target = 0; - return inst_block(i); -} -void inst_set_target(block b, block target) { - assert(block_is_single(b)); - assert(opcode_describe(b.first->op)->flags & OP_HAS_BRANCH); - assert(target.last); - b.first->imm.target = target.last; -} - -block gen_op_unbound(opcode op, const char* name) { - assert(opcode_describe(op)->flags & OP_HAS_BINDING); - inst* i = inst_new(op); - i->symbol = strdup(name); - return inst_block(i); -} - -block gen_op_var_fresh(opcode op, const char* name) { - assert(opcode_describe(op)->flags & OP_HAS_VARIABLE); - return block_bind(gen_op_unbound(op, name), - gen_noop(), OP_HAS_VARIABLE); -} - -block gen_op_bound(opcode op, block binder) { - assert(block_is_single(binder)); - block b = gen_op_unbound(op, binder.first->symbol); - b.first->bound_by = binder.first; - return b; -} - - -static void inst_join(inst* a, inst* b) { - assert(a && b); - assert(!a->next); - assert(!b->prev); - a->next = b; - b->prev = a; -} - -void block_append(block* b, block b2) { - if (b2.first) { - if (b->last) { - inst_join(b->last, b2.first); - } else { - b->first = b2.first; - } - b->last = b2.last; - } -} - -block block_join(block a, block b) { - block c = a; - block_append(&c, b); - return c; -} - -int block_has_only_binders_and_imports(block binders, int bindflags) { - bindflags |= OP_HAS_BINDING; - for (inst* curr = binders.first; curr; curr = curr->next) { - if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != DEPS && curr->op != MODULEMETA) { - return 0; - } - } - return 1; -} - -static int inst_is_binder(inst *i, int bindflags) { - return !((opcode_describe(i->op)->flags & bindflags) != bindflags && i->op != MODULEMETA); -} - -int block_has_only_binders(block binders, int bindflags) { - bindflags |= OP_HAS_BINDING; - bindflags &= ~OP_BIND_WILDCARD; - for (inst* curr = binders.first; curr; curr = curr->next) { - if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != MODULEMETA) { - return 0; - } - } - return 1; -} - -// Count a binder's (function) formal params -static int block_count_formals(block b) { - int args = 0; - if (b.first->op == CLOSURE_CREATE_C) - return b.first->imm.cfunc->nargs - 1; - for (inst* i = b.first->arglist.first; i; i = i->next) { - assert(i->op == CLOSURE_PARAM); - args++; - } - return args; -} - -// Count a call site's actual params -static int block_count_actuals(block b) { - int args = 0; - for (inst* i = b.first; i; i = i->next) { - switch (i->op) { - default: assert(0 && "Unknown function type"); break; - case CLOSURE_CREATE: - case CLOSURE_PARAM: - case CLOSURE_CREATE_C: - args++; - break; - } - } - return args; -} - -static int block_count_refs(block binder, block body) { - int nrefs = 0; - for (inst* i = body.first; i; i = i->next) { - if (i != binder.first && i->bound_by == binder.first) { - nrefs++; - } - // counting recurses into closures - nrefs += block_count_refs(binder, i->subfn); - // counting recurses into argument list - nrefs += block_count_refs(binder, i->arglist); - } - return nrefs; -} - -static int block_bind_subblock(block binder, block body, int bindflags, int break_distance) { - assert(block_is_single(binder)); - assert((opcode_describe(binder.first->op)->flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD)); - assert(binder.first->symbol); - assert(binder.first->bound_by == 0 || binder.first->bound_by == binder.first); - assert(break_distance >= 0); - - binder.first->bound_by = binder.first; - if (binder.first->nformals == -1) - binder.first->nformals = block_count_formals(binder); - int nrefs = 0; - for (inst* i = body.first; i; i = i->next) { - int flags = opcode_describe(i->op)->flags; - if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by == 0 && - (!strcmp(i->symbol, binder.first->symbol) || - // Check for break/break2/break3; see parser.y - ((bindflags & OP_BIND_WILDCARD) && i->symbol[0] == '*' && - break_distance <= 3 && (i->symbol[1] == '1' + break_distance) && - i->symbol[2] == '\0'))) { - // bind this instruction - if (i->op == CALL_JQ && i->nactuals == -1) - i->nactuals = block_count_actuals(i->arglist); - if (i->nactuals == -1 || i->nactuals == binder.first->nformals) { - i->bound_by = binder.first; - nrefs++; - } - } else if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by != 0 && - !strncmp(binder.first->symbol, "*anonlabel", sizeof("*anonlabel") - 1) && - !strncmp(i->symbol, "*anonlabel", sizeof("*anonlabel") - 1)) { - // Increment the break distance required for this binder to match - // a break whenever we come across a STOREV of *anonlabel... - break_distance++; - } - // binding recurses into closures - nrefs += block_bind_subblock(binder, i->subfn, bindflags, break_distance); - // binding recurses into argument list - nrefs += block_bind_subblock(binder, i->arglist, bindflags, break_distance); - } - return nrefs; -} - -static int block_bind_each(block binder, block body, int bindflags) { - assert(block_has_only_binders(binder, bindflags)); - bindflags |= OP_HAS_BINDING; - int nrefs = 0; - for (inst* curr = binder.first; curr; curr = curr->next) { - nrefs += block_bind_subblock(inst_block(curr), body, bindflags, 0); - } - return nrefs; -} - -block block_bind(block binder, block body, int bindflags) { - block_bind_each(binder, body, bindflags); - return block_join(binder, body); -} - -block block_bind_library(block binder, block body, int bindflags, const char *libname) { - bindflags |= OP_HAS_BINDING; - int nrefs = 0; - int matchlen = (libname == NULL) ? 0 : strlen(libname); - char *matchname = jv_mem_alloc(matchlen+2+1); - matchname[0] = '\0'; - if (libname != NULL && libname[0] != '\0') { - strcpy(matchname,libname); - strcpy(matchname+matchlen, "::"); - matchlen += 2; - } - assert(block_has_only_binders(binder, bindflags)); - for (inst *curr = binder.first; curr; curr = curr->next) { - int bindflags2 = bindflags; - char* cname = curr->symbol; - char* tname = jv_mem_alloc(strlen(curr->symbol)+matchlen+1); - strcpy(tname, matchname); - strcpy(tname+matchlen, curr->symbol); - - // Ew - if ((opcode_describe(curr->op)->flags & (OP_HAS_VARIABLE | OP_HAS_CONSTANT))) - bindflags2 = OP_HAS_VARIABLE | OP_HAS_BINDING; - - // This mutation is ugly, even if we undo it - curr->symbol = tname; - nrefs += block_bind_subblock(inst_block(curr), body, bindflags2, 0); - curr->symbol = cname; - free(tname); - } - free(matchname); - return body; // We don't return a join because we don't want those sticking around... -} - -// Bind binder to body and throw away any defs in binder not referenced -// (directly or indirectly) from body. -block block_bind_referenced(block binder, block body, int bindflags) { - assert(block_has_only_binders(binder, bindflags)); - bindflags |= OP_HAS_BINDING; - block refd = gen_noop(); - block unrefd = gen_noop(); - int nrefs; - for (int last_kept = 0, kept = 0; ; ) { - for (inst* curr; (curr = block_take(&binder));) { - block b = inst_block(curr); - nrefs = block_bind_each(b, body, bindflags); - // Check if this binder is referenced from any of the ones we - // already know are referenced by body. - nrefs += block_count_refs(b, refd); - nrefs += block_count_refs(b, body); - if (nrefs) { - refd = BLOCK(refd, b); - kept++; - } else { - unrefd = BLOCK(unrefd, b); - } - } - if (kept == last_kept) - break; - last_kept = kept; - binder = unrefd; - unrefd = gen_noop(); - } - block_free(unrefd); - return block_join(refd, body); -} - -block block_drop_unreferenced(block body) { - inst* curr; - block refd = gen_noop(); - block unrefd = gen_noop(); - int drop; - do { - drop = 0; - while ((curr = block_take(&body)) && curr->op != TOP) { - block b = inst_block(curr); - if (block_count_refs(b,refd) + block_count_refs(b,body) == 0) { - unrefd = BLOCK(unrefd, b); - drop++; - } else { - refd = BLOCK(refd, b); - } - } - if (curr && curr->op == TOP) { - body = BLOCK(inst_block(curr),body); - } - body = BLOCK(refd, body); - refd = gen_noop(); - } while (drop != 0); - block_free(unrefd); - return body; -} - -jv block_take_imports(block* body) { - jv imports = jv_array(); - - inst* top = NULL; - if (body->first && body->first->op == TOP) { - top = block_take(body); - } - while (body->first && (body->first->op == MODULEMETA || body->first->op == DEPS)) { - inst* dep = block_take(body); - if (dep->op == DEPS) { - imports = jv_array_append(imports, jv_copy(dep->imm.constant)); - } - inst_free(dep); - } - if (top) { - *body = block_join(inst_block(top),*body); - } - return imports; -} - -block gen_module(block metadata) { - inst* i = inst_new(MODULEMETA); - i->imm.constant = block_const(metadata); - if (jv_get_kind(i->imm.constant) != JV_KIND_OBJECT) - i->imm.constant = jv_object_set(jv_object(), jv_string("metadata"), i->imm.constant); - block_free(metadata); - return inst_block(i); -} - -jv block_module_meta(block b) { - if (b.first != NULL && b.first->op == MODULEMETA) - return jv_copy(b.first->imm.constant); - return jv_null(); -} - -block gen_import(const char* name, const char* as, int is_data) { - inst* i = inst_new(DEPS); - jv meta = jv_object(); - if (as != NULL) - meta = jv_object_set(meta, jv_string("as"), jv_string(as)); - meta = jv_object_set(meta, jv_string("is_data"), is_data ? jv_true() : jv_false()); - meta = jv_object_set(meta, jv_string("relpath"), jv_string(name)); - i->imm.constant = meta; - return inst_block(i); -} - -block gen_import_meta(block import, block metadata) { - assert(block_is_single(import) && import.first->op == DEPS); - assert(block_is_const(metadata) && block_const_kind(metadata) == JV_KIND_OBJECT); - inst *i = import.first; - i->imm.constant = jv_object_merge(block_const(metadata), i->imm.constant); - block_free(metadata); - return import; -} - -block gen_function(const char* name, block formals, block body) { - inst* i = inst_new(CLOSURE_CREATE); - for (inst* i = formals.last; i; i = i->prev) { - if (i->op == CLOSURE_PARAM_REGULAR) { - i->op = CLOSURE_PARAM; - body = gen_var_binding(gen_call(i->symbol, gen_noop()), i->symbol, body); - } - block_bind_subblock(inst_block(i), body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); - } - i->subfn = body; - i->symbol = strdup(name); - i->arglist = formals; - block b = inst_block(i); - block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); - return b; -} - -block gen_param_regular(const char* name) { - return gen_op_unbound(CLOSURE_PARAM_REGULAR, name); -} - -block gen_param(const char* name) { - return gen_op_unbound(CLOSURE_PARAM, name); -} - -block gen_lambda(block body) { - return gen_function("@lambda", gen_noop(), body); -} - -block gen_call(const char* name, block args) { - block b = gen_op_unbound(CALL_JQ, name); - b.first->arglist = args; - return b; -} - - - -block gen_subexp(block a) { - return BLOCK(gen_op_simple(SUBEXP_BEGIN), a, gen_op_simple(SUBEXP_END)); -} - -block gen_both(block a, block b) { - block jump = gen_op_targetlater(JUMP); - block fork = gen_op_target(FORK, jump); - block c = BLOCK(fork, a, jump, b); - inst_set_target(jump, c); - return c; -} - -block gen_const_object(block expr) { - int is_const = 1; - jv o = jv_object(); - jv k = jv_null(); - jv v = jv_null(); - for (inst *i = expr.first; i; i = i->next) { - if (i->op != SUBEXP_BEGIN || - i->next == NULL || - i->next->op != LOADK || - i->next->next == NULL || - i->next->next->op != SUBEXP_END) { - is_const = 0; - break; - } - k = jv_copy(i->next->imm.constant); - i = i->next->next->next; - if (i == NULL || - i->op != SUBEXP_BEGIN || - i->next == NULL || - i->next->op != LOADK || - i->next->next == NULL || - i->next->next->op != SUBEXP_END) { - is_const = 0; - break; - } - v = jv_copy(i->next->imm.constant); - i = i->next->next->next; - if (i == NULL || i->op != INSERT) { - is_const = 0; - break; - } - if (jv_get_kind(k) != JV_KIND_STRING) { - is_const = 0; - break; - } - o = jv_object_set(o, k, v); - k = jv_null(); - v = jv_null(); - } - if (!is_const) { - jv_free(o); - jv_free(k); - jv_free(v); - block b = {0,0}; - return b; - } - block_free(expr); - return gen_const(o); -} - -static block gen_const_array(block expr) { - /* - * An expr of all constant elements looks like this: - * - * 0009 FORK 0027 - * 0011 FORK 0023 - * 0013 FORK 0019 - * 0015 LOADK 1 - * 0017 JUMP 0021 - * 0019 LOADK 2 - * 0021 JUMP 0025 - * 0023 LOADK 3 - * 0025 JUMP 0029 - * 0027 LOADK 4 - * - * That's: N-1 commas for N elements, N LOADKs, and a JUMP between - * every LOADK. The sequence ends in a LOADK. Any deviation and it's - * not a list of constants. - * - * Here we check for this pattern almost exactly. We don't check that - * the targets of the FORK and JUMP instructions are in the right - * sequence. - */ - int all_const = 1; - int commas = 0; - int normal = 1; - jv a = jv_array(); - for (inst *i = expr.first; i; i = i->next) { - if (i->op == FORK) { - commas++; - if (i->imm.target == NULL || i->imm.target->op != JUMP || - jv_array_length(jv_copy(a)) > 0) { - normal = 0; - break; - } - } else if (all_const && i->op == LOADK) { - if (i->next != NULL && i->next->op != JUMP) { - normal = 0; - break; - } - a = jv_array_append(a, jv_copy(i->imm.constant)); - } else if (i->op != JUMP || i->imm.target == NULL || - i->imm.target->op != LOADK) { - all_const = 0; - } - } - - if (all_const && normal && - (expr.last == NULL || expr.last->op == LOADK) && - jv_array_length(jv_copy(a)) == commas + 1) { - block_free(expr); - return gen_const(a); - } - - jv_free(a); - block b = {0,0}; - return b; -} - -block gen_collect(block expr) { - block const_array = gen_const_array(expr); - if (const_array.first != NULL) - return const_array; - - block array_var = gen_op_var_fresh(STOREV, "collect"); - block c = BLOCK(gen_op_simple(DUP), gen_const(jv_array()), array_var); - - block tail = BLOCK(gen_op_bound(APPEND, array_var), - gen_op_simple(BACKTRACK)); - - return BLOCK(c, - gen_op_target(FORK, tail), - expr, - tail, - gen_op_bound(LOADVN, array_var)); -} - -static block bind_matcher(block matcher, block body) { - // cannot call block_bind(matcher, body) because that requires - // block_has_only_binders(matcher), which is not true here as matchers - // may also contain code to extract the correct elements - for (inst* i = matcher.first; i; i = i->next) { - if (i->op == STOREV && !i->bound_by) - block_bind_subblock(inst_block(i), body, OP_HAS_VARIABLE, 0); - } - return BLOCK(matcher, body); -} - -block gen_reduce(block source, block matcher, block init, block body) { - block res_var = gen_op_var_fresh(STOREV, "reduce"); - block update_var = gen_op_bound(STOREV, res_var); - block jmp = gen_op_target(JUMP, body); - block loop = BLOCK(gen_op_simple(DUPN), - source, - bind_matcher(matcher, - BLOCK(gen_op_bound(LOADVN, res_var), - /* - * We fork to the body, jump to - * the STOREV. This means that - * if body produces no results - * (i.e., it just does empty) - * then we keep the current - * reduction state as-is. - * - * To break out of a - * reduction... use break. - */ - gen_op_target(FORK, jmp), - jmp, - body, - update_var)), - gen_op_simple(BACKTRACK)); - return BLOCK(gen_op_simple(DUP), - init, - res_var, - gen_op_target(FORK, loop), - loop, - gen_op_bound(LOADVN, res_var)); -} - -block gen_foreach(block source, block matcher, block init, block update, block extract) { - block output = gen_op_targetlater(JUMP); - block state_var = gen_op_var_fresh(STOREV, "foreach"); - block loop = BLOCK(gen_op_simple(DUPN), - // get a value from the source expression: - source, - // destructure the value into variable(s) for all the code - // in the body to see - bind_matcher(matcher, - // load the loop state variable - BLOCK(gen_op_bound(LOADVN, state_var), - // generate updated state - update, - // save the updated state for value extraction - gen_op_simple(DUP), - // save new state - gen_op_bound(STOREV, state_var), - // extract an output... - extract, - // ...and output it by jumping - // past the BACKTRACK that comes - // right after the loop body, - // which in turn is there - // because... - // - // (Incidentally, extract can also - // backtrack, e.g., if it calls - // empty, in which case we don't - // get here.) - output))); - block foreach = BLOCK(gen_op_simple(DUP), - init, - state_var, - gen_op_target(FORK, loop), - loop, - // ...at this point `foreach`'s original input - // will be on top of the stack, and we don't - // want to output it, so we backtrack. - gen_op_simple(BACKTRACK)); - inst_set_target(output, foreach); // make that JUMP go bast the BACKTRACK at the end of the loop - return foreach; -} - -block gen_definedor(block a, block b) { - // var found := false - block found_var = gen_op_var_fresh(STOREV, "found"); - block init = BLOCK(gen_op_simple(DUP), gen_const(jv_false()), found_var); - - // if found, backtrack. Otherwise execute b - block backtrack = gen_op_simple(BACKTRACK); - block tail = BLOCK(gen_op_simple(DUP), - gen_op_bound(LOADV, found_var), - gen_op_target(JUMP_F, backtrack), - backtrack, - gen_op_simple(POP), - b); - - // try again - block if_notfound = gen_op_simple(BACKTRACK); - - // found := true, produce result - block if_found = BLOCK(gen_op_simple(DUP), - gen_const(jv_true()), - gen_op_bound(STOREV, found_var), - gen_op_target(JUMP, tail)); - - return BLOCK(init, - gen_op_target(FORK, if_notfound), - a, - gen_op_target(JUMP_F, if_found), - if_found, - if_notfound, - tail); -} - -int block_has_main(block top) { - for (inst *c = top.first; c; c = c->next) { - if (c->op == TOP) - return 1; - } - return 0; -} - -int block_is_funcdef(block b) { - if (b.first != NULL && b.first->op == CLOSURE_CREATE) - return 1; - return 0; -} - -block gen_condbranch(block iftrue, block iffalse) { - iftrue = BLOCK(iftrue, gen_op_target(JUMP, iffalse)); - return BLOCK(gen_op_target(JUMP_F, iftrue), iftrue, iffalse); -} - -block gen_and(block a, block b) { - // a and b = if a then (if b then true else false) else false - return BLOCK(gen_op_simple(DUP), a, - gen_condbranch(BLOCK(gen_op_simple(POP), - b, - gen_condbranch(gen_const(jv_true()), - gen_const(jv_false()))), - BLOCK(gen_op_simple(POP), gen_const(jv_false())))); -} - -block gen_or(block a, block b) { - // a or b = if a then true else (if b then true else false) - return BLOCK(gen_op_simple(DUP), a, - gen_condbranch(BLOCK(gen_op_simple(POP), gen_const(jv_true())), - BLOCK(gen_op_simple(POP), - b, - gen_condbranch(gen_const(jv_true()), - gen_const(jv_false()))))); -} - -block gen_var_binding(block var, const char* name, block body) { - return gen_destructure(var, gen_op_unbound(STOREV, name), body); -} - -block gen_array_matcher(block left, block curr) { - int index; - if (block_is_noop(left)) - index = 0; - else { - // `left` was returned by this function, so the third inst is the - // constant containing the previously used index - assert(left.first->op == DUP); - assert(left.first->next->op == SUBEXP_BEGIN); - assert(left.first->next->next->op == LOADK); - index = 1 + (int) jv_number_value(left.first->next->next->imm.constant); - } - - // `left` goes at the end so that the const index is in a predictable place - return BLOCK(gen_op_simple(DUP), gen_subexp(gen_const(jv_number(index))), - gen_op_simple(INDEX), curr, left); -} - -block gen_object_matcher(block name, block curr) { - return BLOCK(gen_op_simple(DUP), gen_subexp(name), gen_op_simple(INDEX), - curr); -} - -block gen_destructure(block var, block matcher, block body) { - // var bindings can be added after coding the program; leave the TOP first. - block top = gen_noop(); - if (body.first && body.first->op == TOP) - top = inst_block(block_take(&body)); - - return BLOCK(top, gen_op_simple(DUP), var, bind_matcher(matcher, body)); -} - -// Like gen_var_binding(), but bind `break`'s wildcard unbound variable -static block gen_wildvar_binding(block var, const char* name, block body) { - return BLOCK(gen_op_simple(DUP), var, - block_bind(gen_op_unbound(STOREV, name), - body, OP_HAS_VARIABLE | OP_BIND_WILDCARD)); -} - -block gen_cond(block cond, block iftrue, block iffalse) { - return BLOCK(gen_op_simple(DUP), cond, - gen_condbranch(BLOCK(gen_op_simple(POP), iftrue), - 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_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
- * - * JUMP - * - * - * If this is not an internal try/catch, then catch and re-raise - * internal errors to prevent them from leaking. - * - * 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 (!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); -} - -block gen_label(const char *label, block exp) { - block cond = gen_call("_equal", - BLOCK(gen_lambda(gen_noop()), - gen_lambda(gen_op_unbound(LOADV, label)))); - return gen_wildvar_binding(gen_op_simple(GENLABEL), label, - BLOCK(gen_op_simple(POP), - // try exp catch if . == $label - // then empty - // else error end - // - // Can't use gen_binop(), as that's firmly - // stuck in parser.y as it refers to things - // like EQ. - gen_try(exp, - gen_cond(cond, - gen_op_simple(BACKTRACK), - gen_call("error", gen_noop()))))); -} - -block gen_cbinding(const struct cfunction* cfunctions, int ncfunctions, block code) { - for (int cfunc=0; cfuncimm.cfunc = &cfunctions[cfunc]; - i->symbol = strdup(i->imm.cfunc->name); - code = block_bind(inst_block(i), code, OP_IS_CALL_PSEUDO); - } - return code; -} - -static uint16_t nesting_level(struct bytecode* bc, inst* target) { - uint16_t level = 0; - assert(bc && target && target->compiled); - while (bc && target->compiled != bc) { - level++; - bc = bc->parent; - } - assert(bc && bc == target->compiled); - return level; -} - -static int count_cfunctions(block b) { - int n = 0; - for (inst* i = b.first; i; i = i->next) { - if (i->op == CLOSURE_CREATE_C) n++; - n += count_cfunctions(i->subfn); - } - return n; -} - - -// Expands call instructions into a calling sequence -static int expand_call_arglist(block* b) { - int errors = 0; - block ret = gen_noop(); - for (inst* curr; (curr = block_take(b));) { - if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) { - if (!curr->bound_by) { - if (curr->symbol[0] == '*' && curr->symbol[1] >= '1' && curr->symbol[1] <= '3' && curr->symbol[2] == '\0') - locfile_locate(curr->locfile, curr->source, "jq: error: break used outside labeled control structure"); - else - locfile_locate(curr->locfile, curr->source, "jq: error: %s/%d is not defined", curr->symbol, block_count_actuals(curr->arglist)); - errors++; - // don't process this instruction if it's not well-defined - ret = BLOCK(ret, inst_block(curr)); - continue; - } - } - - block prelude = gen_noop(); - if (curr->op == CALL_JQ) { - int actual_args = 0, desired_args = 0; - // We expand the argument list as a series of instructions - switch (curr->bound_by->op) { - default: assert(0 && "Unknown function type"); break; - case CLOSURE_CREATE: - case CLOSURE_PARAM: { - block callargs = gen_noop(); - for (inst* i; (i = block_take(&curr->arglist));) { - assert(opcode_describe(i->op)->flags & OP_IS_CALL_PSEUDO); - block b = inst_block(i); - switch (i->op) { - default: assert(0 && "Unknown type of parameter"); break; - case CLOSURE_REF: - block_append(&callargs, b); - break; - case CLOSURE_CREATE: - block_append(&prelude, b); - block_append(&callargs, gen_op_bound(CLOSURE_REF, b)); - break; - } - actual_args++; - } - curr->imm.intval = actual_args; - curr->arglist = callargs; - - if (curr->bound_by->op == CLOSURE_CREATE) { - for (inst* i = curr->bound_by->arglist.first; i; i = i->next) { - assert(i->op == CLOSURE_PARAM); - desired_args++; - } - } - break; - } - - case CLOSURE_CREATE_C: { - for (inst* i; (i = block_take(&curr->arglist)); ) { - assert(i->op == CLOSURE_CREATE); // FIXME - block body = i->subfn; - i->subfn = gen_noop(); - inst_free(i); - // arguments should be pushed in reverse order, prepend them to prelude - errors += expand_call_arglist(&body); - prelude = BLOCK(gen_subexp(body), prelude); - actual_args++; - } - assert(curr->op == CALL_JQ); - curr->op = CALL_BUILTIN; - curr->imm.intval = actual_args + 1 /* include the implicit input in arg count */; - assert(curr->bound_by->op == CLOSURE_CREATE_C); - desired_args = curr->bound_by->imm.cfunc->nargs - 1; - assert(!curr->arglist.first); - break; - } - } - - assert(actual_args == desired_args); // because now handle this above - } - ret = BLOCK(ret, prelude, inst_block(curr)); - } - *b = ret; - return errors; -} - -static int compile(struct bytecode* bc, block b, struct locfile* lf) { - int errors = 0; - int pos = 0; - int var_frame_idx = 0; - bc->nsubfunctions = 0; - errors += expand_call_arglist(&b); - b = BLOCK(b, gen_op_simple(RET)); - jv localnames = jv_array(); - for (inst* curr = b.first; curr; curr = curr->next) { - if (!curr->next) assert(curr == b.last); - int length = opcode_describe(curr->op)->length; - if (curr->op == CALL_JQ) { - for (inst* arg = curr->arglist.first; arg; arg = arg->next) { - length += 2; - } - } - pos += length; - curr->bytecode_pos = pos; - curr->compiled = bc; - - assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM); - - if ((opcode_describe(curr->op)->flags & OP_HAS_VARIABLE) && - curr->bound_by == curr) { - curr->imm.intval = var_frame_idx++; - localnames = jv_array_append(localnames, jv_string(curr->symbol)); - } - - if (curr->op == CLOSURE_CREATE) { - assert(curr->bound_by == curr); - curr->imm.intval = bc->nsubfunctions++; - } - if (curr->op == CLOSURE_CREATE_C) { - assert(curr->bound_by == curr); - int idx = bc->globals->ncfunctions++; - bc->globals->cfunc_names = jv_array_append(bc->globals->cfunc_names, - jv_string(curr->symbol)); - bc->globals->cfunctions[idx] = *curr->imm.cfunc; - curr->imm.intval = idx; - } - } - if (pos > 0xFFFF) { - // too long for program counter to fit in uint16_t - locfile_locate(lf, UNKNOWN_LOCATION, - "function compiled to %d bytes which is too long", pos); - errors++; - } - bc->codelen = pos; - bc->debuginfo = jv_object_set(bc->debuginfo, jv_string("locals"), localnames); - if (bc->nsubfunctions) { - bc->subfunctions = jv_mem_alloc(sizeof(struct bytecode*) * bc->nsubfunctions); - for (inst* curr = b.first; curr; curr = curr->next) { - if (curr->op == CLOSURE_CREATE) { - struct bytecode* subfn = jv_mem_alloc(sizeof(struct bytecode)); - bc->subfunctions[curr->imm.intval] = subfn; - subfn->globals = bc->globals; - subfn->parent = bc; - subfn->nclosures = 0; - subfn->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_string(curr->symbol)); - jv params = jv_array(); - for (inst* param = curr->arglist.first; param; param = param->next) { - assert(param->op == CLOSURE_PARAM); - assert(param->bound_by == param); - param->imm.intval = subfn->nclosures++; - param->compiled = subfn; - params = jv_array_append(params, jv_string(param->symbol)); - } - subfn->debuginfo = jv_object_set(subfn->debuginfo, jv_string("params"), params); - errors += compile(subfn, curr->subfn, lf); - curr->subfn = gen_noop(); - } - } - } else { - bc->subfunctions = 0; - } - uint16_t* code = jv_mem_alloc(sizeof(uint16_t) * bc->codelen); - bc->code = code; - pos = 0; - jv constant_pool = jv_array(); - int maxvar = -1; - if (!errors) for (inst* curr = b.first; curr; curr = curr->next) { - const struct opcode_description* op = opcode_describe(curr->op); - if (op->length == 0) - continue; - code[pos++] = curr->op; - assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM); - if (curr->op == CALL_BUILTIN) { - assert(curr->bound_by->op == CLOSURE_CREATE_C); - assert(!curr->arglist.first); - code[pos++] = (uint16_t)curr->imm.intval; - code[pos++] = curr->bound_by->imm.intval; - } else if (curr->op == CALL_JQ) { - assert(curr->bound_by->op == CLOSURE_CREATE || - curr->bound_by->op == CLOSURE_PARAM); - code[pos++] = (uint16_t)curr->imm.intval; - code[pos++] = nesting_level(bc, curr->bound_by); - code[pos++] = curr->bound_by->imm.intval | - (curr->bound_by->op == CLOSURE_CREATE ? ARG_NEWCLOSURE : 0); - for (inst* arg = curr->arglist.first; arg; arg = arg->next) { - assert(arg->op == CLOSURE_REF && arg->bound_by->op == CLOSURE_CREATE); - code[pos++] = nesting_level(bc, arg->bound_by); - code[pos++] = arg->bound_by->imm.intval | ARG_NEWCLOSURE; - } - } else if ((op->flags & OP_HAS_CONSTANT) && (op->flags & OP_HAS_VARIABLE)) { - // STORE_GLOBAL: constant global, basically - code[pos++] = jv_array_length(jv_copy(constant_pool)); - constant_pool = jv_array_append(constant_pool, jv_copy(curr->imm.constant)); - code[pos++] = nesting_level(bc, curr->bound_by); - uint16_t var = (uint16_t)curr->bound_by->imm.intval; - code[pos++] = var; - } else if (op->flags & OP_HAS_CONSTANT) { - code[pos++] = jv_array_length(jv_copy(constant_pool)); - constant_pool = jv_array_append(constant_pool, jv_copy(curr->imm.constant)); - } else if (op->flags & OP_HAS_VARIABLE) { - code[pos++] = nesting_level(bc, curr->bound_by); - uint16_t var = (uint16_t)curr->bound_by->imm.intval; - code[pos++] = var; - if (var > maxvar) maxvar = var; - } else if (op->flags & OP_HAS_BRANCH) { - assert(curr->imm.target->bytecode_pos != -1); - assert(curr->imm.target->bytecode_pos > pos); // only forward branches - code[pos] = curr->imm.target->bytecode_pos - (pos + 1); - pos++; - } else if (op->length > 1) { - assert(0 && "codegen not implemented for this operation"); - } - } - bc->constants = constant_pool; - bc->nlocals = maxvar + 2; // FIXME: frames of size zero? - block_free(b); - return errors; -} - -int block_compile(block b, struct bytecode** out, struct locfile* lf) { - struct bytecode* bc = jv_mem_alloc(sizeof(struct bytecode)); - bc->parent = 0; - bc->nclosures = 0; - bc->globals = jv_mem_alloc(sizeof(struct symbol_table)); - int ncfunc = count_cfunctions(b); - bc->globals->ncfunctions = 0; - bc->globals->cfunctions = jv_mem_alloc(sizeof(struct cfunction) * ncfunc); - bc->globals->cfunc_names = jv_array(); - bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null()); - int nerrors = compile(bc, b, lf); - assert(bc->globals->ncfunctions == ncfunc); - if (nerrors > 0) { - bytecode_free(bc); - *out = 0; - } else { - *out = bc; - } - return nerrors; -} - -void block_free(block b) { - struct inst* next; - for (struct inst* curr = b.first; curr; curr = next) { - next = curr->next; - inst_free(curr); - } -} diff --git a/src/jq/compile.h b/src/jq/compile.h deleted file mode 100644 index 4572c9c..0000000 --- a/src/jq/compile.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef COMPILE_H -#define COMPILE_H -#include -#include "jv.h" -#include "bytecode.h" -#include "locfile.h" - -struct inst; -typedef struct inst inst; - - -typedef struct block { - inst* first; - inst* last; -} block; - -block gen_location(location, struct locfile*, block); - -block gen_noop(); -int block_is_noop(block b); -block gen_op_simple(opcode op); -block gen_const(jv constant); -block gen_const_global(jv constant, const char *name); -int block_is_const(block b); -int block_is_const_inf(block b); -jv_kind block_const_kind(block b); -jv block_const(block b); -block gen_op_target(opcode op, block target); -block gen_op_unbound(opcode op, const char* name); -block gen_op_bound(opcode op, block binder); -block gen_op_var_fresh(opcode op, const char* name); - -block gen_module(block metadata); -jv block_module_meta(block b); -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(const char* name); -block gen_lambda(block body); -block gen_call(const char* name, block body); -block gen_subexp(block a); -block gen_both(block a, block b); -block gen_const_object(block expr); -block gen_collect(block expr); -block gen_reduce(block source, block matcher, block init, block body); -block gen_foreach(block source, block matcher, block init, block update, block extract); -block gen_definedor(block a, block b); -block gen_condbranch(block iftrue, block iffalse); -block gen_and(block a, block b); -block gen_or(block a, block b); - -block gen_var_binding(block var, const char* name, block body); -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_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); - -void block_append(block* b, block b2); -block block_join(block a, block b); -int block_has_only_binders_and_imports(block, int bindflags); -int block_has_only_binders(block, int bindflags); -int block_has_main(block); -int block_is_funcdef(block b); -int block_is_single(block b); -block block_bind(block binder, block body, int bindflags); -block block_bind_library(block binder, block body, int bindflags, const char* libname); -block block_bind_referenced(block binder, block body, int bindflags); -block block_drop_unreferenced(block body); - -jv block_take_imports(block* body); - -int block_compile(block, struct bytecode**, struct locfile*); - -void block_free(block); - - - -// Here's some horrible preprocessor gunk so that code -// sequences can be contructed as BLOCK(block1, block2, block3) - -#define BLOCK_1(b1) (b1) -#define BLOCK_2(b1,b2) (block_join((b1),(b2))) -#define BLOCK_3(b1,b2,b3) (block_join(BLOCK_2(b1,b2),(b3))) -#define BLOCK_4(b1,b2,b3,b4) (block_join(BLOCK_3(b1,b2,b3),(b4))) -#define BLOCK_5(b1,b2,b3,b4,b5) (block_join(BLOCK_4(b1,b2,b3,b4),(b5))) -#define BLOCK_6(b1,b2,b3,b4,b5,b6) (block_join(BLOCK_5(b1,b2,b3,b4,b5),(b6))) -#define BLOCK_7(b1,b2,b3,b4,b5,b6,b7) (block_join(BLOCK_6(b1,b2,b3,b4,b5,b6),(b7))) -#define BLOCK_8(b1,b2,b3,b4,b5,b6,b7,b8) (block_join(BLOCK_7(b1,b2,b3,b4,b5,b6,b7),(b8))) - -#define BLOCK_IDX(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME -#define BLOCK(...) \ - BLOCK_IDX(__VA_ARGS__, BLOCK_8, BLOCK_7, BLOCK_6, BLOCK_5, BLOCK_4, BLOCK_3, BLOCK_2, BLOCK_1)(__VA_ARGS__) - - -#endif diff --git a/src/jq/exec_stack.h b/src/jq/exec_stack.h deleted file mode 100644 index 57e1365..0000000 --- a/src/jq/exec_stack.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef EXEC_STACK_H -#define EXEC_STACK_H -#include -#include -#include -#include -#include "jv_alloc.h" - -/* - * The stack is a directed forest of variably sized blocks. Each block has a - * "next" block which is at a higher memory address, or 0 if the block has no - * "next" block. More than one block may have no "next" block. A block may be - * the "next" block of more than one other block. Pushed blocks are added at - * the low-address end of the stack. - * - * Stack pointers are negative integers that are offsets relative to "mem_end", - * the end of the allocated region. The stack "bound" is the stack pointer of - * the last block that would be able to fit in the currently allocated region. - * The stack "limit" is the stack pointer of the last block currently in the - * stack. The stack pointer of the "next" block is stored directly below each - * block. - * - * <- mem_end = 0x100 - * 0xF8 +------------+ - * 0xF0 | | - * 0xE8 +------------+ <- stack_ptr1 = -0x18 - * 0xE0 next = 0 - * 0xD8 +------------+ - * 0xD0 | | - * 0xC8 | | - * 0xC0 +------------+ <- stack_ptr2 = limit = -0x40 - * 0xB8 next = -0x18 - * 0xB0 - * 0xA8 <- bound = -0x58 - * 0xA0 - */ - -struct determine_alignment { - char x; - union { int i; double d; uint64_t u64; size_t sz; void* ptr; } u; -}; -enum {ALIGNMENT = offsetof(struct determine_alignment, u)}; - -static size_t align_round_up(size_t sz) { - return ((sz + (ALIGNMENT - 1)) / ALIGNMENT) * ALIGNMENT; -} - -typedef int stack_ptr; - -struct stack { - char* mem_end; // one-past-the-end of allocated region - stack_ptr bound; - stack_ptr limit; // 0 - stack is empty -}; - -static void stack_init(struct stack* s) { - s->mem_end = 0; - s->bound = ALIGNMENT; - s->limit = 0; -} - -static void stack_reset(struct stack* s) { - assert(s->limit == 0 && "stack freed while not empty"); - char* mem_start = s->mem_end - ( -s->bound + ALIGNMENT); - free(mem_start); - stack_init(s); -} - -static int stack_pop_will_free(struct stack* s, stack_ptr p) { - return p == s->limit; -} - -static void* stack_block(struct stack* s, stack_ptr p) { - return (void*)(s->mem_end + p); -} - -static stack_ptr* stack_block_next(struct stack* s, stack_ptr p) { - return &((stack_ptr*)stack_block(s, p))[-1]; -} - -static void stack_reallocate(struct stack* s, size_t sz) { - int old_mem_length = -(s->bound) + ALIGNMENT; - char* old_mem_start = s->mem_end - old_mem_length; - - int new_mem_length = align_round_up((old_mem_length + sz + 256) * 2); - char* new_mem_start = jv_mem_realloc(old_mem_start, new_mem_length); - memmove(new_mem_start + (new_mem_length - old_mem_length), - new_mem_start, old_mem_length); - s->mem_end = new_mem_start + new_mem_length; - s->bound = -(new_mem_length - ALIGNMENT); -} - -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; - if (r < s->bound) { - stack_reallocate(s, alloc_sz); - } - s->limit = r; - *stack_block_next(s, r) = p; - return r; -} - -static stack_ptr stack_pop_block(struct stack* s, stack_ptr p, size_t sz) { - stack_ptr r = *stack_block_next(s, p); - if (p == s->limit) { - int alloc_sz = align_round_up(sz) + ALIGNMENT; - s->limit += alloc_sz; - } - return r; -} -#endif diff --git a/src/jq/execute.c b/src/jq/execute.c deleted file mode 100644 index 1a84f4c..0000000 --- a/src/jq/execute.c +++ /dev/null @@ -1,1155 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "exec_stack.h" -#include "bytecode.h" - -#include "jv_alloc.h" -#include "jq_parser.h" -#include "locfile.h" -#include "jv.h" -#include "jq.h" -#include "parser.h" -#include "builtin.h" -#include "util.h" -#include "linker.h" - -struct jq_state { - void (*nomem_handler)(void *); - void *nomem_handler_data; - struct bytecode* bc; - - jq_msg_cb err_cb; - void *err_cb_data; - jv error; - - struct stack stk; - stack_ptr curr_frame; - stack_ptr stk_top; - stack_ptr fork_top; - - jv path; - jv value_at_path; - int subexp_nest; - int debug_trace_enabled; - int initial_execution; - unsigned next_label; - - jv attrs; - jq_input_cb input_cb; - void *input_cb_data; - jq_msg_cb debug_cb; - void *debug_cb_data; -}; - -struct closure { - struct bytecode* bc; // jq bytecode - stack_ptr env; // jq stack address of closed frame -}; - -// locals for any function called: either a closure or a local variable -union frame_entry { - struct closure closure; - jv localvar; -}; - -// jq function call frame -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 - uint16_t* retaddr; // jq bytecode return address - union frame_entry entries[]; // nclosures + nlocals -}; - -static int frame_size(struct bytecode* bc) { - return sizeof(struct frame) + sizeof(union frame_entry) * (bc->nclosures + bc->nlocals); -} - -static struct frame* frame_current(struct jq_state* jq) { - struct frame* fp = stack_block(&jq->stk, jq->curr_frame); - - stack_ptr next = *stack_block_next(&jq->stk, jq->curr_frame); - if (next) { - struct frame* fpnext = stack_block(&jq->stk, next); - struct bytecode* bc = fpnext->bc; - assert(fp->retaddr >= bc->code && fp->retaddr < bc->code + bc->codelen); - } else { - assert(fp->retaddr == 0); - } - return fp; -} - -static stack_ptr frame_get_level(struct jq_state* jq, int level) { - stack_ptr fr = jq->curr_frame; - for (int i=0; istk, fr); - fr = fp->env; - } - return fr; -} - -static jv* frame_local_var(struct jq_state* jq, int var, int level) { - struct frame* fr = stack_block(&jq->stk, frame_get_level(jq, level)); - assert(var >= 0); - assert(var < fr->bc->nlocals); - return &fr->entries[fr->bc->nclosures + var].localvar; -} - -static struct closure make_closure(struct jq_state* jq, uint16_t* pc) { - uint16_t level = *pc++; - uint16_t idx = *pc++; - stack_ptr fridx = frame_get_level(jq, level); - struct frame* fr = stack_block(&jq->stk, fridx); - if (idx & ARG_NEWCLOSURE) { - // A new closure closing the frame identified by level, and with - // the bytecode body of the idx'th subfunction of that frame - int subfn_idx = idx & ~ARG_NEWCLOSURE; - assert(subfn_idx < fr->bc->nsubfunctions); - struct closure cl = {fr->bc->subfunctions[subfn_idx], - fridx}; - return cl; - } else { - // A reference to a closure from the frame identified by level; copy - // it as-is - int closure = idx; - assert(closure >= 0); - assert(closure < fr->bc->nclosures); - return fr->entries[closure].closure; - } -} - -static struct frame* frame_push(struct jq_state* jq, struct closure callee, - uint16_t* argdef, int nargs) { - stack_ptr new_frame_idx = stack_push_block(&jq->stk, jq->curr_frame, frame_size(callee.bc)); - struct frame* new_frame = stack_block(&jq->stk, new_frame_idx); - new_frame->bc = callee.bc; - new_frame->env = callee.env; - assert(nargs == new_frame->bc->nclosures); - union frame_entry* entries = new_frame->entries; - for (int i=0; iclosure = make_closure(jq, argdef + i * 2); - entries++; - } - for (int i=0; inlocals; i++) { - entries->localvar = jv_invalid(); - entries++; - } - jq->curr_frame = new_frame_idx; - return new_frame; -} - -static void frame_pop(struct jq_state* jq) { - assert(jq->curr_frame); - struct frame* fp = frame_current(jq); - if (stack_pop_will_free(&jq->stk, jq->curr_frame)) { - int nlocals = fp->bc->nlocals; - for (int i=0; icurr_frame = stack_pop_block(&jq->stk, jq->curr_frame, frame_size(fp->bc)); -} - -void stack_push(jq_state *jq, jv val) { - assert(jv_is_valid(val)); - jq->stk_top = stack_push_block(&jq->stk, jq->stk_top, sizeof(jv)); - jv* sval = stack_block(&jq->stk, jq->stk_top); - *sval = val; -} - -jv stack_pop(jq_state *jq) { - jv* sval = stack_block(&jq->stk, jq->stk_top); - jv val = *sval; - if (!stack_pop_will_free(&jq->stk, jq->stk_top)) { - val = jv_copy(val); - } - jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv)); - assert(jv_is_valid(val)); - return val; -} - -// Like stack_pop(), but assert !stack_pop_will_free() and replace with -// jv_null() on the stack. -jv stack_popn(jq_state *jq) { - jv* sval = stack_block(&jq->stk, jq->stk_top); - jv val = *sval; - if (!stack_pop_will_free(&jq->stk, jq->stk_top)) { - *sval = jv_null(); - } - jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv)); - assert(jv_is_valid(val)); - return val; -} - - -struct forkpoint { - stack_ptr saved_data_stack; - stack_ptr saved_curr_frame; - int path_len, subexp_nest; - jv value_at_path; - uint16_t* return_address; -}; - -struct stack_pos { - stack_ptr saved_data_stack, saved_curr_frame; -}; - -struct stack_pos stack_get_pos(jq_state* jq) { - struct stack_pos sp = {jq->stk_top, jq->curr_frame}; - return sp; -} - -void stack_save(jq_state *jq, uint16_t* retaddr, struct stack_pos sp){ - jq->fork_top = stack_push_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint)); - struct forkpoint* fork = stack_block(&jq->stk, jq->fork_top); - fork->saved_data_stack = jq->stk_top; - fork->saved_curr_frame = jq->curr_frame; - fork->path_len = - jv_get_kind(jq->path) == JV_KIND_ARRAY ? jv_array_length(jv_copy(jq->path)) : 0; - fork->value_at_path = jv_copy(jq->value_at_path); - fork->subexp_nest = jq->subexp_nest; - fork->return_address = retaddr; - jq->stk_top = sp.saved_data_stack; - jq->curr_frame = sp.saved_curr_frame; -} - -static int path_intact(jq_state *jq, jv curr) { - if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) { - return jv_identical(curr, jv_copy(jq->value_at_path)); - } else { - jv_free(curr); - return 1; - } -} - -static void path_append(jq_state* jq, jv component, jv value_at_path) { - if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) { - int n1 = jv_array_length(jv_copy(jq->path)); - jq->path = jv_array_append(jq->path, component); - int n2 = jv_array_length(jv_copy(jq->path)); - assert(n2 == n1 + 1); - jv_free(jq->value_at_path); - jq->value_at_path = value_at_path; - } else { - jv_free(component); - jv_free(value_at_path); - } -} - -uint16_t* stack_restore(jq_state *jq){ - while (!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)) { - frame_pop(jq); - } else { - assert(0); - } - } - - if (jq->fork_top == 0) { - return 0; - } - - struct forkpoint* fork = stack_block(&jq->stk, jq->fork_top); - uint16_t* retaddr = fork->return_address; - jq->stk_top = fork->saved_data_stack; - jq->curr_frame = fork->saved_curr_frame; - int path_len = fork->path_len; - if (jv_get_kind(jq->path) == JV_KIND_ARRAY) { - assert(path_len >= 0); - jq->path = jv_array_slice(jq->path, 0, path_len); - } else { - assert(path_len == 0); - } - jv_free(jq->value_at_path); - jq->value_at_path = fork->value_at_path; - jq->subexp_nest = fork->subexp_nest; - jq->fork_top = stack_pop_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint)); - return retaddr; -} - -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); - jv_free(jq->error); - jq->error = jv_null(); - - if (jv_get_kind(jq->path) != JV_KIND_INVALID) - jv_free(jq->path); - jq->path = jv_null(); - jv_free(jq->value_at_path); - jq->value_at_path = jv_null(); - jq->subexp_nest = 0; -} - -void jq_report_error(jq_state *jq, jv value) { - assert(jq->err_cb); - // callback must jv_free() its jv argument - jq->err_cb(jq->err_cb_data, value); -} - -static void set_error(jq_state *jq, jv value) { - // Record so try/catch can find it. - jv_free(jq->error); - jq->error = value; -} - -#define ON_BACKTRACK(op) ((op)+NUM_OPCODES) - -jv jq_next(jq_state *jq) { - jv cfunc_input[MAX_CFUNCTION_ARGS]; - - jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); - - uint16_t* pc = stack_restore(jq); - assert(pc); - - int raising; - int backtracking = !jq->initial_execution; - jq->initial_execution = 0; - assert(jv_get_kind(jq->error) == JV_KIND_NULL); - while (1) { - uint16_t opcode = *pc; - raising = 0; - - 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]; - for (int i=0; istk_top; - } else { - printf(" | "); - param = *stack_block_next(&jq->stk, param); - } - if (!param) break; - jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT); - //printf("<%d>", jv_get_refcnt(param->val)); - //printf(" -- "); - //jv_dump(jv_copy(jq->path), 0); - } - } else { - printf("\t"); - } - - printf("\n"); - } - - if (backtracking) { - opcode = ON_BACKTRACK(opcode); - backtracking = 0; - raising = !jv_is_valid(jq->error); - } - pc++; - - 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)); - jv_free(stack_pop(jq)); - stack_push(jq, v); - break; - } - - case GENLABEL: { - stack_push(jq, JV_OBJECT(jv_string("__jq"), jv_number(jq->next_label++))); - break; - } - - case DUP: { - jv v = stack_pop(jq); - stack_push(jq, jv_copy(v)); - stack_push(jq, v); - break; - } - - case DUPN: { - jv v = stack_popn(jq); - stack_push(jq, jv_copy(v)); - stack_push(jq, v); - break; - } - - case DUP2: { - jv keep = stack_pop(jq); - jv v = stack_pop(jq); - stack_push(jq, jv_copy(v)); - stack_push(jq, keep); - stack_push(jq, v); - break; - } - - case SUBEXP_BEGIN: { - jv v = stack_pop(jq); - stack_push(jq, jv_copy(v)); - stack_push(jq, v); - jq->subexp_nest++; - break; - } - - case SUBEXP_END: { - assert(jq->subexp_nest > 0); - jq->subexp_nest--; - jv a = stack_pop(jq); - jv b = stack_pop(jq); - stack_push(jq, a); - stack_push(jq, b); - break; - } - - case POP: { - jv_free(stack_pop(jq)); - break; - } - - case APPEND: { - jv v = stack_pop(jq); - uint16_t level = *pc++; - uint16_t vidx = *pc++; - jv* var = frame_local_var(jq, vidx, level); - assert(jv_get_kind(*var) == JV_KIND_ARRAY); - *var = jv_array_append(*var, v); - break; - } - - case INSERT: { - jv stktop = stack_pop(jq); - jv v = stack_pop(jq); - jv k = stack_pop(jq); - jv objv = stack_pop(jq); - assert(jv_get_kind(objv) == JV_KIND_OBJECT); - if (jv_get_kind(k) == JV_KIND_STRING) { - stack_push(jq, jv_object_set(objv, k, v)); - stack_push(jq, stktop); - } else { - char errbuf[15]; - set_error(jq, jv_invalid_with_msg(jv_string_fmt("Cannot use %s (%s) as object key", - jv_kind_name(jv_get_kind(k)), - jv_dump_string_trunc(jv_copy(k), errbuf, sizeof(errbuf))))); - jv_free(stktop); - jv_free(v); - jv_free(k); - jv_free(objv); - goto do_backtrack; - } - break; - } - - case ON_BACKTRACK(RANGE): - case RANGE: { - uint16_t level = *pc++; - uint16_t v = *pc++; - jv* var = frame_local_var(jq, v, level); - jv max = stack_pop(jq); - if (raising) goto do_backtrack; - if (jv_get_kind(*var) != JV_KIND_NUMBER || - jv_get_kind(max) != JV_KIND_NUMBER) { - set_error(jq, jv_invalid_with_msg(jv_string_fmt("Range bounds must be numeric"))); - jv_free(max); - goto do_backtrack; - } else if (jv_number_value(jv_copy(*var)) >= jv_number_value(jv_copy(max))) { - /* finished iterating */ - goto do_backtrack; - } else { - jv curr = jv_copy(*var); - *var = jv_number(jv_number_value(*var) + 1); - - struct stack_pos spos = stack_get_pos(jq); - stack_push(jq, jv_copy(max)); - stack_save(jq, pc - 3, spos); - - stack_push(jq, curr); - } - break; - } - - // FIXME: loadv/storev may do too much copying/freeing - case LOADV: { - uint16_t level = *pc++; - uint16_t v = *pc++; - jv* var = frame_local_var(jq, v, level); - if (jq->debug_trace_enabled) { - printf("V%d = ", v); - jv_dump(jv_copy(*var), 0); - printf(" (%d)\n", jv_get_refcnt(*var)); - } - jv_free(stack_pop(jq)); - stack_push(jq, jv_copy(*var)); - break; - } - - // Does a load but replaces the variable with null - case LOADVN: { - uint16_t level = *pc++; - uint16_t v = *pc++; - jv* var = frame_local_var(jq, v, level); - if (jq->debug_trace_enabled) { - printf("V%d = ", v); - jv_dump(jv_copy(*var), 0); - printf(" (%d)\n", jv_get_refcnt(*var)); - } - jv_free(stack_popn(jq)); - stack_push(jq, *var); - *var = jv_null(); - break; - } - - case STOREV: { - uint16_t level = *pc++; - uint16_t v = *pc++; - jv* var = frame_local_var(jq, v, level); - jv val = stack_pop(jq); - if (jq->debug_trace_enabled) { - printf("V%d = ", v); - jv_dump(jv_copy(val), 0); - printf(" (%d)\n", jv_get_refcnt(val)); - } - jv_free(*var); - *var = val; - break; - } - - case STORE_GLOBAL: { - // Get the constant - jv val = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); - assert(jv_is_valid(val)); - - // Store the var - uint16_t level = *pc++; - uint16_t v = *pc++; - jv* var = frame_local_var(jq, v, level); - if (jq->debug_trace_enabled) { - printf("V%d = ", v); - jv_dump(jv_copy(val), 0); - printf(" (%d)\n", jv_get_refcnt(val)); - } - jv_free(*var); - *var = val; - break; - } - - case PATH_BEGIN: { - jv v = stack_pop(jq); - stack_push(jq, jq->path); - - stack_save(jq, pc - 1, stack_get_pos(jq)); - - stack_push(jq, jv_number(jq->subexp_nest)); - stack_push(jq, jq->value_at_path); - stack_push(jq, jv_copy(v)); - - jq->path = jv_array(); - jq->value_at_path = v; // next INDEX operation must index into v - jq->subexp_nest = 0; - break; - } - - case PATH_END: { - jv v = stack_pop(jq); - // detect invalid path expression like path(.a | reverse) - if (!path_intact(jq, jv_copy(v))) { - char errbuf[30]; - jv msg = jv_string_fmt( - "Invalid path expression with result %s", - jv_dump_string_trunc(v, errbuf, sizeof(errbuf))); - set_error(jq, jv_invalid_with_msg(msg)); - goto do_backtrack; - } - jv_free(v); // discard value, only keep path - - jv old_value_at_path = stack_pop(jq); - int old_subexp_nest = (int)jv_number_value(stack_pop(jq)); - - jv path = jq->path; - jq->path = stack_pop(jq); - - struct stack_pos spos = stack_get_pos(jq); - stack_push(jq, jv_copy(path)); - stack_save(jq, pc - 1, spos); - - stack_push(jq, path); - jq->subexp_nest = old_subexp_nest; - jv_free(jq->value_at_path); - jq->value_at_path = old_value_at_path; - break; - } - - case ON_BACKTRACK(PATH_BEGIN): - case ON_BACKTRACK(PATH_END): { - jv_free(jq->path); - jq->path = stack_pop(jq); - goto do_backtrack; - } - - case INDEX: - case INDEX_OPT: { - jv t = stack_pop(jq); - jv k = stack_pop(jq); - // detect invalid path expression like path(reverse | .a) - if (!path_intact(jq, jv_copy(t))) { - char keybuf[15]; - char objbuf[30]; - jv msg = jv_string_fmt( - "Invalid path expression near attempt to access element %s of %s", - jv_dump_string_trunc(k, keybuf, sizeof(keybuf)), - jv_dump_string_trunc(t, objbuf, sizeof(objbuf))); - set_error(jq, jv_invalid_with_msg(msg)); - goto do_backtrack; - } - jv v = jv_get(t, jv_copy(k)); - if (jv_is_valid(v)) { - path_append(jq, k, jv_copy(v)); - stack_push(jq, v); - } else { - jv_free(k); - if (opcode == INDEX) - set_error(jq, v); - else - jv_free(v); - goto do_backtrack; - } - break; - } - - - case JUMP: { - uint16_t offset = *pc++; - pc += offset; - break; - } - - case JUMP_F: { - uint16_t offset = *pc++; - jv t = stack_pop(jq); - jv_kind kind = jv_get_kind(t); - if (kind == JV_KIND_FALSE || kind == JV_KIND_NULL) { - pc += offset; - } - stack_push(jq, t); // FIXME do this better - break; - } - - case EACH: - case EACH_OPT: { - jv container = stack_pop(jq); - // detect invalid path expression like path(reverse | .[]) - if (!path_intact(jq, jv_copy(container))) { - char errbuf[30]; - jv msg = jv_string_fmt( - "Invalid path expression near attempt to iterate through %s", - jv_dump_string_trunc(container, errbuf, sizeof(errbuf))); - set_error(jq, jv_invalid_with_msg(msg)); - goto do_backtrack; - } - stack_push(jq, container); - stack_push(jq, jv_number(-1)); - // fallthrough - } - case ON_BACKTRACK(EACH): - case ON_BACKTRACK(EACH_OPT): { - int idx = jv_number_value(stack_pop(jq)); - jv container = stack_pop(jq); - - int keep_going, is_last = 0; - jv key, value; - if (jv_get_kind(container) == JV_KIND_ARRAY) { - if (opcode == EACH || opcode == EACH_OPT) idx = 0; - else idx = idx + 1; - int len = jv_array_length(jv_copy(container)); - keep_going = idx < len; - is_last = idx == len - 1; - if (keep_going) { - key = jv_number(idx); - value = jv_array_get(jv_copy(container), idx); - } - } else if (jv_get_kind(container) == JV_KIND_OBJECT) { - if (opcode == EACH || opcode == EACH_OPT) idx = jv_object_iter(container); - else idx = jv_object_iter_next(container, idx); - keep_going = jv_object_iter_valid(container, idx); - if (keep_going) { - key = jv_object_iter_key(container, idx); - value = jv_object_iter_value(container, idx); - } - } else { - assert(opcode == EACH || opcode == EACH_OPT); - if (opcode == EACH) { - char errbuf[15]; - set_error(jq, - jv_invalid_with_msg(jv_string_fmt("Cannot iterate over %s (%s)", - jv_kind_name(jv_get_kind(container)), - jv_dump_string_trunc(jv_copy(container), errbuf, sizeof(errbuf))))); - } - keep_going = 0; - } - - if (!keep_going || raising) { - if (keep_going) - jv_free(value); - jv_free(container); - goto do_backtrack; - } else if (is_last) { - // we don't need to make a backtrack point - jv_free(container); - path_append(jq, key, jv_copy(value)); - stack_push(jq, value); - } else { - struct stack_pos spos = stack_get_pos(jq); - stack_push(jq, container); - stack_push(jq, jv_number(idx)); - stack_save(jq, pc - 1, spos); - path_append(jq, key, jv_copy(value)); - stack_push(jq, value); - } - break; - } - - do_backtrack: - case BACKTRACK: { - pc = stack_restore(jq); - if (!pc) { - if (!jv_is_valid(jq->error)) { - jv error = jq->error; - jq->error = jv_null(); - return error; - } - return jv_invalid(); - } - backtracking = 1; - break; - } - - case FORK_OPT: - case FORK: { - stack_save(jq, pc - 1, stack_get_pos(jq)); - pc++; // skip offset this time - break; - } - - case ON_BACKTRACK(FORK_OPT): { - if (jv_is_valid(jq->error)) { - // `try EXP ...` backtracked here (no value, `empty`), so we backtrack more - jv_free(stack_pop(jq)); - goto do_backtrack; - } - // `try EXP ...` exception caught in EXP - 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(); - uint16_t offset = *pc++; - pc += offset; - break; - } - case ON_BACKTRACK(FORK): { - if (raising) goto do_backtrack; - uint16_t offset = *pc++; - pc += offset; - break; - } - - case CALL_BUILTIN: { - int nargs = *pc++; - jv top = stack_pop(jq); - jv* in = cfunc_input; - in[0] = top; - for (int i = 1; i < nargs; i++) { - in[i] = stack_pop(jq); - } - struct cfunction* function = &frame_current(jq)->bc->globals->cfunctions[*pc++]; - typedef jv (*func_1)(jq_state*,jv); - typedef jv (*func_2)(jq_state*,jv,jv); - typedef jv (*func_3)(jq_state*,jv,jv,jv); - typedef jv (*func_4)(jq_state*,jv,jv,jv,jv); - typedef jv (*func_5)(jq_state*,jv,jv,jv,jv,jv); - switch (function->nargs) { - case 1: top = ((func_1)function->fptr)(jq, in[0]); break; - case 2: top = ((func_2)function->fptr)(jq, in[0], in[1]); break; - case 3: top = ((func_3)function->fptr)(jq, in[0], in[1], in[2]); break; - case 4: top = ((func_4)function->fptr)(jq, in[0], in[1], in[2], in[3]); break; - case 5: top = ((func_5)function->fptr)(jq, in[0], in[1], in[2], in[3], in[4]); break; - // FIXME: a) up to 7 arguments (input + 6), b) should assert - // because the compiler should not generate this error. - default: return jv_invalid_with_msg(jv_string("Function takes too many arguments")); - } - - if (jv_is_valid(top)) { - stack_push(jq, top); - } else if (jv_invalid_has_msg(jv_copy(top))) { - set_error(jq, top); - goto do_backtrack; - } else { - // C-coded function returns invalid w/o msg? -> backtrack, as if - // it had returned `empty` - goto do_backtrack; - } - break; - } - - case TAIL_CALL_JQ: - case CALL_JQ: { - /* - * Bytecode layout here: - * - * CALL_JQ - * (i.e., number of call arguments) - * (what we're calling) - * (frame reference + code pointer) - * - * - * - * Each closure consists of two uint16_t values: a "level" - * identifying the frame to be closed over, and an index. - * - * The level is a relative number of call frames reachable from - * the currently one; 0 -> current frame, 1 -> previous frame, and - * so on. - * - * The index is either an index of the closed frame's subfunctions - * or of the closed frame's parameter closures. If the latter, - * that closure will be passed, else the closed frame's pointer - * and the subfunction's code will form the closure to be passed. - * - * See make_closure() for more information. - */ - jv input = stack_pop(jq); - uint16_t nclosures = *pc++; - uint16_t* retaddr = pc + 2 + nclosures*2; - stack_ptr retdata = jq->stk_top; - struct frame* new_frame; - struct closure cl = make_closure(jq, pc); - if (opcode == TAIL_CALL_JQ) { - retaddr = frame_current(jq)->retaddr; - retdata = frame_current(jq)->retdata; - frame_pop(jq); - } - new_frame = frame_push(jq, cl, pc + 2, nclosures); - new_frame->retdata = retdata; - new_frame->retaddr = retaddr; - pc = new_frame->bc->code; - stack_push(jq, input); - break; - } - - case RET: { - jv value = stack_pop(jq); - assert(jq->stk_top == frame_current(jq)->retdata); - uint16_t* retaddr = frame_current(jq)->retaddr; - if (retaddr) { - // function return - pc = retaddr; - frame_pop(jq); - } else { - // top-level return, yielding value - struct stack_pos spos = stack_get_pos(jq); - stack_push(jq, jv_null()); - stack_save(jq, pc - 1, spos); - return value; - } - stack_push(jq, value); - break; - } - case ON_BACKTRACK(RET): { - // resumed after top-level return - goto do_backtrack; - } - } - } -} - -jv jq_format_error(jv msg) { - if (jv_get_kind(msg) == JV_KIND_NULL || - (jv_get_kind(msg) == JV_KIND_INVALID && !jv_invalid_has_msg(jv_copy(msg)))) { - jv_free(msg); - fprintf(stderr, "jq: error: out of memory\n"); - return jv_null(); - } - - if (jv_get_kind(msg) == JV_KIND_STRING) - return msg; // expected to already be formatted - - if (jv_get_kind(msg) == JV_KIND_INVALID) - msg = jv_invalid_get_msg(msg); - - if (jv_get_kind(msg) == JV_KIND_NULL) - return jq_format_error(msg); // ENOMEM - - // Invalid with msg; prefix with "jq: error: " - - if (jv_get_kind(msg) != JV_KIND_INVALID) { - if (jv_get_kind(msg) == JV_KIND_STRING) - return jv_string_fmt("jq: error: %s", jv_string_value(msg)); - - msg = jv_dump_string(msg, JV_PRINT_INVALID); - if (jv_get_kind(msg) == JV_KIND_STRING) - return jv_string_fmt("jq: error: %s", jv_string_value(msg)); - return jq_format_error(jv_null()); // ENOMEM - } - - // An invalid inside an invalid! - return jq_format_error(jv_invalid_get_msg(msg)); -} - -// 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. -static void default_err_cb(void *data, jv msg) { - msg = jq_format_error(msg); - fprintf((FILE *)data, "%s\n", jv_string_value(msg)); - jv_free(msg); -} - -jq_state *jq_init(void) { - jq_state *jq; - jq = jv_mem_alloc_unguarded(sizeof(*jq)); - if (jq == NULL) - return NULL; - - jq->bc = 0; - jq->next_label = 0; - - stack_init(&jq->stk); - jq->stk_top = 0; - jq->fork_top = 0; - jq->curr_frame = 0; - jq->error = jv_null(); - - jq->err_cb = default_err_cb; - jq->err_cb_data = stderr; - - jq->attrs = jv_object(); - jq->path = jv_null(); - jq->value_at_path = jv_null(); - return jq; -} - -void jq_set_error_cb(jq_state *jq, jq_msg_cb cb, void *data) { - if (cb == NULL) { - jq->err_cb = default_err_cb; - jq->err_cb_data = stderr; - } else { - jq->err_cb = cb; - jq->err_cb_data = data; - } -} - -void jq_get_error_cb(jq_state *jq, jq_msg_cb *cb, void **data) { - *cb = jq->err_cb; - *data = jq->err_cb_data; -} - -void jq_set_nomem_handler(jq_state *jq, void (*nomem_handler)(void *), void *data) { - jv_nomem_handler(nomem_handler, data); - jq->nomem_handler = nomem_handler; - jq->nomem_handler_data = data; -} - - -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; - - stack_push(jq, input); - stack_save(jq, jq->bc->code, stack_get_pos(jq)); - if (flags & JQ_DEBUG_TRACE) { - jq->debug_trace_enabled = 1; - } else { - jq->debug_trace_enabled = 0; - } - jq->initial_execution = 1; -} - -void jq_teardown(jq_state **jq) { - jq_state *old_jq = *jq; - if (old_jq == NULL) - return; - *jq = NULL; - - jq_reset(old_jq); - bytecode_free(old_jq->bc); - old_jq->bc = 0; - jv_free(old_jq->attrs); - - jv_mem_free(old_jq); -} - -static int ret_follows(uint16_t *pc) { - if (*pc == RET) - return 1; - if (*pc++ != JUMP) - return 0; - return ret_follows(pc + *pc + 1); // FIXME, might be ironic -} - -/* - * Look for tail calls that can be optimized: tail calls with no - * references left to the current frame. - * - * We're staring at this bytecode layout: - * - * CALL_JQ - * - * (2 units) - * (2 units each) - * - * - * A closure is: - * - * (a relative frame count chased via the current frame's env) - * (an index of a subfunction or closure in that frame) - * - * We're looking for: - * - * a) the next instruction is a RET or a chain of unconditional JUMPs - * that ends in a RET, and - * - * b) none of the closures -callee included- have level == 0. - */ -static uint16_t tail_call_analyze(uint16_t *pc) { - assert(*pc == CALL_JQ); - pc++; - // + 1 for the callee closure - for (uint16_t nclosures = *pc++ + 1; nclosures > 0; pc++, nclosures--) { - if (*pc++ == 0) - return CALL_JQ; - } - if (ret_follows(pc)) - return TAIL_CALL_JQ; - return CALL_JQ; -} - -static struct bytecode *optimize_code(struct bytecode *bc) { - uint16_t *pc = bc->code; - // FIXME: Don't mutate bc->code... - while (pc < bc->code + bc->codelen) { - switch (*pc) { - case CALL_JQ: - *pc = tail_call_analyze(pc); - break; - - // Other bytecode optimizations here. A peephole optimizer would - // fit right in. - default: break; - } - pc += bytecode_operation_length(pc); - } - return bc; -} - -static struct bytecode *optimize(struct bytecode *bc) { - for (int i=0; insubfunctions; i++) { - bc->subfunctions[i] = optimize(bc->subfunctions[i]); - } - return optimize_code(bc); -} - -int jq_compile_args(jq_state *jq, const char* str, jv args) { - jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); - assert(jv_get_kind(args) == JV_KIND_ARRAY); - struct locfile* locations; - locations = locfile_init(jq, "", str, strlen(str)); - block program; - jq_reset(jq); - if (jq->bc) { - bytecode_free(jq->bc); - jq->bc = 0; - } - int nerrors = load_program(jq, locations, &program); - if (nerrors == 0) { - jv_array_foreach(args, i, arg) { - jv name = jv_object_get(jv_copy(arg), jv_string("name")); - jv value = jv_object_get(arg, jv_string("value")); - program = gen_var_binding(gen_const(value), jv_string_value(name), program); - jv_free(name); - } - - nerrors = builtins_bind(jq, &program); - if (nerrors == 0) { - nerrors = block_compile(program, &jq->bc, locations); - } - } - if (nerrors) - jq_report_error(jq, jv_string_fmt("jq: %d compile %s", nerrors, nerrors > 1 ? "errors" : "error")); - if (jq->bc) - jq->bc = optimize(jq->bc); - jv_free(args); - locfile_free(locations); - return jq->bc != NULL; -} - -int jq_compile(jq_state *jq, const char* str) { - return jq_compile_args(jq, str, jv_array()); -} - -jv jq_get_jq_origin(jq_state *jq) { - return jq_get_attr(jq, jv_string("JQ_ORIGIN")); -} - -jv jq_get_prog_origin(jq_state *jq) { - return jq_get_attr(jq, jv_string("PROGRAM_ORIGIN")); -} - -jv jq_get_lib_dirs(jq_state *jq) { - return jq_get_attr(jq, jv_string("JQ_LIBRARY_PATH")); -} - -void jq_set_attrs(jq_state *jq, jv attrs) { - assert(jv_get_kind(attrs) == JV_KIND_OBJECT); - jv_free(jq->attrs); - jq->attrs = attrs; -} - -void jq_set_attr(jq_state *jq, jv attr, jv val) { - jq->attrs = jv_object_set(jq->attrs, attr, val); -} - -jv jq_get_attr(jq_state *jq, jv attr) { - return jv_object_get(jv_copy(jq->attrs), attr); -} - -void jq_dump_disassembly(jq_state *jq, int indent) { - dump_disassembly(indent, jq->bc); -} - -void jq_set_input_cb(jq_state *jq, jq_input_cb cb, void *data) { - jq->input_cb = cb; - jq->input_cb_data = data; -} - -void jq_get_input_cb(jq_state *jq, jq_input_cb *cb, void **data) { - *cb = jq->input_cb; - *data = jq->input_cb_data; -} - -void jq_set_debug_cb(jq_state *jq, jq_msg_cb cb, void *data) { - jq->debug_cb = cb; - jq->debug_cb_data = data; -} - -void jq_get_debug_cb(jq_state *jq, jq_msg_cb *cb, void **data) { - *cb = jq->debug_cb; - *data = jq->debug_cb_data; -} diff --git a/src/jq/inject_errors.c b/src/jq/inject_errors.c deleted file mode 100644 index b61a271..0000000 --- a/src/jq/inject_errors.c +++ /dev/null @@ -1,112 +0,0 @@ - -#define _GNU_SOURCE /* for RTLD_NEXT */ -#include -#include -#include -#include -#include -#include - -static FILE *fail; -static FILE *fail_read; -static FILE *fail_write; -static FILE *fail_close; -static int error; - -static FILE * (*real_fopen)(const char *, const char *); -static int (*real_fclose)(FILE *); -static int (*real_ferror)(FILE *); -static void (*real_clearerr)(FILE *); -static char * (*real_fgets)(char *, int, FILE *); -static size_t (*real_fread)(void *, size_t, size_t, FILE *); -static size_t (*real_fwrite)(const void *, size_t, size_t, FILE *); - -#define GET_REAL(sym) \ - do { \ - if (real_ ## sym == 0) { \ - real_ ## sym = dlsym(RTLD_NEXT, #sym); \ - assert(real_ ## sym != 0); \ - } \ - } while (0) - -#define dbg_write(msg) (void)write(2, msg, sizeof(msg) - 1) - -#define dbg() \ - do { \ - dbg_write("here: "); \ - dbg_write(__func__); \ - dbg_write("!\n"); \ - } while (0) - -FILE *fopen(const char *path, const char *mode) { - GET_REAL(fopen); - fail = fail_read = fail_write = fail_close = 0; - FILE *f = real_fopen(path, mode); - error = EIO; - if (strcmp(path, "fail_read") == 0) { - fail = fail_read = f; - } else if (strncmp(path, "fail_write", sizeof("fail_write") - 1) == 0) { - // Not that jq opens files for write anyways... - fail = fail_write = f; - if (strcmp(path, "fail_write_enospc") == 0) - error = ENOSPC; - } else if (strncmp(path, "fail_close", sizeof("fail_close") - 1) == 0) { - fail = fail_close = f; - if (strcmp(path, "fail_close_enospc") == 0) - error = ENOSPC; - } - return f; -} - -int fclose(FILE *f) { - GET_REAL(fclose); - int res = real_fclose(f); - if (fail_close == f) { - fail = fail_read = fail_write = fail_close = 0; - return EOF; - } - return res; -} - -char * fgets(char *buf, int len, FILE *f) { - GET_REAL(fgets); - char *res = real_fgets(buf, len, f); - if (fail_read == f) - return 0; - return res; -} - -size_t fread(void *buf, size_t sz, size_t nemb, FILE *f) { - GET_REAL(fread); - size_t res = real_fread(buf, sz, nemb, f); - if (fail_read == f) - return 0; - return res; -} - -size_t fwrite(const void *buf, size_t sz, size_t nemb, FILE *f) { - GET_REAL(fwrite); - size_t res = real_fwrite(buf, sz, nemb, f); - if (fail_write == f) - return 0; - return res; -} - -int ferror(FILE *f) { - GET_REAL(ferror); - int res = real_ferror(f); - if (fail == f) { - errno = error; - return 1; - } - return res; -} - -void clearerr(FILE *f) { - GET_REAL(clearerr); - real_clearerr(f); - if (fail == f) { - fail = fail_read = fail_write = fail_close = 0; - error = 0; - } -} diff --git a/src/jq/jq.h b/src/jq/jq.h deleted file mode 100644 index 7ade128..0000000 --- a/src/jq/jq.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef JQ_H -#define JQ_H - -#include -#include "jv.h" - -enum {JQ_DEBUG_TRACE = 1}; - -typedef struct jq_state jq_state; -typedef void (*jq_msg_cb)(void *, jv); - -jq_state *jq_init(void); -void jq_set_error_cb(jq_state *, jq_msg_cb, void *); -void jq_get_error_cb(jq_state *, jq_msg_cb *, void **); -void jq_set_nomem_handler(jq_state *, void (*)(void *), void *); -jv jq_format_error(jv msg); -void jq_report_error(jq_state *, jv); -int jq_compile(jq_state *, const char*); -int jq_compile_args(jq_state *, const char*, jv); -void jq_dump_disassembly(jq_state *, int); -void jq_start(jq_state *, jv value, int); -jv jq_next(jq_state *); -void jq_teardown(jq_state **); - -typedef jv (*jq_input_cb)(jq_state *, void *); -void jq_set_input_cb(jq_state *, jq_input_cb, void *); -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 **); - -void jq_set_attrs(jq_state *, jv); -jv jq_get_attrs(jq_state *); -jv jq_get_jq_origin(jq_state *); -jv jq_get_prog_origin(jq_state *); -jv jq_get_lib_dirs(jq_state *); -void jq_set_attr(jq_state *, jv, jv); -jv jq_get_attr(jq_state *, jv); - -/* - * We use char * instead of jf for filenames here because filenames - * should be in the process' locale's codeset, which may not be UTF-8, - * whereas jv string values must be in UTF-8. This way the caller - * doesn't have to perform any codeset conversions. - */ -typedef struct jq_util_input_state jq_util_input_state; -typedef void (*jq_util_msg_cb)(void *, const char *); - -jq_util_input_state *jq_util_input_init(jq_util_msg_cb, void *); -void jq_util_input_set_parser(jq_util_input_state *, jv_parser *, int); -void jq_util_input_free(jq_util_input_state **); -void jq_util_input_add_input(jq_util_input_state *, const char *); -int jq_util_input_errors(jq_util_input_state *); -jv jq_util_input_next_input(jq_util_input_state *); -jv jq_util_input_next_input_cb(jq_state *, void *); -jv jq_util_input_get_position(jq_state*); -jv jq_util_input_get_current_filename(jq_state*); -jv jq_util_input_get_current_line(jq_state*); - -#endif /* !JQ_H */ diff --git a/src/jq/jq_parser.h b/src/jq/jq_parser.h deleted file mode 100644 index 809ace0..0000000 --- a/src/jq/jq_parser.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef JQ_PARSER_H -#define JQ_PARSER_H -#include "locfile.h" -#include "compile.h" - -int jq_parse(struct locfile* source, block* answer); -int jq_parse_library(struct locfile* locations, block* answer); - -#endif diff --git a/src/jq/jq_test.c b/src/jq/jq_test.c deleted file mode 100644 index 7a396b9..0000000 --- a/src/jq/jq_test.c +++ /dev/null @@ -1,346 +0,0 @@ -#include -#include -#include -#include -#include "jv.h" -#include "jq.h" - -static void jv_test(); -static void run_jq_tests(jv, int, FILE *); - - -int jq_testsuite(jv libdirs, int verbose, int argc, char* argv[]) { - FILE *testdata = stdin; - jv_test(); - if (argc > 0) { - testdata = fopen(argv[0], "r"); - if (!testdata) { - perror("fopen"); - exit(1); - } - } - run_jq_tests(libdirs, verbose, testdata); - return 0; -} - -static int skipline(const char* buf) { - int p = 0; - while (buf[p] == ' ' || buf[p] == '\t') p++; - if (buf[p] == '#' || buf[p] == '\n' || buf[p] == 0) return 1; - return 0; -} - -static int checkerrormsg(const char* buf) { - return strcmp(buf, "%%FAIL\n") == 0; -} - -static int checkfail(const char* buf) { - return strcmp(buf, "%%FAIL\n") == 0 || strcmp(buf, "%%FAIL IGNORE MSG\n") == 0; -} - -struct err_data { - char buf[4096]; -}; - -static void test_err_cb(void *data, jv e) { - struct err_data *err_data = data; - if (jv_get_kind(e) != JV_KIND_STRING) - e = jv_dump_string(e, JV_PRINT_INVALID); - if (!strncmp(jv_string_value(e), "jq: error", sizeof("jq: error") - 1)) - snprintf(err_data->buf, sizeof(err_data->buf), "%s", jv_string_value(e)); - if (strchr(err_data->buf, '\n')) - *(strchr(err_data->buf, '\n')) = '\0'; - jv_free(e); -} - -static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata) { - char prog[4096]; - char buf[4096]; - struct err_data err_msg; - int tests = 0, passed = 0, invalid = 0; - unsigned int lineno = 0; - int must_fail = 0; - int check_msg = 0; - jq_state *jq = NULL; - - jq = jq_init(); - assert(jq); - if (jv_get_kind(lib_dirs) == JV_KIND_NULL) - lib_dirs = jv_array(); - jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_dirs); - - while (1) { - if (!fgets(prog, sizeof(prog), testdata)) break; - lineno++; - if (skipline(prog)) continue; - if (checkfail(prog)) { - must_fail = 1; - check_msg = checkerrormsg(prog); - jq_set_error_cb(jq, test_err_cb, &err_msg); - continue; - } - if (prog[strlen(prog)-1] == '\n') prog[strlen(prog)-1] = 0; - printf("Testing '%s' at line number %u\n", prog, lineno); - int pass = 1; - tests++; - int compiled = jq_compile(jq, prog); - - if (must_fail) { - jq_set_error_cb(jq, NULL, NULL); - if (!fgets(buf, sizeof(buf), testdata)) { invalid++; break; } - lineno++; - if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0; - if (compiled) { - printf("*** Test program compiled that should not have at line %u: %s\n", lineno, prog); - must_fail = 0; - check_msg = 0; - invalid++; - continue; - } - if (check_msg && strcmp(buf, err_msg.buf) != 0) { - printf("*** Erroneous test program failed with wrong message (%s) at line %u: %s\n", err_msg.buf, lineno, prog); - invalid++; - } else { - passed++; - } - must_fail = 0; - check_msg = 0; - continue; - } - - if (!compiled) { - printf("*** Test program failed to compile at line %u: %s\n", lineno, prog); - invalid++; - // skip past test data - while (fgets(buf, sizeof(buf), testdata)) { - lineno++; - if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n')) - break; - } - continue; - } - if (verbose) { - printf("Disassembly:\n"); - jq_dump_disassembly(jq, 2); - printf("\n"); - } - if (!fgets(buf, sizeof(buf), testdata)) { invalid++; break; } - lineno++; - jv input = jv_parse(buf); - if (!jv_is_valid(input)) { - printf("*** Input is invalid on line %u: %s\n", lineno, buf); - invalid++; - continue; - } - jq_start(jq, input, verbose ? JQ_DEBUG_TRACE : 0); - - while (fgets(buf, sizeof(buf), testdata)) { - lineno++; - if (skipline(buf)) break; - jv 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)) { - jv_free(actual); - printf("*** Insufficient results 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(" for test at line number %u: %s\n", lineno, prog); - pass = 0; - } - 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))); - assert(jv_equal(jv_copy(expected), jv_copy(reparsed))); - jv_free(as_string); - jv_free(reparsed); - jv_free(expected); - jv_free(actual); - } - if (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 { - jv_free(extra); - } - } - passed+=pass; - } - jq_teardown(&jq); - printf("%d of %d tests passed (%d malformed)\n", passed,tests,invalid); - if (passed != tests) exit(1); -} - - -static void jv_test() { - /// JSON parser regression tests - { - jv v = jv_parse("{\"a':\"12\"}"); - assert(jv_get_kind(v) == JV_KIND_INVALID); - v = jv_invalid_get_msg(v); - assert(strcmp(jv_string_value(v), "Expected separator between values at line 1, column 9 (while parsing '{\"a':\"12\"}')") == 0); - jv_free(v); - } - /// Arrays and numbers - { - jv a = jv_array(); - assert(jv_get_kind(a) == JV_KIND_ARRAY); - assert(jv_array_length(jv_copy(a)) == 0); - assert(jv_array_length(jv_copy(a)) == 0); - - a = jv_array_append(a, jv_number(42)); - assert(jv_array_length(jv_copy(a)) == 1); - assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); - - jv a2 = jv_array_append(jv_array(), jv_number(42)); - assert(jv_equal(jv_copy(a), jv_copy(a))); - assert(jv_equal(jv_copy(a2), jv_copy(a2))); - assert(jv_equal(jv_copy(a), jv_copy(a2))); - assert(jv_equal(jv_copy(a2), jv_copy(a))); - jv_free(a2); - - a2 = jv_array_append(jv_array(), jv_number(19)); - assert(!jv_equal(jv_copy(a), jv_copy(a2))); - assert(!jv_equal(jv_copy(a2), jv_copy(a))); - jv_free(a2); - - - assert(jv_get_refcnt(a) == 1); - a = jv_array_append(a, jv_copy(a)); - assert(jv_get_refcnt(a) == 1); - - assert(jv_array_length(jv_copy(a)) == 2); - assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); - - for (int i=0; i<10; i++) { - jv subarray = jv_array_get(jv_copy(a), 1); - assert(jv_get_kind(subarray) == JV_KIND_ARRAY); - assert(jv_array_length(jv_copy(subarray)) == 1); - assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); - jv_free(subarray); - } - - - jv subarray = jv_array_get(jv_copy(a), 1); - assert(jv_get_kind(subarray) == JV_KIND_ARRAY); - assert(jv_array_length(jv_copy(subarray)) == 1); - assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); - - jv sub2 = jv_copy(subarray); - sub2 = jv_array_append(sub2, jv_number(19)); - - assert(jv_get_kind(sub2) == JV_KIND_ARRAY); - assert(jv_array_length(jv_copy(sub2)) == 2); - assert(jv_number_value(jv_array_get(jv_copy(sub2), 0)) == 42); - assert(jv_number_value(jv_array_get(jv_copy(sub2), 1)) == 19); - - assert(jv_get_kind(subarray) == JV_KIND_ARRAY); - assert(jv_array_length(jv_copy(subarray)) == 1); - assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); - - jv_free(subarray); - - void* before = sub2.u.ptr; - sub2 = jv_array_append(sub2, jv_number(200)); - void* after = sub2.u.ptr; - assert(before == after); - jv_free(sub2); - - jv a3 = jv_array_append(jv_copy(a), jv_number(19)); - assert(jv_array_length(jv_copy(a3)) == 3); - assert(jv_number_value(jv_array_get(jv_copy(a3), 0)) == 42); - assert(jv_array_length(jv_array_get(jv_copy(a3), 1)) == 1); - assert(jv_number_value(jv_array_get(jv_copy(a3), 2)) == 19); - jv_free(a3); - - - jv a4 = jv_array(); - a4 = jv_array_append(a4, jv_number(1)); - a4 = jv_array_append(a4, jv_number(2)); - jv a5 = jv_copy(a4); - a4 = jv_array_append(a4, jv_number(3)); - a4 = jv_array_slice(a4, 0, 1); - assert(jv_array_length(jv_copy(a4)) == 1); - a4 = jv_array_append(a4, jv_number(4)); - assert(jv_array_length(jv_copy(a4)) == 2); - assert(jv_array_length(jv_copy(a5)) == 2); - jv_free(a4); - jv_free(a5); - - - assert(jv_array_length(jv_copy(a)) == 2); - assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); - assert(jv_array_length(jv_array_get(jv_copy(a), 1)) == 1); - - - //jv_dump(jv_copy(a), 0); printf("\n"); - jv_free(a); - } - - - /// Strings - { - assert(jv_equal(jv_string("foo"), jv_string_sized("foo", 3))); - char nasty[] = "foo\0"; - jv shortstr = jv_string(nasty), longstr = jv_string_sized(nasty, sizeof(nasty)); - assert(jv_string_length_bytes(jv_copy(shortstr)) == (int)strlen(nasty)); - assert(jv_string_length_bytes(jv_copy(longstr)) == (int)sizeof(nasty)); - jv_free(shortstr); - jv_free(longstr); - - - char a1s[] = "hello", a2s[] = "hello", bs[] = "goodbye"; - jv a1 = jv_string(a1s), a2 = jv_string(a2s), b = jv_string(bs); - assert(jv_equal(jv_copy(a1), jv_copy(a2))); - assert(jv_equal(jv_copy(a2), jv_copy(a1))); - assert(!jv_equal(jv_copy(a1), jv_copy(b))); - - assert(jv_string_hash(jv_copy(a1)) == jv_string_hash(jv_copy(a1))); - assert(jv_string_hash(jv_copy(a1)) == jv_string_hash(jv_copy(a2))); - assert(jv_string_hash(jv_copy(b)) != jv_string_hash(jv_copy(a1))); - jv_free(a1); - jv_free(a2); - jv_free(b); - - assert(jv_equal(jv_string("hello42!"), jv_string_fmt("hello%d%s", 42, "!"))); - char big[20000]; - for (int i=0; i<(int)sizeof(big); i++) big[i] = 'a'; - big[sizeof(big)-1] = 0; - jv str = jv_string_fmt("%s", big); - assert(jv_string_length_bytes(jv_copy(str)) == sizeof(big) - 1); - assert(!strcmp(big, jv_string_value(str))); - jv_free(str); - } - - /// Objects - { - jv o1 = jv_object(); - o1 = jv_object_set(o1, jv_string("foo"), jv_number(42)); - o1 = jv_object_set(o1, jv_string("bar"), jv_number(24)); - assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("foo"))) == 42); - assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("bar"))) == 24); - - jv o2 = jv_object_set(jv_copy(o1), jv_string("foo"), jv_number(420)); - o2 = jv_object_set(o2, jv_string("bar"), jv_number(240)); - assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("foo"))) == 42); - assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("bar"))) == 24); - assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("foo"))) == 420); - jv_free(o1); - assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("bar"))) == 240); - - //jv_dump(jv_copy(o2), 0); printf("\n"); - jv_free(o2); - } -} diff --git a/src/jq/jv.c b/src/jq/jv.c deleted file mode 100644 index e064baf..0000000 --- a/src/jq/jv.c +++ /dev/null @@ -1,1334 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "jv_alloc.h" -#include "jv.h" -#include "jv_unicode.h" -#include "util.h" - -/* - * Internal refcounting helpers - */ - -typedef struct jv_refcnt { - int count; -} jv_refcnt; - -static const jv_refcnt JV_REFCNT_INIT = {1}; - -static void jvp_refcnt_inc(jv_refcnt* c) { - c->count++; -} - -static int jvp_refcnt_dec(jv_refcnt* c) { - c->count--; - return c->count == 0; -} - -static int jvp_refcnt_unshared(jv_refcnt* c) { - assert(c->count > 0); - return c->count == 1; -} - -/* - * Simple values (true, false, null) - */ - -#define KIND_MASK 0xf - -jv_kind jv_get_kind(jv x) { - return x.kind_flags & KIND_MASK; -} - -const char* jv_kind_name(jv_kind k) { - switch (k) { - case JV_KIND_INVALID: return ""; - case JV_KIND_NULL: return "null"; - case JV_KIND_FALSE: return "boolean"; - case JV_KIND_TRUE: return "boolean"; - case JV_KIND_NUMBER: return "number"; - case JV_KIND_STRING: return "string"; - case JV_KIND_ARRAY: return "array"; - case JV_KIND_OBJECT: return "object"; - } - assert(0 && "invalid kind"); - return ""; -} - -static const jv JV_NULL = {JV_KIND_NULL, 0, 0, 0, {0}}; -static const jv JV_INVALID = {JV_KIND_INVALID, 0, 0, 0, {0}}; -static const jv JV_FALSE = {JV_KIND_FALSE, 0, 0, 0, {0}}; -static const jv JV_TRUE = {JV_KIND_TRUE, 0, 0, 0, {0}}; - -jv jv_true() { - return JV_TRUE; -} - -jv jv_false() { - return JV_FALSE; -} - -jv jv_null() { - return JV_NULL; -} - -jv jv_bool(int x) { - return x ? JV_TRUE : JV_FALSE; -} - -/* - * Invalid objects, with optional error messages - */ - -typedef struct { - jv_refcnt refcnt; - jv errmsg; -} jvp_invalid; - -jv jv_invalid_with_msg(jv err) { - if (jv_get_kind(err) == JV_KIND_NULL) - return JV_INVALID; - jvp_invalid* i = jv_mem_alloc(sizeof(jvp_invalid)); - i->refcnt = JV_REFCNT_INIT; - i->errmsg = err; - - jv x = {JV_KIND_INVALID, 0, 0, 0, {&i->refcnt}}; - return x; -} - -jv jv_invalid() { - return JV_INVALID; -} - -jv jv_invalid_get_msg(jv inv) { - assert(jv_get_kind(inv) == JV_KIND_INVALID); - jv x; - if (inv.u.ptr == 0) - x = jv_null(); - else - x = jv_copy(((jvp_invalid*)inv.u.ptr)->errmsg); - jv_free(inv); - return x; -} - -int jv_invalid_has_msg(jv inv) { - jv msg = jv_invalid_get_msg(inv); - int r = jv_get_kind(msg) != JV_KIND_NULL; - jv_free(msg); - return r; -} - -static void jvp_invalid_free(jv x) { - assert(jv_get_kind(x) == JV_KIND_INVALID); - if (x.u.ptr != 0 && jvp_refcnt_dec(x.u.ptr)) { - jv_free(((jvp_invalid*)x.u.ptr)->errmsg); - jv_mem_free(x.u.ptr); - } -} - -/* - * Numbers - */ - -jv jv_number(double x) { - jv j = {JV_KIND_NUMBER, 0, 0, 0, {.number = x}}; - return j; -} - -double jv_number_value(jv j) { - assert(jv_get_kind(j) == JV_KIND_NUMBER); - return j.u.number; -} - -int jv_is_integer(jv j){ - if(jv_get_kind(j) != JV_KIND_NUMBER){ - return 0; - } - double x = jv_number_value(j); - if(x != x || x > INT_MAX || x < INT_MIN){ - return 0; - } - - return x == (int)x; -} - -/* - * Arrays (internal helpers) - */ - -#define ARRAY_SIZE_ROUND_UP(n) (((n)*3)/2) - -static int imax(int a, int b) { - if (a>b) return a; - else return b; -} - -//FIXME signed vs unsigned -typedef struct { - jv_refcnt refcnt; - int length, alloc_length; - jv elements[]; -} jvp_array; - -static jvp_array* jvp_array_ptr(jv a) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - return (jvp_array*)a.u.ptr; -} - -static jvp_array* jvp_array_alloc(unsigned size) { - jvp_array* a = jv_mem_alloc(sizeof(jvp_array) + sizeof(jv) * size); - a->refcnt.count = 1; - a->length = 0; - a->alloc_length = size; - return a; -} - -static jv jvp_array_new(unsigned size) { - jv r = {JV_KIND_ARRAY, 0, 0, 0, {&jvp_array_alloc(size)->refcnt}}; - return r; -} - -static void jvp_array_free(jv a) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - if (jvp_refcnt_dec(a.u.ptr)) { - jvp_array* array = jvp_array_ptr(a); - for (int i=0; ilength; i++) { - jv_free(array->elements[i]); - } - jv_mem_free(array); - } -} - -static int jvp_array_length(jv a) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - return a.size; -} - -static int jvp_array_offset(jv a) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - return a.offset; -} - -static jv* jvp_array_read(jv a, int i) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - if (i >= 0 && i < jvp_array_length(a)) { - jvp_array* array = jvp_array_ptr(a); - assert(i + jvp_array_offset(a) < array->length); - return &array->elements[i + jvp_array_offset(a)]; - } else { - return 0; - } -} - -static jv* jvp_array_write(jv* a, int i) { - assert(i >= 0); - jvp_array* array = jvp_array_ptr(*a); - - int pos = i + jvp_array_offset(*a); - if (pos < array->alloc_length && jvp_refcnt_unshared(a->u.ptr)) { - // use existing array space - for (int j = array->length; j <= pos; j++) { - array->elements[j] = JV_NULL; - } - array->length = imax(pos + 1, array->length); - a->size = imax(i + 1, a->size); - return &array->elements[pos]; - } else { - // allocate a new array - int new_length = imax(i + 1, jvp_array_length(*a)); - jvp_array* new_array = jvp_array_alloc(ARRAY_SIZE_ROUND_UP(new_length)); - int j; - for (j = 0; j < jvp_array_length(*a); j++) { - new_array->elements[j] = - jv_copy(array->elements[j + jvp_array_offset(*a)]); - } - for (; j < new_length; j++) { - new_array->elements[j] = JV_NULL; - } - new_array->length = new_length; - jvp_array_free(*a); - jv new_jv = {JV_KIND_ARRAY, 0, 0, new_length, {&new_array->refcnt}}; - *a = new_jv; - return &new_array->elements[i]; - } -} - -static int jvp_array_equal(jv a, jv b) { - if (jvp_array_length(a) != jvp_array_length(b)) - return 0; - if (jvp_array_ptr(a) == jvp_array_ptr(b) && - jvp_array_offset(a) == jvp_array_offset(b)) - return 1; - for (int i=0; i len) *pstart = len; - if (*pend > len) *pend = len; - if (*pend < *pstart) *pend = *pstart; -} - -static jv jvp_array_slice(jv a, int start, int end) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - int len = jvp_array_length(a); - jvp_clamp_slice_params(len, &start, &end); - assert(0 <= start && start <= end && end <= len); - - // FIXME: maybe slice should reallocate if the slice is small enough - if (start == end) { - jv_free(a); - return jv_array(); - } - // FIXME FIXME FIXME large offsets - a.offset += start; - a.size = end - start; - return a; -} - -/* - * Arrays (public interface) - */ - -jv jv_array_sized(int n) { - return jvp_array_new(n); -} - -jv jv_array() { - return jv_array_sized(16); -} - -int jv_array_length(jv j) { - assert(jv_get_kind(j) == JV_KIND_ARRAY); - int len = jvp_array_length(j); - jv_free(j); - return len; -} - -jv jv_array_get(jv j, int idx) { - assert(jv_get_kind(j) == JV_KIND_ARRAY); - jv* slot = jvp_array_read(j, idx); - jv val; - if (slot) { - val = jv_copy(*slot); - } else { - val = jv_invalid(); - } - jv_free(j); - return val; -} - -jv jv_array_set(jv j, int idx, jv val) { - assert(jv_get_kind(j) == JV_KIND_ARRAY); - - if (idx < 0) - idx = jvp_array_length(j) + idx; - if (idx < 0) { - jv_free(j); - jv_free(val); - return jv_invalid_with_msg(jv_string("Out of bounds negative array index")); - } - // copy/free of val,j coalesced - jv* slot = jvp_array_write(&j, idx); - jv_free(*slot); - *slot = val; - return j; -} - -jv jv_array_append(jv j, jv val) { - // copy/free of val,j coalesced - return jv_array_set(j, jv_array_length(jv_copy(j)), val); -} - -jv jv_array_concat(jv a, jv b) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - assert(jv_get_kind(b) == JV_KIND_ARRAY); - - // FIXME: could be faster - jv_array_foreach(b, i, elem) { - a = jv_array_append(a, elem); - } - jv_free(b); - return a; -} - -jv jv_array_slice(jv a, int start, int end) { - assert(jv_get_kind(a) == JV_KIND_ARRAY); - // copy/free of a coalesced - return jvp_array_slice(a, start, end); -} - -int jv_array_contains(jv a, jv b) { - int r = 1; - jv_array_foreach(b, bi, belem) { - int ri = 0; - jv_array_foreach(a, ai, aelem) { - if (jv_contains(aelem, jv_copy(belem))) { - ri = 1; - break; - } - } - jv_free(belem); - if (!ri) { - r = 0; - break; - } - } - jv_free(a); - jv_free(b); - return r; -} - -jv jv_array_indexes(jv a, jv b) { - jv res = jv_array(); - int idx = -1; - jv_array_foreach(a, ai, aelem) { - jv_array_foreach(b, bi, belem) { - // quieten compiler warnings about aelem not being used... by - // using it - if ((bi == 0 && !jv_equal(jv_copy(aelem), jv_copy(belem))) || - (bi > 0 && !jv_equal(jv_array_get(jv_copy(a), ai + bi), jv_copy(belem)))) - idx = -1; - else if (bi == 0 && idx == -1) - idx = ai; - } - if (idx > -1) - res = jv_array_append(res, jv_number(idx)); - idx = -1; - } - jv_free(a); - jv_free(b); - return res; -} - - -/* - * Strings (internal helpers) - */ - -typedef struct { - jv_refcnt refcnt; - uint32_t hash; - // high 31 bits are length, low bit is a flag - // indicating whether hash has been computed. - uint32_t length_hashed; - uint32_t alloc_length; - char data[]; -} jvp_string; - -static jvp_string* jvp_string_ptr(jv a) { - assert(jv_get_kind(a) == JV_KIND_STRING); - return (jvp_string*)a.u.ptr; -} - -static jvp_string* jvp_string_alloc(uint32_t size) { - jvp_string* s = jv_mem_alloc(sizeof(jvp_string) + size + 1); - s->refcnt.count = 1; - s->alloc_length = size; - return s; -} - -/* Copy a UTF8 string, replacing all badly encoded points with U+FFFD */ -static jv jvp_string_copy_replace_bad(const char* data, uint32_t length) { - const char* end = data + length; - const char* i = data; - const char* cstart; - - uint32_t maxlength = length * 3 + 1; // worst case: all bad bytes, each becomes a 3-byte U+FFFD - jvp_string* s = jvp_string_alloc(maxlength); - char* out = s->data; - int c = 0; - - while ((i = jvp_utf8_next((cstart = i), end, &c))) { - if (c == -1) { - c = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER - } - out += jvp_utf8_encode(c, out); - assert(out < s->data + maxlength); - } - length = out - s->data; - s->data[length] = 0; - s->length_hashed = length << 1; - jv r = {JV_KIND_STRING, 0, 0, 0, {&s->refcnt}}; - return r; -} - -/* Assumes valid UTF8 */ -static jv jvp_string_new(const char* data, uint32_t length) { - jvp_string* s = jvp_string_alloc(length); - s->length_hashed = length << 1; - if (data != NULL) - memcpy(s->data, data, length); - s->data[length] = 0; - jv r = {JV_KIND_STRING, 0, 0, 0, {&s->refcnt}}; - return r; -} - -static jv jvp_string_empty_new(uint32_t length) { - jvp_string* s = jvp_string_alloc(length); - s->length_hashed = 0; - memset(s->data, 0, length); - jv r = {JV_KIND_STRING, 0, 0, 0, {&s->refcnt}}; - return r; -} - - -static void jvp_string_free(jv js) { - jvp_string* s = jvp_string_ptr(js); - if (jvp_refcnt_dec(&s->refcnt)) { - jv_mem_free(s); - } -} - -static uint32_t jvp_string_length(jvp_string* s) { - return s->length_hashed >> 1; -} - -static uint32_t jvp_string_remaining_space(jvp_string* s) { - assert(s->alloc_length >= jvp_string_length(s)); - uint32_t r = s->alloc_length - jvp_string_length(s); - return r; -} - -static jv jvp_string_append(jv string, const char* data, uint32_t len) { - jvp_string* s = jvp_string_ptr(string); - uint32_t currlen = jvp_string_length(s); - - if (jvp_refcnt_unshared(string.u.ptr) && - jvp_string_remaining_space(s) >= len) { - // the next string fits at the end of a - memcpy(s->data + currlen, data, len); - s->data[currlen + len] = 0; - s->length_hashed = (currlen + len) << 1; - return string; - } else { - // allocate a bigger buffer and copy - uint32_t allocsz = (currlen + len) * 2; - if (allocsz < 32) allocsz = 32; - jvp_string* news = jvp_string_alloc(allocsz); - news->length_hashed = (currlen + len) << 1; - memcpy(news->data, s->data, currlen); - memcpy(news->data + currlen, data, len); - news->data[currlen + len] = 0; - jvp_string_free(string); - jv r = {JV_KIND_STRING, 0, 0, 0, {&news->refcnt}}; - return r; - } -} - -static const uint32_t HASH_SEED = 0x432A9843; - -static uint32_t rotl32 (uint32_t x, int8_t r){ - return (x << r) | (x >> (32 - r)); -} - -static uint32_t jvp_string_hash(jv jstr) { - jvp_string* str = jvp_string_ptr(jstr); - if (str->length_hashed & 1) - return str->hash; - - /* The following is based on MurmurHash3. - MurmurHash3 was written by Austin Appleby, and is placed - in the public domain. */ - - const uint8_t* data = (const uint8_t*)str->data; - int len = (int)jvp_string_length(str); - const int nblocks = len / 4; - - uint32_t h1 = HASH_SEED; - - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; - const uint32_t* blocks = (const uint32_t *)(data + nblocks*4); - - for(int i = -nblocks; i; i++) { - uint32_t k1 = blocks[i]; //FIXME: endianness/alignment - - k1 *= c1; - k1 = rotl32(k1,15); - k1 *= c2; - - h1 ^= k1; - h1 = rotl32(h1,13); - h1 = h1*5+0xe6546b64; - } - - const uint8_t* tail = (const uint8_t*)(data + nblocks*4); - - uint32_t k1 = 0; - - switch(len & 3) { - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: k1 ^= tail[0]; - k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1; - } - - h1 ^= len; - - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - str->length_hashed |= 1; - str->hash = h1; - - return h1; -} - -static int jvp_string_equal(jv a, jv b) { - assert(jv_get_kind(a) == JV_KIND_STRING); - assert(jv_get_kind(b) == JV_KIND_STRING); - jvp_string* stra = jvp_string_ptr(a); - jvp_string* strb = jvp_string_ptr(b); - if (jvp_string_length(stra) != jvp_string_length(strb)) return 0; - return memcmp(stra->data, strb->data, jvp_string_length(stra)) == 0; -} - -/* - * Strings (public API) - */ - -jv jv_string_sized(const char* str, int len) { - return - jvp_utf8_is_valid(str, str+len) ? - jvp_string_new(str, len) : - jvp_string_copy_replace_bad(str, len); -} - -jv jv_string_empty(int len) { - return jvp_string_empty_new(len); -} - -jv jv_string(const char* str) { - return jv_string_sized(str, strlen(str)); -} - -int jv_string_length_bytes(jv j) { - assert(jv_get_kind(j) == JV_KIND_STRING); - int r = jvp_string_length(jvp_string_ptr(j)); - jv_free(j); - return r; -} - -int jv_string_length_codepoints(jv j) { - assert(jv_get_kind(j) == JV_KIND_STRING); - const char* i = jv_string_value(j); - const char* end = i + jv_string_length_bytes(jv_copy(j)); - int c = 0, len = 0; - while ((i = jvp_utf8_next(i, end, &c))) len++; - jv_free(j); - return len; -} - - -jv jv_string_indexes(jv j, jv k) { - assert(jv_get_kind(j) == JV_KIND_STRING); - assert(jv_get_kind(k) == JV_KIND_STRING); - const char *jstr = jv_string_value(j); - const char *idxstr = jv_string_value(k); - const char *p; - int jlen = jv_string_length_bytes(jv_copy(j)); - int idxlen = jv_string_length_bytes(jv_copy(k)); - jv a = jv_array(); - - p = jstr; - while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) { - a = jv_array_append(a, jv_number(p - jstr)); - p += idxlen; - } - jv_free(j); - jv_free(k); - return a; -} - -jv jv_string_split(jv j, jv sep) { - assert(jv_get_kind(j) == JV_KIND_STRING); - assert(jv_get_kind(sep) == JV_KIND_STRING); - const char *jstr = jv_string_value(j); - const char *jend = jstr + jv_string_length_bytes(jv_copy(j)); - const char *sepstr = jv_string_value(sep); - const char *p, *s; - int seplen = jv_string_length_bytes(jv_copy(sep)); - jv a = jv_array(); - - assert(jv_get_refcnt(a) == 1); - - if (seplen == 0) { - int c; - while ((jstr = jvp_utf8_next(jstr, jend, &c))) - a = jv_array_append(a, jv_string_append_codepoint(jv_string(""), c)); - } else { - for (p = jstr; p < jend; p = s + seplen) { - s = _jq_memmem(p, jend - p, sepstr, seplen); - if (s == NULL) - s = jend; - a = jv_array_append(a, jv_string_sized(p, s - p)); - // Add an empty string to denote that j ends on a sep - if (s + seplen == jend && seplen != 0) - a = jv_array_append(a, jv_string("")); - } - } - jv_free(j); - jv_free(sep); - return a; -} - -jv jv_string_explode(jv j) { - assert(jv_get_kind(j) == JV_KIND_STRING); - const char* i = jv_string_value(j); - int len = jv_string_length_bytes(jv_copy(j)); - const char* end = i + len; - jv a = jv_array_sized(len); - int c; - while ((i = jvp_utf8_next(i, end, &c))) - a = jv_array_append(a, jv_number(c)); - jv_free(j); - return a; -} - -jv jv_string_implode(jv j) { - assert(jv_get_kind(j) == JV_KIND_ARRAY); - int len = jv_array_length(jv_copy(j)); - jv s = jv_string_empty(len); - int i; - - assert(len >= 0); - - for (i = 0; i < len; i++) { - jv n = jv_array_get(jv_copy(j), i); - assert(jv_get_kind(n) == JV_KIND_NUMBER); - int nv = jv_number_value(n); - if (nv > 0x10FFFF) - nv = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER - s = jv_string_append_codepoint(s, nv); - } - - jv_free(j); - return s; -} - -unsigned long jv_string_hash(jv j) { - assert(jv_get_kind(j) == JV_KIND_STRING); - uint32_t hash = jvp_string_hash(j); - jv_free(j); - return hash; -} - -const char* jv_string_value(jv j) { - assert(jv_get_kind(j) == JV_KIND_STRING); - return jvp_string_ptr(j)->data; -} - -jv jv_string_slice(jv j, int start, int end) { - assert(jv_get_kind(j) == JV_KIND_STRING); - const char *s = jv_string_value(j); - int len = jv_string_length_bytes(jv_copy(j)); - int i; - const char *p, *e; - int c; - jv res; - - jvp_clamp_slice_params(len, &start, &end); - assert(0 <= start && start <= end && end <= len); - - /* Look for byte offset corresponding to start codepoints */ - for (p = s, i = 0; i < start; i++) { - p = jvp_utf8_next(p, s + len, &c); - if (p == NULL) { - jv_free(j); - return jv_string_empty(16); - } - if (c == -1) { - jv_free(j); - return jv_invalid_with_msg(jv_string("Invalid UTF-8 string")); - } - } - /* Look for byte offset corresponding to end codepoints */ - for (e = p; e != NULL && i < end; i++) { - e = jvp_utf8_next(e, s + len, &c); - if (e == NULL) { - e = s + len; - break; - } - if (c == -1) { - jv_free(j); - return jv_invalid_with_msg(jv_string("Invalid UTF-8 string")); - } - } - - /* - * NOTE: Ideally we should do here what jvp_array_slice() does instead - * of allocating a new string as we do! However, we assume NUL- - * terminated strings all over, and in the jv API, so for now we waste - * memory like a drunken navy programmer. There's probably nothing we - * can do about it. - */ - res = jv_string_sized(p, e - p); - jv_free(j); - return res; -} - -jv jv_string_concat(jv a, jv b) { - a = jvp_string_append(a, jv_string_value(b), - jvp_string_length(jvp_string_ptr(b))); - jv_free(b); - return a; -} - -jv jv_string_append_buf(jv a, const char* buf, int len) { - if (jvp_utf8_is_valid(buf, buf+len)) { - a = jvp_string_append(a, buf, len); - } else { - jv b = jvp_string_copy_replace_bad(buf, len); - a = jv_string_concat(a, b); - } - return a; -} - -jv jv_string_append_codepoint(jv a, uint32_t c) { - char buf[5]; - int len = jvp_utf8_encode(c, buf); - a = jvp_string_append(a, buf, len); - return a; -} - -jv jv_string_append_str(jv a, const char* str) { - return jv_string_append_buf(a, str, strlen(str)); -} - -jv jv_string_vfmt(const char* fmt, va_list ap) { - int size = 1024; - while (1) { - char* buf = jv_mem_alloc(size); - va_list ap2; - va_copy(ap2, ap); - int n = vsnprintf(buf, size, fmt, ap2); - va_end(ap2); - /* - * NOTE: here we support old vsnprintf()s that return -1 because the - * buffer is too small. - */ - if (n >= 0 && n < size) { - jv ret = jv_string_sized(buf, n); - jv_mem_free(buf); - return ret; - } else { - jv_mem_free(buf); - size = (n > 0) ? /* standard */ (n * 2) : /* not standard */ (size * 2); - } - } -} - -jv jv_string_fmt(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - jv res = jv_string_vfmt(fmt, args); - va_end(args); - return res; -} - -/* - * Objects (internal helpers) - */ - -struct object_slot { - int next; /* next slot with same hash, for collisions */ - uint32_t hash; - jv string; - jv value; -}; - -typedef struct { - jv_refcnt refcnt; - int next_free; - struct object_slot elements[]; -} jvp_object; - - -/* warning: nontrivial justification of alignment */ -static jv jvp_object_new(int size) { - // Allocates an object of (size) slots and (size*2) hash buckets. - - // size must be a power of two - assert(size > 0 && (size & (size - 1)) == 0); - - jvp_object* obj = jv_mem_alloc(sizeof(jvp_object) + - sizeof(struct object_slot) * size + - sizeof(int) * (size * 2)); - obj->refcnt.count = 1; - for (int i=0; ielements[i].next = i - 1; - obj->elements[i].string = JV_NULL; - obj->elements[i].hash = 0; - obj->elements[i].value = JV_NULL; - } - obj->next_free = 0; - int* hashbuckets = (int*)(&obj->elements[size]); - for (int i=0; irefcnt}}; - return r; -} - -static jvp_object* jvp_object_ptr(jv o) { - assert(jv_get_kind(o) == JV_KIND_OBJECT); - return (jvp_object*)o.u.ptr; -} - -static uint32_t jvp_object_mask(jv o) { - assert(jv_get_kind(o) == JV_KIND_OBJECT); - return (o.size * 2) - 1; -} - -static int jvp_object_size(jv o) { - assert(jv_get_kind(o) == JV_KIND_OBJECT); - return o.size; -} - -static int* jvp_object_buckets(jv o) { - return (int*)(&jvp_object_ptr(o)->elements[o.size]); -} - -static int* jvp_object_find_bucket(jv object, jv key) { - return jvp_object_buckets(object) + (jvp_object_mask(object) & jvp_string_hash(key)); -} - -static struct object_slot* jvp_object_get_slot(jv object, int slot) { - assert(slot == -1 || (slot >= 0 && slot < jvp_object_size(object))); - if (slot == -1) return 0; - else return &jvp_object_ptr(object)->elements[slot]; -} - -static struct object_slot* jvp_object_next_slot(jv object, struct object_slot* slot) { - return jvp_object_get_slot(object, slot->next); -} - -static struct object_slot* jvp_object_find_slot(jv object, jv keystr, int* bucket) { - uint32_t hash = jvp_string_hash(keystr); - for (struct object_slot* curr = jvp_object_get_slot(object, *bucket); - curr; - curr = jvp_object_next_slot(object, curr)) { - if (curr->hash == hash && jvp_string_equal(keystr, curr->string)) { - return curr; - } - } - return 0; -} - -static struct object_slot* jvp_object_add_slot(jv object, jv key, int* bucket) { - jvp_object* o = jvp_object_ptr(object); - int newslot_idx = o->next_free; - if (newslot_idx == jvp_object_size(object)) return 0; - struct object_slot* newslot = jvp_object_get_slot(object, newslot_idx); - o->next_free++; - newslot->next = *bucket; - *bucket = newslot_idx; - newslot->hash = jvp_string_hash(key); - newslot->string = key; - return newslot; -} - -static jv* jvp_object_read(jv object, jv key) { - assert(jv_get_kind(key) == JV_KIND_STRING); - int* bucket = jvp_object_find_bucket(object, key); - struct object_slot* slot = jvp_object_find_slot(object, key, bucket); - if (slot == 0) return 0; - else return &slot->value; -} - -static void jvp_object_free(jv o) { - assert(jv_get_kind(o) == JV_KIND_OBJECT); - if (jvp_refcnt_dec(o.u.ptr)) { - for (int i=0; istring) != JV_KIND_NULL) { - jvp_string_free(slot->string); - jv_free(slot->value); - } - } - jv_mem_free(jvp_object_ptr(o)); - } -} - -static jv jvp_object_rehash(jv object) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - assert(jvp_refcnt_unshared(object.u.ptr)); - int size = jvp_object_size(object); - jv new_object = jvp_object_new(size * 2); - for (int i=0; istring) == JV_KIND_NULL) continue; - int* new_bucket = jvp_object_find_bucket(new_object, slot->string); - assert(!jvp_object_find_slot(new_object, slot->string, new_bucket)); - struct object_slot* new_slot = jvp_object_add_slot(new_object, slot->string, new_bucket); - assert(new_slot); - new_slot->value = slot->value; - } - // references are transported, just drop the old table - jv_mem_free(jvp_object_ptr(object)); - return new_object; -} - -static jv jvp_object_unshare(jv object) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - if (jvp_refcnt_unshared(object.u.ptr)) - return object; - - jv new_object = jvp_object_new(jvp_object_size(object)); - jvp_object_ptr(new_object)->next_free = jvp_object_ptr(object)->next_free; - for (int i=0; istring) != JV_KIND_NULL) { - new_slot->string = jv_copy(old_slot->string); - new_slot->value = jv_copy(old_slot->value); - } - } - - int* old_buckets = jvp_object_buckets(object); - int* new_buckets = jvp_object_buckets(new_object); - memcpy(new_buckets, old_buckets, sizeof(int) * jvp_object_size(new_object)*2); - - jvp_object_free(object); - assert(jvp_refcnt_unshared(new_object.u.ptr)); - return new_object; -} - -static jv* jvp_object_write(jv* object, jv key) { - *object = jvp_object_unshare(*object); - int* bucket = jvp_object_find_bucket(*object, key); - struct object_slot* slot = jvp_object_find_slot(*object, key, bucket); - if (slot) { - // already has the key - jvp_string_free(key); - return &slot->value; - } - slot = jvp_object_add_slot(*object, key, bucket); - if (slot) { - slot->value = jv_invalid(); - } else { - *object = jvp_object_rehash(*object); - bucket = jvp_object_find_bucket(*object, key); - assert(!jvp_object_find_slot(*object, key, bucket)); - slot = jvp_object_add_slot(*object, key, bucket); - assert(slot); - slot->value = jv_invalid(); - } - return &slot->value; -} - -static int jvp_object_delete(jv* object, jv key) { - assert(jv_get_kind(key) == JV_KIND_STRING); - *object = jvp_object_unshare(*object); - int* bucket = jvp_object_find_bucket(*object, key); - int* prev_ptr = bucket; - uint32_t hash = jvp_string_hash(key); - for (struct object_slot* curr = jvp_object_get_slot(*object, *bucket); - curr; - curr = jvp_object_next_slot(*object, curr)) { - if (hash == curr->hash && jvp_string_equal(key, curr->string)) { - *prev_ptr = curr->next; - jvp_string_free(curr->string); - curr->string = JV_NULL; - jv_free(curr->value); - return 1; - } - prev_ptr = &curr->next; - } - return 0; -} - -static int jvp_object_length(jv object) { - int n = 0; - for (int i=0; istring) != JV_KIND_NULL) n++; - } - return n; -} - -static int jvp_object_equal(jv o1, jv o2) { - int len2 = jvp_object_length(o2); - int len1 = 0; - for (int i=0; istring) == JV_KIND_NULL) continue; - jv* slot2 = jvp_object_read(o2, slot->string); - if (!slot2) return 0; - // FIXME: do less refcounting here - if (!jv_equal(jv_copy(slot->value), jv_copy(*slot2))) return 0; - len1++; - } - return len1 == len2; -} - -/* - * Objects (public interface) - */ -#define DEFAULT_OBJECT_SIZE 8 -jv jv_object() { - return jvp_object_new(8); -} - -jv jv_object_get(jv object, jv key) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - assert(jv_get_kind(key) == JV_KIND_STRING); - jv* slot = jvp_object_read(object, key); - jv val; - if (slot) { - val = jv_copy(*slot); - } else { - val = jv_invalid(); - } - jv_free(object); - jv_free(key); - return val; -} - -jv jv_object_set(jv object, jv key, jv value) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - assert(jv_get_kind(key) == JV_KIND_STRING); - // copy/free of object, key, value coalesced - jv* slot = jvp_object_write(&object, key); - jv_free(*slot); - *slot = value; - return object; -} - -jv jv_object_delete(jv object, jv key) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - assert(jv_get_kind(key) == JV_KIND_STRING); - jvp_object_delete(&object, key); - jv_free(key); - return object; -} - -int jv_object_length(jv object) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - int n = jvp_object_length(object); - jv_free(object); - return n; -} - -jv jv_object_merge(jv a, jv b) { - assert(jv_get_kind(a) == JV_KIND_OBJECT); - jv_object_foreach(b, k, v) { - a = jv_object_set(a, k, v); - } - jv_free(b); - return a; -} - -jv jv_object_merge_recursive(jv a, jv b) { - assert(jv_get_kind(a) == JV_KIND_OBJECT); - assert(jv_get_kind(b) == JV_KIND_OBJECT); - - jv_object_foreach(b, k, v) { - jv elem = jv_object_get(jv_copy(a), jv_copy(k)); - if (jv_is_valid(elem) && - jv_get_kind(elem) == JV_KIND_OBJECT && - jv_get_kind(v) == JV_KIND_OBJECT) { - a = jv_object_set(a, k, jv_object_merge_recursive(elem, v)); - } else { - jv_free(elem); - a = jv_object_set(a, k, v); - } - } - jv_free(b); - return a; -} - -int jv_object_contains(jv a, jv b) { - assert(jv_get_kind(a) == JV_KIND_OBJECT); - assert(jv_get_kind(b) == JV_KIND_OBJECT); - int r = 1; - - jv_object_foreach(b, key, b_val) { - jv a_val = jv_object_get(jv_copy(a), jv_copy(key)); - - r = jv_contains(a_val, b_val); - jv_free(key); - - if (!r) break; - } - - jv_free(a); - jv_free(b); - return r; -} - -/* - * Object iteration (internal helpers) - */ - -enum { ITER_FINISHED = -2 }; - -int jv_object_iter_valid(jv object, int i) { - return i != ITER_FINISHED; -} - -int jv_object_iter(jv object) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - return jv_object_iter_next(object, -1); -} - -int jv_object_iter_next(jv object, int iter) { - assert(jv_get_kind(object) == JV_KIND_OBJECT); - assert(iter != ITER_FINISHED); - struct object_slot* slot; - do { - iter++; - if (iter >= jvp_object_size(object)) - return ITER_FINISHED; - slot = jvp_object_get_slot(object, iter); - } while (jv_get_kind(slot->string) == JV_KIND_NULL); - assert(jv_get_kind(jvp_object_get_slot(object,iter)->string) - == JV_KIND_STRING); - return iter; -} - -jv jv_object_iter_key(jv object, int iter) { - jv s = jvp_object_get_slot(object, iter)->string; - assert(jv_get_kind(s) == JV_KIND_STRING); - return jv_copy(s); -} - -jv jv_object_iter_value(jv object, int iter) { - return jv_copy(jvp_object_get_slot(object, iter)->value); -} - -/* - * Memory management - */ -jv jv_copy(jv j) { - if (jv_get_kind(j) == JV_KIND_ARRAY || - jv_get_kind(j) == JV_KIND_STRING || - jv_get_kind(j) == JV_KIND_OBJECT || - (jv_get_kind(j) == JV_KIND_INVALID && j.u.ptr != 0)) { - jvp_refcnt_inc(j.u.ptr); - } - return j; -} - -void jv_free(jv j) { - if (jv_get_kind(j) == JV_KIND_ARRAY) { - jvp_array_free(j); - } else if (jv_get_kind(j) == JV_KIND_STRING) { - jvp_string_free(j); - } else if (jv_get_kind(j) == JV_KIND_OBJECT) { - jvp_object_free(j); - } else if (jv_get_kind(j) == JV_KIND_INVALID) { - jvp_invalid_free(j); - } -} - -int jv_get_refcnt(jv j) { - switch (jv_get_kind(j)) { - case JV_KIND_ARRAY: - case JV_KIND_STRING: - case JV_KIND_OBJECT: - return j.u.ptr->count; - default: - return 1; - } -} - -/* - * Higher-level operations - */ - -int jv_equal(jv a, jv b) { - int r; - if (jv_get_kind(a) != jv_get_kind(b)) { - r = 0; - } else if (jv_get_kind(a) == JV_KIND_NUMBER) { - r = jv_number_value(a) == jv_number_value(b); - } else if (a.kind_flags == b.kind_flags && - a.size == b.size && - a.u.ptr == b.u.ptr) { - r = 1; - } else { - switch (jv_get_kind(a)) { - case JV_KIND_ARRAY: - r = jvp_array_equal(a, b); - break; - case JV_KIND_STRING: - r = jvp_string_equal(a, b); - break; - case JV_KIND_OBJECT: - r = jvp_object_equal(a, b); - break; - default: - r = 1; - break; - } - } - jv_free(a); - jv_free(b); - return r; -} - -int jv_identical(jv a, jv b) { - int r; - if (a.kind_flags != b.kind_flags - || a.offset != b.offset - || a.size != b.size) { - r = 0; - } else { - switch (jv_get_kind(a)) { - case JV_KIND_ARRAY: - case JV_KIND_STRING: - case JV_KIND_OBJECT: - r = a.u.ptr == b.u.ptr; - break; - case JV_KIND_NUMBER: - r = memcmp(&a.u.number, &b.u.number, sizeof(a.u.number)) == 0; - break; - default: - r = 1; - break; - } - } - jv_free(a); - jv_free(b); - return r; -} - -int jv_contains(jv a, jv b) { - int r = 1; - if (jv_get_kind(a) != jv_get_kind(b)) { - r = 0; - } else if (jv_get_kind(a) == JV_KIND_OBJECT) { - r = jv_object_contains(jv_copy(a), jv_copy(b)); - } else if (jv_get_kind(a) == JV_KIND_ARRAY) { - r = jv_array_contains(jv_copy(a), jv_copy(b)); - } else if (jv_get_kind(a) == JV_KIND_STRING) { - r = strstr(jv_string_value(a), jv_string_value(b)) != 0; - } else { - r = jv_equal(jv_copy(a), jv_copy(b)); - } - jv_free(a); - jv_free(b); - return r; -} diff --git a/src/jq/jv.h b/src/jq/jv.h deleted file mode 100644 index 9e74c9d..0000000 --- a/src/jq/jv.h +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef JV_H -#define JV_H - -#include -#include -#include - -typedef enum { - JV_KIND_INVALID, - JV_KIND_NULL, - JV_KIND_FALSE, - JV_KIND_TRUE, - JV_KIND_NUMBER, - JV_KIND_STRING, - JV_KIND_ARRAY, - JV_KIND_OBJECT -} jv_kind; - -struct jv_refcnt; - -/* All of the fields of this struct are private. - Really. Do not play with them. */ -typedef struct { - unsigned char kind_flags; - unsigned char pad_; - unsigned short offset; /* array offsets */ - int size; - union { - struct jv_refcnt* ptr; - double number; - } u; -} jv; - -/* - * All jv_* functions consume (decref) input and produce (incref) output - * Except jv_copy - */ - -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; } - -jv jv_copy(jv); -void jv_free(jv); - -int jv_get_refcnt(jv); - -int jv_equal(jv, jv); -int jv_identical(jv, jv); -int jv_contains(jv, jv); - -jv jv_invalid(void); -jv jv_invalid_with_msg(jv); -jv jv_invalid_get_msg(jv); -int jv_invalid_has_msg(jv); - - -jv jv_null(void); -jv jv_true(void); -jv jv_false(void); -jv jv_bool(int); - -jv jv_number(double); -double jv_number_value(jv); -int jv_is_integer(jv); - -jv jv_array(void); -jv jv_array_sized(int); -int jv_array_length(jv); -jv jv_array_get(jv, int); -jv jv_array_set(jv, int, jv); -jv jv_array_append(jv, jv); -jv jv_array_concat(jv, jv); -jv jv_array_slice(jv, int, int); -jv jv_array_indexes(jv, jv); -#define jv_array_foreach(a, i, x) \ - for (int jv_len__ = jv_array_length(jv_copy(a)), i=0, jv_j__ = 1; \ - jv_j__; jv_j__ = 0) \ - for (jv x; \ - i < jv_len__ ? \ - (x = jv_array_get(jv_copy(a), i), 1) : 0; \ - i++) - -#define JV_ARRAY_1(e) (jv_array_append(jv_array(),e)) -#define JV_ARRAY_2(e1,e2) (jv_array_append(JV_ARRAY_1(e1),e2)) -#define JV_ARRAY_3(e1,e2,e3) (jv_array_append(JV_ARRAY_2(e1,e2),e3)) -#define JV_ARRAY_4(e1,e2,e3,e4) (jv_array_append(JV_ARRAY_3(e1,e2,e3),e4)) -#define JV_ARRAY_5(e1,e2,e3,e4,e5) (jv_array_append(JV_ARRAY_4(e1,e2,e3,e4),e5)) -#define JV_ARRAY_6(e1,e2,e3,e4,e5,e6) (jv_array_append(JV_ARRAY_5(e1,e2,e3,e4,e5),e6)) -#define JV_ARRAY_7(e1,e2,e3,e4,e5,e6,e7) (jv_array_append(JV_ARRAY_6(e1,e2,e3,e4,e5,e6),e7)) -#define JV_ARRAY_8(e1,e2,e3,e4,e5,e6,e7,e8) (jv_array_append(JV_ARRAY_7(e1,e2,e3,e4,e5,e6,e7),e8)) -#define JV_ARRAY_9(e1,e2,e3,e4,e5,e6,e7,e8,e9) (jv_array_append(JV_ARRAY_8(e1,e2,e3,e4,e5,e6,e7,e8),e9)) -#define JV_ARRAY_IDX(_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) NAME -#define JV_ARRAY(...) \ - JV_ARRAY_IDX(__VA_ARGS__, JV_ARRAY_9, JV_ARRAY_8, JV_ARRAY_7, JV_ARRAY_6, JV_ARRAY_5, JV_ARRAY_4, JV_ARRAY_3, JV_ARRAY_2, JV_ARRAY_1, dummy)(__VA_ARGS__) - -#ifdef __GNUC__ -#define JV_PRINTF_LIKE(fmt_arg_num, args_num) \ - __attribute__ ((__format__( __printf__, fmt_arg_num, args_num))) -#define JV_VPRINTF_LIKE(fmt_arg_num) \ - __attribute__ ((__format__( __printf__, fmt_arg_num, 0))) -#endif - - -jv jv_string(const char*); -jv jv_string_sized(const char*, int); -jv jv_string_empty(int len); -int jv_string_length_bytes(jv); -int jv_string_length_codepoints(jv); -unsigned long jv_string_hash(jv); -const char* jv_string_value(jv); -jv jv_string_indexes(jv j, jv k); -jv jv_string_slice(jv j, int start, int end); -jv jv_string_concat(jv, jv); -jv jv_string_vfmt(const char*, va_list) JV_VPRINTF_LIKE(1); -jv jv_string_fmt(const char*, ...) JV_PRINTF_LIKE(1, 2); -jv jv_string_append_codepoint(jv a, uint32_t c); -jv jv_string_append_buf(jv a, const char* buf, int len); -jv jv_string_append_str(jv a, const char* str); -jv jv_string_split(jv j, jv sep); -jv jv_string_explode(jv j); -jv jv_string_implode(jv j); - -jv jv_object(void); -jv jv_object_get(jv object, jv key); -jv jv_object_set(jv object, jv key, jv value); -jv jv_object_delete(jv object, jv key); -int jv_object_length(jv object); -jv jv_object_merge(jv, jv); -jv jv_object_merge_recursive(jv, jv); - -int jv_object_iter(jv); -int jv_object_iter_next(jv, int); -int jv_object_iter_valid(jv, int); -jv jv_object_iter_key(jv, int); -jv jv_object_iter_value(jv, int); -#define jv_object_foreach(t, k, v) \ - for (int jv_i__ = jv_object_iter(t), jv_j__ = 1; jv_j__; jv_j__ = 0) \ - for (jv k, v; \ - jv_object_iter_valid((t), jv_i__) ? \ - (k = jv_object_iter_key(t, jv_i__), \ - v = jv_object_iter_value(t, jv_i__), \ - 1) \ - : 0; \ - jv_i__ = jv_object_iter_next(t, jv_i__)) \ - -#define JV_OBJECT_1(k1) (jv_object_set(jv_object(),(k1),jv_null())) -#define JV_OBJECT_2(k1,v1) (jv_object_set(jv_object(),(k1),(v1))) -#define JV_OBJECT_3(k1,v1,k2) (jv_object_set(JV_OBJECT_2((k1),(v1)),(k2),jv_null())) -#define JV_OBJECT_4(k1,v1,k2,v2) (jv_object_set(JV_OBJECT_2((k1),(v1)),(k2),(v2))) -#define JV_OBJECT_5(k1,v1,k2,v2,k3) (jv_object_set(JV_OBJECT_4((k1),(v1),(k2),(v2)),(k3),jv_null())) -#define JV_OBJECT_6(k1,v1,k2,v2,k3,v3) (jv_object_set(JV_OBJECT_4((k1),(v1),(k2),(v2)),(k3),(v3))) -#define JV_OBJECT_7(k1,v1,k2,v2,k3,v3,k4) (jv_object_set(JV_OBJECT_6((k1),(v1),(k2),(v2),(k3),(v3)),(k4),jv_null())) -#define JV_OBJECT_8(k1,v1,k2,v2,k3,v3,k4,v4) (jv_object_set(JV_OBJECT_6((k1),(v1),(k2),(v2),(k3),(v3)),(k4),(v4))) -#define JV_OBJECT_9(k1,v1,k2,v2,k3,v3,k4,v4,k5) \ - (jv_object_set(JV_OBJECT_8((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4)),(k5),jv_null())) -#define JV_OBJECT_10(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5) \ - (jv_object_set(JV_OBJECT_8((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4)),(k5),(v5))) -#define JV_OBJECT_11(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6) \ - (jv_object_set(JV_OBJECT_10((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5)),(k6),jv_null())) -#define JV_OBJECT_12(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6) \ - (jv_object_set(JV_OBJECT_10((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5)),(k6),(v6))) -#define JV_OBJECT_13(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7) \ - (jv_object_set(JV_OBJECT_12((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6)),(k7),jv_null())) -#define JV_OBJECT_14(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7) \ - (jv_object_set(JV_OBJECT_12((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6)),(k7),(v7))) -#define JV_OBJECT_15(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8) \ - (jv_object_set(JV_OBJECT_14((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7)),(k8),jv_null())) -#define JV_OBJECT_16(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8) \ - (jv_object_set(JV_OBJECT_14((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7)),(k8),(v8))) -#define JV_OBJECT_17(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9) \ - (jv_object_set(JV_OBJECT_16((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7),(k8),(v8)),(k9),jv_null())) -#define JV_OBJECT_18(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9) \ - (jv_object_set(JV_OBJECT_16((k1),(v1),(k2),(v2),(k3),(v3),(k4),(v4),(k5),(v5),(k6),(v6),(k7),(v7),(k8),(v8)),(k9),(v9))) -#define JV_OBJECT_IDX(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,NAME,...) NAME -#define JV_OBJECT(...) \ - JV_OBJECT_IDX(__VA_ARGS__, \ - JV_OBJECT_18, JV_OBJECT_17, JV_OBJECT_16, JV_OBJECT_15, \ - JV_OBJECT_14, JV_OBJECT_13, JV_OBJECT_12, JV_OBJECT_11, \ - JV_OBJECT_10, JV_OBJECT_9, JV_OBJECT_8, JV_OBJECT_7, \ - JV_OBJECT_6, JV_OBJECT_5, JV_OBJECT_4, JV_OBJECT_3, \ - JV_OBJECT_2, JV_OBJECT_1)(__VA_ARGS__) - - - -int jv_get_refcnt(jv); - -enum jv_print_flags { - JV_PRINT_PRETTY = 1, - JV_PRINT_ASCII = 2, - JV_PRINT_COLOR = 4, - JV_PRINT_SORTED = 8, - JV_PRINT_INVALID = 16, - JV_PRINT_REFCOUNT = 32, - JV_PRINT_TAB = 64, - JV_PRINT_ISATTY = 128, - JV_PRINT_SPACE0 = 256, - JV_PRINT_SPACE1 = 512, - JV_PRINT_SPACE2 = 1024, -}; -#define JV_PRINT_INDENT_FLAGS(n) \ - ((n) < 0 || (n) > 7 ? JV_PRINT_TAB | JV_PRINT_PRETTY : (n) == 0 ? 0 : (n) << 8 | JV_PRINT_PRETTY) -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 { - JV_PARSE_SEQ = 1, - JV_PARSE_STREAMING = 2, - JV_PARSE_STREAM_ERRORS = 4, -}; - -jv jv_parse(const char* string); -jv jv_parse_sized(const char* string, int length); - -typedef void (*jv_nomem_handler_f)(void *); -void jv_nomem_handler(jv_nomem_handler_f, void *); - -jv jv_load_file(const char *, int); - -typedef struct jv_parser jv_parser; -jv_parser* jv_parser_new(int); -void jv_parser_set_buf(jv_parser*, const char*, int, int); -int jv_parser_remaining(jv_parser*); -jv jv_parser_next(jv_parser*); -void jv_parser_free(jv_parser*); - -jv jv_get(jv, jv); -jv jv_set(jv, jv, jv); -jv jv_has(jv, jv); -jv jv_setpath(jv, jv, jv); -jv jv_getpath(jv, jv); -jv jv_delpaths(jv, jv); -jv jv_keys(jv /*object or array*/); -jv jv_keys_unsorted(jv /*object or array*/); -int jv_cmp(jv, jv); -jv jv_group(jv, jv); -jv jv_sort(jv, jv); - - -#endif - - -/* - -true/false/null: -check kind - -number: -introduce/eliminate jv -to integer - -array: -copy -free -slice -index -update - -updateslice? - - - */ diff --git a/src/jq/jv_alloc.c b/src/jq/jv_alloc.c deleted file mode 100644 index fd7b257..0000000 --- a/src/jq/jv_alloc.c +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include -#include "jv_alloc.h" - -struct nomem_handler { - jv_nomem_handler_f handler; - void *data; -}; - -#if !defined(HAVE_PTHREAD_KEY_CREATE) || \ - !defined(HAVE_PTHREAD_ONCE) || \ - !defined(HAVE_ATEXIT) - -/* Try thread-local storage? */ - -#ifdef _MSC_VER -/* Visual C++: yes */ -static __declspec(thread) struct nomem_handler nomem_handler; -#define USE_TLS -#else -#ifdef HAVE___THREAD -/* GCC and friends: yes */ -static __thread struct nomem_handler nomem_handler; -#define USE_TLS -#endif /* HAVE___THREAD */ -#endif /* _MSC_VER */ - -#endif /* !HAVE_PTHREAD_KEY_CREATE */ - -#ifdef USE_TLS -void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { - nomem_handler.handler = handler; -} - -static void memory_exhausted() { - if (nomem_handler.handler) - nomem_handler.handler(nomem_handler.data); // Maybe handler() will longjmp() to safety - // Or not - fprintf(stderr, "error: cannot allocate memory\n"); - abort(); -} -#else /* USE_TLS */ - -#ifdef HAVE_PTHREAD_KEY_CREATE -#include - -pthread_key_t nomem_handler_key; -pthread_once_t mem_once = PTHREAD_ONCE_INIT; - -static void tsd_fini(void) { - struct nomem_handler *nomem_handler; - nomem_handler = pthread_getspecific(nomem_handler_key); - if (nomem_handler) { - (void) pthread_setspecific(nomem_handler_key, NULL); - free(nomem_handler); - } -} - -static void tsd_init(void) { - if (pthread_key_create(&nomem_handler_key, NULL) != 0) { - fprintf(stderr, "error: cannot create thread specific key"); - abort(); - } - if (atexit(tsd_fini) != 0) { - fprintf(stderr, "error: cannot set an exit handler"); - abort(); - } - struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler)); - if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) { - fprintf(stderr, "error: cannot set thread specific data"); - abort(); - } -} - -void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { - pthread_once(&mem_once, tsd_init); // cannot fail - struct nomem_handler *nomem_handler; - - nomem_handler = pthread_getspecific(nomem_handler_key); - if (nomem_handler == NULL) { - handler(data); - fprintf(stderr, "error: cannot allocate memory\n"); - abort(); - } - nomem_handler->handler = handler; - nomem_handler->data = data; -} - -static void memory_exhausted() { - struct nomem_handler *nomem_handler; - - pthread_once(&mem_once, tsd_init); - nomem_handler = pthread_getspecific(nomem_handler_key); - if (nomem_handler) - nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety - // Or not - fprintf(stderr, "error: cannot allocate memory\n"); - abort(); -} - -#else - -/* No thread-local storage of any kind that we know how to handle */ - -static struct nomem_handler nomem_handler; -void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { - nomem_handler.handler = handler; - nomem_handler.data = data; -} - -static void memory_exhausted() { - fprintf(stderr, "error: cannot allocate memory\n"); - abort(); -} - -#endif /* HAVE_PTHREAD_KEY_CREATE */ -#endif /* USE_TLS */ - - -void* jv_mem_alloc(size_t sz) { - void* p = malloc(sz); - if (!p) { - memory_exhausted(); - } - return p; -} - -void* jv_mem_alloc_unguarded(size_t sz) { - return malloc(sz); -} - -void* jv_mem_calloc(size_t nemb, size_t sz) { - void* p = calloc(nemb, sz); - if (!p) { - memory_exhausted(); - } - return p; -} - -void* jv_mem_calloc_unguarded(size_t nemb, size_t sz) { - return calloc(nemb, sz); -} - -char* jv_mem_strdup(const char *s) { - char *p = strdup(s); - if (!p) { - memory_exhausted(); - } - return p; -} - -char* jv_mem_strdup_unguarded(const char *s) { - return strdup(s); -} - -void jv_mem_free(void* p) { - free(p); -} - -void* jv_mem_realloc(void* p, size_t sz) { - p = realloc(p, sz); - if (!p) { - memory_exhausted(); - } - return p; -} - -#ifndef NDEBUG -volatile char jv_mem_uninitialised; -__attribute__((constructor)) void jv_mem_uninit_setup(){ - // ignore warning that this reads uninitialized memory - that's the point! -#ifndef __clang_analyzer__ - char* p = malloc(1); - jv_mem_uninitialised = *p; - free(p); -#endif -} -#endif diff --git a/src/jq/jv_alloc.h b/src/jq/jv_alloc.h deleted file mode 100644 index 0e38379..0000000 --- a/src/jq/jv_alloc.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef JV_ALLOC_H -#define JV_ALLOC_H - -#include -#include "jv.h" - -#ifndef NDEBUG -extern volatile char jv_mem_uninitialised; -#endif - -static void jv_mem_invalidate(void* mem, size_t n) { -#ifndef NDEBUG - char* m = mem; - while (n--) *m++ ^= jv_mem_uninitialised ^ jv_mem_uninitialised; -#endif -} - -void* jv_mem_alloc(size_t); -void* jv_mem_alloc_unguarded(size_t); -void* jv_mem_calloc(size_t, size_t); -void* jv_mem_calloc_unguarded(size_t, size_t); -char* jv_mem_strdup(const char *); -char* jv_mem_strdup_unguarded(const char *); -void jv_mem_free(void*); -__attribute__((warn_unused_result)) void* jv_mem_realloc(void*, size_t); - -#endif diff --git a/src/jq/jv_aux.c b/src/jq/jv_aux.c deleted file mode 100644 index db2e0ef..0000000 --- a/src/jq/jv_aux.c +++ /dev/null @@ -1,643 +0,0 @@ -#include -#include -#include -#include "jv_alloc.h" - -static int parse_slice(jv j, jv slice, int* pstart, int* pend) { - // Array slices - jv start_jv = jv_object_get(jv_copy(slice), jv_string("start")); - jv end_jv = jv_object_get(slice, jv_string("end")); - if (jv_get_kind(start_jv) == JV_KIND_NULL) { - jv_free(start_jv); - start_jv = jv_number(0); - } - int len; - if (jv_get_kind(j) == JV_KIND_ARRAY) { - len = jv_array_length(j); - } else if (jv_get_kind(j) == JV_KIND_STRING) { - len = jv_string_length_codepoints(j); - } else { - jv_free(j); - return 0; - } - if (jv_get_kind(end_jv) == JV_KIND_NULL) { - jv_free(end_jv); - end_jv = jv_number(len); - } - if (jv_get_kind(start_jv) != JV_KIND_NUMBER || - jv_get_kind(end_jv) != JV_KIND_NUMBER) { - jv_free(start_jv); - jv_free(end_jv); - return 0; - } else { - double dstart = jv_number_value(start_jv); - double dend = jv_number_value(end_jv); - if (dstart < 0) dstart += len; - if (dend < 0) dend += len; - if (dstart < 0) dstart = 0; - if (dstart > len) dstart = len; - - int start = (int)dstart; - int end = (dend > len) ? len : (int)dend; - // Ends are exclusive but e.g. 1 < 1.5 so :1.5 should be :2 not :1 - if(end < dend) end += 1; - - if (end > len) end = len; - if (end < start) end = start; - assert(0 <= start && start <= end && end <= len); - *pstart = start; - *pend = end; - return 1; - } -} - -jv jv_get(jv t, jv k) { - jv v; - if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { - v = jv_object_get(t, k); - if (!jv_is_valid(v)) { - jv_free(v); - v = jv_null(); - } - } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { - if(jv_is_integer(k)){ - int idx = (int)jv_number_value(k); - if (idx < 0) - idx += jv_array_length(jv_copy(t)); - v = jv_array_get(t, idx); - if (!jv_is_valid(v)) { - jv_free(v); - v = jv_null(); - } - } else { - jv_free(t); - jv_free(k); - v = jv_null(); - } - } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_OBJECT) { - int start, end; - if (parse_slice(jv_copy(t), k, &start, &end)) { - v = jv_array_slice(t, start, end); - } else { - jv_free(t); - v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers")); - } - } else if (jv_get_kind(t) == JV_KIND_STRING && jv_get_kind(k) == JV_KIND_OBJECT) { - int start, end; - if (parse_slice(jv_copy(t), k, &start, &end)) { - v = jv_string_slice(t, start, end); - } else { - v = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an string slice must be numbers")); - jv_free(t); - } - } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_ARRAY) { - v = jv_array_indexes(t, k); - } else if (jv_get_kind(t) == JV_KIND_NULL && - (jv_get_kind(k) == JV_KIND_STRING || - jv_get_kind(k) == JV_KIND_NUMBER || - jv_get_kind(k) == JV_KIND_OBJECT)) { - jv_free(t); - jv_free(k); - v = jv_null(); - } else { - /* - * If k is a short string it's probably from a jq .foo expression or - * similar, in which case putting it in the invalid msg may help the - * user. The length 30 is arbitrary. - */ - if (jv_get_kind(k) == JV_KIND_STRING && jv_string_length_bytes(jv_copy(k)) < 30) { - v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with string \"%s\"", - jv_kind_name(jv_get_kind(t)), - jv_string_value(k))); - } else { - v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with %s", - jv_kind_name(jv_get_kind(t)), - jv_kind_name(jv_get_kind(k)))); - } - jv_free(t); - jv_free(k); - } - return v; -} - -jv jv_set(jv t, jv k, jv v) { - if (!jv_is_valid(v)) { - jv_free(t); - jv_free(k); - return v; - } - int isnull = jv_get_kind(t) == JV_KIND_NULL; - if (jv_get_kind(k) == JV_KIND_STRING && - (jv_get_kind(t) == JV_KIND_OBJECT || isnull)) { - if (isnull) t = jv_object(); - t = jv_object_set(t, k, v); - } else if (jv_get_kind(k) == JV_KIND_NUMBER && - (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) { - if (isnull) t = jv_array(); - t = jv_array_set(t, (int)jv_number_value(k), v); - } else if (jv_get_kind(k) == JV_KIND_OBJECT && - (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) { - if (isnull) t = jv_array(); - int start, end; - if (parse_slice(jv_copy(t), k, &start, &end)) { - if (jv_get_kind(v) == JV_KIND_ARRAY) { - int array_len = jv_array_length(jv_copy(t)); - assert(0 <= start && start <= end && end <= array_len); - int slice_len = end - start; - int insert_len = jv_array_length(jv_copy(v)); - if (slice_len < insert_len) { - // array is growing - int shift = insert_len - slice_len; - for (int i = array_len - 1; i >= end; i--) { - t = jv_array_set(t, i + shift, jv_array_get(jv_copy(t), i)); - } - } else if (slice_len > insert_len) { - // array is shrinking - int shift = slice_len - insert_len; - for (int i = end; i < array_len; i++) { - t = jv_array_set(t, i - shift, jv_array_get(jv_copy(t), i)); - } - t = jv_array_slice(t, 0, array_len - shift); - } - for (int i=0; i < insert_len; i++) { - t = jv_array_set(t, start + i, jv_array_get(jv_copy(v), i)); - } - jv_free(v); - } else { - jv_free(t); - jv_free(v); - t = jv_invalid_with_msg(jv_string_fmt("A slice of an array can only be assigned another array")); - } - } else { - jv_free(t); - jv_free(v); - t = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers")); - } - } else { - jv err = jv_invalid_with_msg(jv_string_fmt("Cannot update field at %s index of %s", - jv_kind_name(jv_get_kind(k)), - jv_kind_name(jv_get_kind(t)))); - jv_free(t); - jv_free(k); - jv_free(v); - t = err; - } - return t; -} - -jv jv_has(jv t, jv k) { - assert(jv_is_valid(t)); - assert(jv_is_valid(k)); - jv ret; - if (jv_get_kind(t) == JV_KIND_NULL) { - jv_free(t); - jv_free(k); - ret = jv_false(); - } else if (jv_get_kind(t) == JV_KIND_OBJECT && - jv_get_kind(k) == JV_KIND_STRING) { - jv elem = jv_object_get(t, k); - ret = jv_bool(jv_is_valid(elem)); - jv_free(elem); - } else if (jv_get_kind(t) == JV_KIND_ARRAY && - jv_get_kind(k) == JV_KIND_NUMBER) { - jv elem = jv_array_get(t, (int)jv_number_value(k)); - ret = jv_bool(jv_is_valid(elem)); - jv_free(elem); - } else { - ret = jv_invalid_with_msg(jv_string_fmt("Cannot check whether %s has a %s key", - jv_kind_name(jv_get_kind(t)), - jv_kind_name(jv_get_kind(k)))); - jv_free(t); - jv_free(k); - } - return ret; -} - -// assumes keys is a sorted array -static jv jv_dels(jv t, jv keys) { - assert(jv_get_kind(keys) == JV_KIND_ARRAY); - assert(jv_is_valid(t)); - - if (jv_get_kind(t) == JV_KIND_NULL || jv_array_length(jv_copy(keys)) == 0) { - // no change - } else if (jv_get_kind(t) == JV_KIND_ARRAY) { - // extract slices, they must be handled differently - jv neg_keys = jv_array(); - jv nonneg_keys = jv_array(); - jv new_array = jv_array(); - jv starts = jv_array(), ends = jv_array(); - jv_array_foreach(keys, i, key) { - if (jv_get_kind(key) == JV_KIND_NUMBER) { - if (jv_number_value(key) < 0) { - neg_keys = jv_array_append(neg_keys, key); - } else { - nonneg_keys = jv_array_append(nonneg_keys, key); - } - } else if (jv_get_kind(key) == JV_KIND_OBJECT) { - int start, end; - if (parse_slice(jv_copy(t), key, &start, &end)) { - starts = jv_array_append(starts, jv_number(start)); - ends = jv_array_append(ends, jv_number(end)); - } else { - jv_free(new_array); - new_array = jv_invalid_with_msg(jv_string_fmt("Start and end indices of an array slice must be numbers")); - goto arr_out; - } - } else { - jv_free(new_array); - new_array = jv_invalid_with_msg(jv_string_fmt("Cannot delete %s element of array", - jv_kind_name(jv_get_kind(key)))); - jv_free(key); - goto arr_out; - } - } - - int neg_idx = 0; - int nonneg_idx = 0; - int len = jv_array_length(jv_copy(t)); - jv_array_foreach(t, i, elem) { - int del = 0; - while (neg_idx < jv_array_length(jv_copy(neg_keys))) { - int delidx = len + (int)jv_number_value(jv_array_get(jv_copy(neg_keys), neg_idx)); - if (i == delidx) { - del = 1; - } - if (i < delidx) { - break; - } - neg_idx++; - } - while (nonneg_idx < jv_array_length(jv_copy(nonneg_keys))) { - int delidx = (int)jv_number_value(jv_array_get(jv_copy(nonneg_keys), nonneg_idx)); - if (i == delidx) { - del = 1; - } - if (i < delidx) { - break; - } - nonneg_idx++; - } - for (int sidx=0; !del && sidx start); - int delkey = jv_array_length(jv_array_get(jv_copy(paths), i)) == start + 1; - jv key = jv_array_get(jv_array_get(jv_copy(paths), i), start); - while (j < jv_array_length(jv_copy(paths)) && - jv_equal(jv_copy(key), jv_array_get(jv_array_get(jv_copy(paths), j), start))) - j++; - // if i <= entry < j, then entry starts with key - if (delkey) { - // deleting this entire key, we don't care about any more specific deletions - delkeys = jv_array_append(delkeys, key); - } else { - // deleting certain sub-parts of this key - jv subobject = jv_get(jv_copy(object), jv_copy(key)); - if (!jv_is_valid(subobject)) { - jv_free(key); - jv_free(object); - object = subobject; - break; - } else if (jv_get_kind(subobject) == JV_KIND_NULL) { - jv_free(key); - jv_free(subobject); - } else { - jv newsubobject = delpaths_sorted(subobject, jv_array_slice(jv_copy(paths), i, j), start+1); - if (!jv_is_valid(newsubobject)) { - jv_free(key); - jv_free(object); - object = newsubobject; - break; - } - object = jv_set(object, key, newsubobject); - } - if (!jv_is_valid(object)) break; - } - i = j; - } - jv_free(paths); - if (jv_is_valid(object)) - object = jv_dels(object, delkeys); - else - jv_free(delkeys); - return object; -} - -jv jv_delpaths(jv object, jv paths) { - if (jv_get_kind(paths) != JV_KIND_ARRAY) { - jv_free(object); - jv_free(paths); - return jv_invalid_with_msg(jv_string("Paths must be specified as an array")); - } - paths = jv_sort(paths, jv_copy(paths)); - jv_array_foreach(paths, i, elem) { - if (jv_get_kind(elem) != JV_KIND_ARRAY) { - jv_free(object); - jv_free(paths); - jv err = jv_invalid_with_msg(jv_string_fmt("Path must be specified as array, not %s", - jv_kind_name(jv_get_kind(elem)))); - jv_free(elem); - return err; - } - jv_free(elem); - } - if (jv_array_length(jv_copy(paths)) == 0) { - // nothing is being deleted - jv_free(paths); - return object; - } - if (jv_array_length(jv_array_get(jv_copy(paths), 0)) == 0) { - // everything is being deleted - jv_free(paths); - jv_free(object); - return jv_null(); - } - return delpaths_sorted(object, paths, 0); -} - - -static int string_cmp(const void* pa, const void* pb){ - const jv* a = pa; - const jv* b = pb; - int lena = jv_string_length_bytes(jv_copy(*a)); - int lenb = jv_string_length_bytes(jv_copy(*b)); - int minlen = lena < lenb ? lena : lenb; - int r = memcmp(jv_string_value(*a), jv_string_value(*b), minlen); - if (r == 0) r = lena - lenb; - return r; -} - -jv jv_keys_unsorted(jv x) { - if (jv_get_kind(x) != JV_KIND_OBJECT) - return jv_keys(x); - jv answer = jv_array_sized(jv_object_length(jv_copy(x))); - jv_object_foreach(x, key, value) { - answer = jv_array_append(answer, key); - jv_free(value); - } - jv_free(x); - return answer; -} - -jv jv_keys(jv x) { - if (jv_get_kind(x) == JV_KIND_OBJECT) { - int nkeys = jv_object_length(jv_copy(x)); - jv* keys = jv_mem_alloc(sizeof(jv) * nkeys); - int kidx = 0; - jv_object_foreach(x, key, value) { - keys[kidx++] = key; - jv_free(value); - } - qsort(keys, nkeys, sizeof(jv), string_cmp); - jv answer = jv_array_sized(nkeys); - for (int i = 0; i= jv_array_length(jv_copy(a)); - int b_done = i >= jv_array_length(jv_copy(b)); - if (a_done || b_done) { - r = b_done - a_done; //suddenly, logic - break; - } - jv xa = jv_array_get(jv_copy(a), i); - jv xb = jv_array_get(jv_copy(b), i); - r = jv_cmp(xa, xb); - i++; - } - break; - } - - case JV_KIND_OBJECT: { - jv keys_a = jv_keys(jv_copy(a)); - jv keys_b = jv_keys(jv_copy(b)); - r = jv_cmp(jv_copy(keys_a), keys_b); - if (r == 0) { - jv_array_foreach(keys_a, i, key) { - jv xa = jv_object_get(jv_copy(a), jv_copy(key)); - jv xb = jv_object_get(jv_copy(b), key); - r = jv_cmp(xa, xb); - if (r) break; - } - } - jv_free(keys_a); - break; - } - } - - jv_free(a); - jv_free(b); - return r; -} - - -struct sort_entry { - jv object; - jv key; - int index; -}; - -static int sort_cmp(const void* pa, const void* pb) { - const struct sort_entry* a = pa; - const struct sort_entry* b = pb; - int r = jv_cmp(jv_copy(a->key), jv_copy(b->key)); - // comparing by index if r == 0 makes the sort stable - return r ? r : (a->index - b->index); -} - -static struct sort_entry* sort_items(jv objects, jv keys) { - assert(jv_get_kind(objects) == JV_KIND_ARRAY); - assert(jv_get_kind(keys) == JV_KIND_ARRAY); - assert(jv_array_length(jv_copy(objects)) == jv_array_length(jv_copy(keys))); - int n = jv_array_length(jv_copy(objects)); - struct sort_entry* entries = jv_mem_alloc(sizeof(struct sort_entry) * n); - for (int i=0; i 0) { - jv curr_key = entries[0].key; - jv group = jv_array_append(jv_array(), entries[0].object); - for (int i = 1; i < n; i++) { - if (jv_equal(jv_copy(curr_key), jv_copy(entries[i].key))) { - jv_free(entries[i].key); - } else { - jv_free(curr_key); - curr_key = entries[i].key; - ret = jv_array_append(ret, group); - group = jv_array(); - } - group = jv_array_append(group, entries[i].object); - } - jv_free(curr_key); - ret = jv_array_append(ret, group); - } - jv_mem_free(entries); - return ret; -} diff --git a/src/jq/jv_dtoa.c b/src/jq/jv_dtoa.c deleted file mode 100644 index 33feb99..0000000 --- a/src/jq/jv_dtoa.c +++ /dev/null @@ -1,4274 +0,0 @@ - -/**************************************************************** - * - * The author of this software is David M. Gay. - * - * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - * - ***************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -/* On a machine with IEEE extended-precision registers, it is - * necessary to specify double-precision (53-bit) rounding precision - * before invoking strtod or dtoa. If the machine uses (the equivalent - * of) Intel 80x87 arithmetic, the call - * _control87(PC_53, MCW_PC); - * does this with many compilers. Whether this or another call is - * appropriate depends on the compiler; for this to work, it may be - * necessary to #include "float.h" or another system-dependent header - * file. - */ - -/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. - * (Note that IEEE arithmetic is disabled by gcc's -ffast-math flag.) - * - * This strtod returns a nearest machine number to the input decimal - * string (or sets errno to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). - * - * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * - * 1. We only require IEEE, IBM, or VAX double-precision - * arithmetic (not IEEE double-extended). - * 2. We get by with floating-point arithmetic in a case that - * Clinger missed -- when we're computing d * 10^n - * for a small integer d and the integer n is not too - * much larger than 22 (the maximum integer k for which - * we can represent 10^k exactly), we may be able to - * compute (d*10^k) * 10^(e-k) with just one roundoff. - * 3. Rather than a bit-at-a-time adjustment of the binary - * result in the hard case, we use floating-point - * arithmetic to determine the adjustment to within - * one bit; only in really hard cases do we need to - * compute a second residual. - * 4. Because of 3., we don't need a large table of powers of 10 - * for ten-to-e (just some small tables, e.g. of 10^k - * for 0 <= k <= 22). - */ - -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define Long int on machines with 32-bit ints and 64-bit longs. - * #define IBM for IBM mainframe-style floating-point arithmetic. - * #define VAX for VAX-style floating-point arithmetic (D_floating). - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. This will cause dtoa modes 4 and 5 to be - * treated the same as modes 2 and 3 for some inputs. - * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS - * is also #defined, fegetround() will be queried for the rounding mode. - * Note that both FLT_ROUNDS and fegetround() are specified by the C99 - * standard (and are specified to be consistent, with fesetround() - * affecting the value of FLT_ROUNDS), but that some (Linux) systems - * do not work correctly in this regard, so using fegetround() is more - * portable than using FLT_ROUNDS directly. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and Honor_FLT_ROUNDS is not #defined. - * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines - * that use extended-precision instructions to compute rounded - * products and quotients) with IBM. - * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic - * that rounds toward +Infinity. - * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased - * rounding when the underlying floating-point arithmetic uses - * unbiased rounding. This prevent using ordinary floating-point - * arithmetic when the result could be computed with one rounding error. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define NO_LONG_LONG on machines that do not have a "long long" - * integer type (of >= 64 bits). On such machines, you can - * #define Just_16 to store 16 bits per 32-bit Long when doing - * high-precision integer arithmetic. Whether this speeds things - * up or slows things down depends on the machine and the number - * being converted. If long long is available and the name is - * something other than "long long", #define Llong to be the name, - * and if "unsigned Llong" does not work as an unsigned version of - * Llong, #define #ULLong to be the corresponding unsigned type. - * #define KR_headers for old-style C function headers. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) - * if memory is available and otherwise does something you deem - * appropriate. If MALLOC is undefined, malloc will be invoked - * directly -- and assumed always to succeed. Similarly, if you - * want something other than the system's free() to be called to - * recycle memory acquired from MALLOC, #define FREE to be the - * name of the alternate routine. (FREE or free is only called in - * pathological cases, e.g., in a dtoa call after a dtoa return in - * mode 3 with thousands of digits requested.) - * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making - * memory allocations from a private pool of memory when possible. - * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, - * unless #defined to be a different length. This default length - * suffices to get rid of MALLOC calls except for unusual cases, - * such as decimal-to-binary conversion of a very long string of - * digits. The longest string dtoa can return is about 751 bytes - * long. For conversions by strtod of strings of 800 digits and - * all dtoa conversions in single-threaded executions with 8-byte - * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte - * pointers, PRIVATE_MEM >= 7112 appears adequate. - * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK - * #defined automatically on IEEE systems. On such systems, - * when INFNAN_CHECK is #defined, strtod checks - * for Infinity and NaN (case insensitively). On some systems - * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 - * appropriately -- to the most significant word of a quiet NaN. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) - * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, - * strtod also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits and spaces; - * if there is only one string of hexadecimal digits, it is taken - * for the 52 fraction bits of the resulting NaN; if there are two - * or more strings of hex digits, the first is for the high 20 bits, - * the second and subsequent for the low 32 bits, with intervening - * white space ignored; but if this results in none of the 52 - * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 - * and NAN_WORD1 are used instead. - * #define MULTIPLE_THREADS if the system offers preemptively scheduled - * multiple threads. In this case, you must provide (or suitably - * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed - * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed - * in pow5mult, ensures lazy evaluation of only one copy of high - * powers of 5; omitting this lock would introduce a small - * probability of wasting memory, but would otherwise be harmless.) - * You must also invoke freedtoa(s) to free the value s returned by - * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. - * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that - * avoids underflows on inputs whose result does not underflow. - * If you #define NO_IEEE_Scale on a machine that uses IEEE-format - * floating-point numbers and flushes underflows to zero rather - * than implementing gradual underflow, then you must also #define - * Sudden_Underflow. - * #define USE_LOCALE to use the current locale's decimal_point value. - * #define SET_INEXACT if IEEE arithmetic is being used and extra - * computation should be done to set the inexact flag when the - * result is inexact and avoid setting inexact when the result - * is exact. In this case, dtoa.c must be compiled in - * an environment, perhaps provided by #include "dtoa.c" in a - * suitable wrapper, that defines two functions, - * int get_inexact(void); - * void clear_inexact(void); - * such that get_inexact() returns a nonzero value if the - * inexact bit is already set, and clear_inexact() sets the - * inexact bit to 0. When SET_INEXACT is #defined, strtod - * also does extra computations to set the underflow and overflow - * flags when appropriate (i.e., when the result is tiny and - * inexact or when it is a numeric value rounded to +-infinity). - * #define NO_ERRNO if strtod should not assign errno = ERANGE when - * the result overflows to +-Infinity or underflows to 0. - * #define NO_HEX_FP to omit recognition of hexadecimal floating-point - * values by strtod. - * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now) - * to disable logic for "fast" testing of very long input strings - * to strtod. This testing proceeds by initially truncating the - * input string, then if necessary comparing the whole string with - * a decimal expansion to decide close cases. This logic is only - * used for input more than STRTOD_DIGLIM digits long (default 40). - */ - -#define NO_ERRNO -#define NO_HEX_FP -#define No_Hex_NaN -#define Long int - -#include "jv_dtoa.h" - -#include "jv_alloc.h" -#define MALLOC jv_mem_alloc -#define FREE jv_mem_free - - - -#ifndef Long -#define Long long -#endif -#ifndef ULong -typedef unsigned Long ULong; -#endif - -#ifdef DEBUG -#include "stdio.h" -#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} -#endif - -#include "stdlib.h" -#include "string.h" - -#ifdef USE_LOCALE -#include "locale.h" -#endif - -#ifdef Honor_FLT_ROUNDS -#ifndef Trust_FLT_ROUNDS -#include -#endif -#endif - -#ifdef MALLOC -extern void *MALLOC(size_t); -#else -#define MALLOC malloc -#endif - -#undef IEEE_Arith -#undef Avoid_Underflow -#ifdef IEEE_MC68k -#define IEEE_Arith -#endif -#ifdef IEEE_8087 -#define IEEE_Arith -#endif - -#ifdef IEEE_Arith -#ifndef NO_INFNAN_CHECK -#undef INFNAN_CHECK -#define INFNAN_CHECK -#endif -#else -#undef INFNAN_CHECK -#define NO_STRTOD_BIGCOMP -#endif - -#include "errno.h" - -#ifdef Bad_float_h - -#ifdef IEEE_Arith -#define DBL_DIG 15 -#define DBL_MAX_10_EXP 308 -#define DBL_MAX_EXP 1024 -#define FLT_RADIX 2 -#endif /*IEEE_Arith*/ - -#ifdef IBM -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 75 -#define DBL_MAX_EXP 63 -#define FLT_RADIX 16 -#define DBL_MAX 7.2370055773322621e+75 -#endif - -#ifdef VAX -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 38 -#define DBL_MAX_EXP 127 -#define FLT_RADIX 2 -#define DBL_MAX 1.7014118346046923e+38 -#endif - -#ifndef LONG_MAX -#define LONG_MAX 2147483647 -#endif - -#else /* ifndef Bad_float_h */ -#include "float.h" -#endif /* Bad_float_h */ - -#ifndef __MATH_H__ -#include "math.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef CONST -#define CONST const -#endif - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 -Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. -#endif - -typedef union { double d; ULong L[2]; } U; - -#ifdef IEEE_8087 -#define word0(x) (x)->L[1] -#define word1(x) (x)->L[0] -#else -#define word0(x) (x)->L[0] -#define word1(x) (x)->L[1] -#endif -#define dval(x) (x)->d - -#ifndef STRTOD_DIGLIM -#define STRTOD_DIGLIM 40 -#endif - -#ifdef DIGLIM_DEBUG -extern int strtod_diglim; -#else -#define strtod_diglim STRTOD_DIGLIM -#endif - -/* The following definition of Storeinc is appropriate for MIPS processors. - * An alternative that might be better on some machines is - * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) - */ -#if defined(IEEE_8087) + defined(VAX) -#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ -((unsigned short *)a)[0] = (unsigned short)c, a++) -#else -#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ -((unsigned short *)a)[1] = (unsigned short)c, a++) -#endif - -/* #define P DBL_MANT_DIG */ -/* Ten_pmax = floor(P*log(2)/log(5)) */ -/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ -/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ -/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ - -#ifdef IEEE_Arith -#define Exp_shift 20 -#define Exp_shift1 20 -#define Exp_msk1 0x100000 -#define Exp_msk11 0x100000 -#define Exp_mask 0x7ff00000 -#define P 53 -#define Nbits 53 -#define Bias 1023 -#define Emax 1023 -#define Emin (-1022) -#define Exp_1 0x3ff00000 -#define Exp_11 0x3ff00000 -#define Ebits 11 -#define Frac_mask 0xfffff -#define Frac_mask1 0xfffff -#define Ten_pmax 22 -#define Bletch 0x10 -#define Bndry_mask 0xfffff -#define Bndry_mask1 0xfffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 1 -#define Tiny0 0 -#define Tiny1 1 -#define Quick_max 14 -#define Int_max 14 -#ifndef NO_IEEE_Scale -#define Avoid_Underflow -#ifdef Flush_Denorm /* debugging option */ -#undef Sudden_Underflow -#endif -#endif - -#ifndef Flt_Rounds -#ifdef FLT_ROUNDS -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /*Flt_Rounds*/ - -#ifdef Honor_FLT_ROUNDS -#undef Check_FLT_ROUNDS -#define Check_FLT_ROUNDS -#else -#define Rounding Flt_Rounds -#endif - -#else /* ifndef IEEE_Arith */ -#undef Check_FLT_ROUNDS -#undef Honor_FLT_ROUNDS -#undef SET_INEXACT -#undef Sudden_Underflow -#define Sudden_Underflow -#ifdef IBM -#undef Flt_Rounds -#define Flt_Rounds 0 -#define Exp_shift 24 -#define Exp_shift1 24 -#define Exp_msk1 0x1000000 -#define Exp_msk11 0x1000000 -#define Exp_mask 0x7f000000 -#define P 14 -#define Nbits 56 -#define Bias 65 -#define Emax 248 -#define Emin (-260) -#define Exp_1 0x41000000 -#define Exp_11 0x41000000 -#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ -#define Frac_mask 0xffffff -#define Frac_mask1 0xffffff -#define Bletch 4 -#define Ten_pmax 22 -#define Bndry_mask 0xefffff -#define Bndry_mask1 0xffffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 4 -#define Tiny0 0x100000 -#define Tiny1 0 -#define Quick_max 14 -#define Int_max 15 -#else /* VAX */ -#undef Flt_Rounds -#define Flt_Rounds 1 -#define Exp_shift 23 -#define Exp_shift1 7 -#define Exp_msk1 0x80 -#define Exp_msk11 0x800000 -#define Exp_mask 0x7f80 -#define P 56 -#define Nbits 56 -#define Bias 129 -#define Emax 126 -#define Emin (-129) -#define Exp_1 0x40800000 -#define Exp_11 0x4080 -#define Ebits 8 -#define Frac_mask 0x7fffff -#define Frac_mask1 0xffff007f -#define Ten_pmax 24 -#define Bletch 2 -#define Bndry_mask 0xffff007f -#define Bndry_mask1 0xffff007f -#define LSB 0x10000 -#define Sign_bit 0x8000 -#define Log2P 1 -#define Tiny0 0x80 -#define Tiny1 0 -#define Quick_max 15 -#define Int_max 15 -#endif /* IBM, VAX */ -#endif /* IEEE_Arith */ - -#ifndef IEEE_Arith -#define ROUND_BIASED -#else -#ifdef ROUND_BIASED_without_Round_Up -#undef ROUND_BIASED -#define ROUND_BIASED -#endif -#endif - -#ifdef RND_PRODQUOT -#define rounded_product(a,b) a = rnd_prod(a, b) -#define rounded_quotient(a,b) a = rnd_quot(a, b) -extern double rnd_prod(double, double), rnd_quot(double, double); -#else -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b -#endif - -#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) -#define Big1 0xffffffff - -#ifndef Pack_32 -#define Pack_32 -#endif - -typedef struct BCinfo BCinfo; - struct -BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; }; - -#define FFFFFFFF 0xffffffffUL - -#ifdef NO_LONG_LONG -#undef ULLong -#ifdef Just_16 -#undef Pack_32 -/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per Long. - */ -#endif -#else /* long long available */ -#ifndef Llong -#define Llong long long -#endif -#ifndef ULLong -#define ULLong unsigned Llong -#endif -#endif /* NO_LONG_LONG */ - - - - struct -Bigint { - struct Bigint *next; - int k, maxwds, sign, wds; - ULong x[1]; - }; - - typedef struct Bigint Bigint; - - -void jvp_dtoa_context_init(struct dtoa_context* C) { - int i; - for (i=0; i<(int)(sizeof(C->freelist)/sizeof(C->freelist[0])); i++) { - C->freelist[i] = 0; - } - C->p5s = 0; -} - - static Bigint * - Balloc(struct dtoa_context* C, int k) -{ - int x; - Bigint *rv; - - /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ - /* but this case seems very unlikely. */ - if (k <= Kmax && (rv = C->freelist[k])) - C->freelist[k] = rv->next; - else { - x = 1 << k; - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); - rv->k = k; - rv->maxwds = x; - } - rv->sign = rv->wds = 0; - return rv; - } - - static void -Bfree - (struct dtoa_context* C, Bigint *v) -{ - if (v) { - if (v->k > Kmax) -#ifdef FREE - FREE((void*)v); -#else - free((void*)v); -#endif - else { - v->next = C->freelist[v->k]; - C->freelist[v->k] = v; - } - } - } - - -void jvp_dtoa_context_free(struct dtoa_context* C) { - int k; - while (C->p5s) { - Bigint* p5 = C->p5s; - C->p5s = p5->next; - Bfree(C, p5); - } - for (k=0; k<(int)(sizeof(C->freelist)/sizeof(C->freelist[0])); k++) { - while (C->freelist[k]) { - Bigint* v = C->freelist[k]; - C->freelist[k] = v->next; - FREE(v); - } - } -} - - -#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ -y->wds*sizeof(Long) + 2*sizeof(int)) - - static Bigint * -multadd - (struct dtoa_context* C, Bigint *b, int m, int a) /* multiply by m and add a */ -{ - int i, wds; -#ifdef ULLong - ULong *x; - ULLong carry, y; -#else - ULong carry, *x, y; -#ifdef Pack_32 - ULong xi, z; -#endif -#endif - Bigint *b1; - - wds = b->wds; - x = b->x; - i = 0; - carry = a; - do { -#ifdef ULLong - y = *x * (ULLong)m + carry; - carry = y >> 32; - *x++ = y & FFFFFFFF; -#else -#ifdef Pack_32 - xi = *x; - y = (xi & 0xffff) * m + carry; - z = (xi >> 16) * m + (y >> 16); - carry = z >> 16; - *x++ = (z << 16) + (y & 0xffff); -#else - y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif -#endif - } - while(++i < wds); - if (carry) { - if (wds >= b->maxwds) { - b1 = Balloc(C, b->k+1); - Bcopy(b1, b); - Bfree(C, b); - b = b1; - } - b->x[wds++] = carry; - b->wds = wds; - } - return b; - } - - static Bigint * -s2b - (struct dtoa_context* C, const char *s, int nd0, int nd, ULong y9, int dplen) -{ - Bigint *b; - int i, k; - Long x, y; - - x = (nd + 8) / 9; - for(k = 0, y = 1; x > y; y <<= 1, k++) ; -#ifdef Pack_32 - b = Balloc(C, k); - b->x[0] = y9; - b->wds = 1; -#else - b = Balloc(C, k+1); - b->x[0] = y9 & 0xffff; - b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; -#endif - - i = 9; - if (9 < nd0) { - s += 9; - do b = multadd(C, b, 10, *s++ - '0'); - while(++i < nd0); - s += dplen; - } - else - s += dplen + 9; - for(; i < nd; i++) - b = multadd(C, b, 10, *s++ - '0'); - return b; - } - - static int -hi0bits - (struct dtoa_context* C, ULong x) -{ - int k = 0; - - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; - } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) - return 32; - } - return k; - } - - static int -lo0bits - (struct dtoa_context* C, ULong *y) -{ - int k; - ULong x = *y; - - if (x & 7) { - if (x & 1) - return 0; - if (x & 2) { - *y = x >> 1; - return 1; - } - *y = x >> 2; - return 2; - } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x) - return 32; - } - *y = x; - return k; - } - - static Bigint * -i2b - (struct dtoa_context* C, int i) -{ - Bigint *b; - - b = Balloc(C, 1); - b->x[0] = i; - b->wds = 1; - return b; - } - - static Bigint * -mult - (struct dtoa_context* C, Bigint *a, Bigint *b) -{ - Bigint *c; - int k, wa, wb, wc; - ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; - ULong y; -#ifdef ULLong - ULLong carry, z; -#else - ULong carry, z; -#ifdef Pack_32 - ULong z2; -#endif -#endif - - if (a->wds < b->wds) { - c = a; - a = b; - b = c; - } - k = a->k; - wa = a->wds; - wb = b->wds; - wc = wa + wb; - if (wc > a->maxwds) - k++; - c = Balloc(C, k); - for(x = c->x, xa = x + wc; x < xa; x++) - *x = 0; - xa = a->x; - xae = xa + wa; - xb = b->x; - xbe = xb + wb; - xc0 = c->x; -#ifdef ULLong - for(; xb < xbe; xc0++) { - if ((y = *xb++)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * (ULLong)y + *xc + carry; - carry = z >> 32; - *xc++ = z & FFFFFFFF; - } - while(x < xae); - *xc = carry; - } - } -#else -#ifdef Pack_32 - for(; xb < xbe; xb++, xc0++) { - if (y = *xb & 0xffff) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } - while(x < xae); - *xc = carry; - } - if (y = *xb >> 16) { - x = xa; - xc = xc0; - carry = 0; - z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } - while(x < xae); - *xc = z2; - } - } -#else - for(; xb < xbe; xc0++) { - if (y = *xb++) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } - while(x < xae); - *xc = carry; - } - } -#endif -#endif - for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; - c->wds = wc; - return c; - } - - - static Bigint * -pow5mult - (struct dtoa_context* C, Bigint *b, int k) -{ - Bigint *b1, *p5, *p51; - int i; - static const int p05[3] = { 5, 25, 125 }; - - if ((i = k & 3)) - b = multadd(C, b, p05[i-1], 0); - - if (!(k >>= 2)) - return b; - if (!(p5 = C->p5s)) { - /* first time */ - p5 = C->p5s = i2b(C, 625); - p5->next = 0; - } - for(;;) { - if (k & 1) { - b1 = mult(C, b, p5); - Bfree(C, b); - b = b1; - } - if (!(k >>= 1)) - break; - if (!(p51 = p5->next)) { - p51 = p5->next = mult(C, p5,p5); - p51->next = 0; - } - p5 = p51; - } - return b; - } - - static Bigint * -lshift - (struct dtoa_context* C, Bigint *b, int k) -{ - int i, k1, n, n1; - Bigint *b1; - ULong *x, *x1, *xe, z; - -#ifdef Pack_32 - n = k >> 5; -#else - n = k >> 4; -#endif - k1 = b->k; - n1 = n + b->wds + 1; - for(i = b->maxwds; n1 > i; i <<= 1) - k1++; - b1 = Balloc(C, k1); - x1 = b1->x; - for(i = 0; i < n; i++) - *x1++ = 0; - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - if (k &= 0x1f) { - k1 = 32 - k; - z = 0; - do { - *x1++ = *x << k | z; - z = *x++ >> k1; - } - while(x < xe); - if ((*x1 = z)) - ++n1; - } -#else - if (k &= 0xf) { - k1 = 16 - k; - z = 0; - do { - *x1++ = *x << k & 0xffff | z; - z = *x++ >> k1; - } - while(x < xe); - if (*x1 = z) - ++n1; - } -#endif - else do - *x1++ = *x++; - while(x < xe); - b1->wds = n1 - 1; - Bfree(C, b); - return b1; - } - - static int -cmp - (struct dtoa_context* C, Bigint *a, Bigint *b) -{ - ULong *xa, *xa0, *xb, *xb0; - int i, j; - - i = a->wds; - j = b->wds; -#ifdef DEBUG - if (i > 1 && !a->x[i-1]) - Bug("cmp called with a->x[a->wds-1] == 0"); - if (j > 1 && !b->x[j-1]) - Bug("cmp called with b->x[b->wds-1] == 0"); -#endif - if (i -= j) - return i; - xa0 = a->x; - xa = xa0 + j; - xb0 = b->x; - xb = xb0 + j; - for(;;) { - if (*--xa != *--xb) - return *xa < *xb ? -1 : 1; - if (xa <= xa0) - break; - } - return 0; - } - - static Bigint * -diff - (struct dtoa_context* C, Bigint *a, Bigint *b) -{ - Bigint *c; - int i, wa, wb; - ULong *xa, *xae, *xb, *xbe, *xc; -#ifdef ULLong - ULLong borrow, y; -#else - ULong borrow, y; -#ifdef Pack_32 - ULong z; -#endif -#endif - - i = cmp(C, a,b); - if (!i) { - c = Balloc(C, 0); - c->wds = 1; - c->x[0] = 0; - return c; - } - if (i < 0) { - c = a; - a = b; - b = c; - i = 1; - } - else - i = 0; - c = Balloc(C, a->k); - c->sign = i; - wa = a->wds; - xa = a->x; - xae = xa + wa; - wb = b->wds; - xb = b->x; - xbe = xb + wb; - xc = c->x; - borrow = 0; -#ifdef ULLong - do { - y = (ULLong)*xa++ - *xb++ - borrow; - borrow = y >> 32 & (ULong)1; - *xc++ = y & FFFFFFFF; - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ - borrow; - borrow = y >> 32 & (ULong)1; - *xc++ = y & FFFFFFFF; - } -#else -#ifdef Pack_32 - do { - y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } - while(xb < xbe); - while(xa < xae) { - y = (*xa & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif -#endif - while(!*--xc) - wa--; - c->wds = wa; - return c; - } - - static double -ulp - (struct dtoa_context* C, U *x) -{ - Long L; - U u; - - L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#endif -#ifdef IBM - L |= Exp_msk1 >> 4; -#endif - word0(&u) = L; - word1(&u) = 0; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - } - else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(&u) = 0x80000 >> L; - word1(&u) = 0; - } - else { - word0(&u) = 0; - L -= Exp_shift; - word1(&u) = L >= 31 ? 1 : 1 << 31 - L; - } - } -#endif -#endif - return dval(&u); - } - - static double -b2d - (struct dtoa_context* C, Bigint *a, int *e) -{ - ULong *xa, *xa0, w, y, z; - int k; - U d; -#ifdef VAX - ULong d0, d1; -#else -#define d0 word0(&d) -#define d1 word1(&d) -#endif - - xa0 = a->x; - xa = xa0 + a->wds; - y = *--xa; -#ifdef DEBUG - if (!y) Bug("zero y in b2d"); -#endif - k = hi0bits(C, y); - *e = 32 - k; -#ifdef Pack_32 - if (k < Ebits) { - d0 = Exp_1 | y >> (Ebits - k); - w = xa > xa0 ? *--xa : 0; - d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - d0 = Exp_1 | y << k | z >> (32 - k); - y = xa > xa0 ? *--xa : 0; - d1 = z << k | y >> (32 - k); - } - else { - d0 = Exp_1 | y; - d1 = z; - } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif - ret_d: -#ifdef VAX - word0(&d) = d0 >> 16 | d0 << 16; - word1(&d) = d1 >> 16 | d1 << 16; -#else -#undef d0 -#undef d1 -#endif - return dval(&d); - } - - static Bigint * -d2b - (struct dtoa_context* C, U *d, int *e, int *bits) -{ - Bigint *b; - int de, k; - ULong *x, y, z; -#ifndef Sudden_Underflow - int i; -#endif -#ifdef VAX - ULong d0, d1; - d0 = word0(d) >> 16 | word0(d) << 16; - d1 = word1(d) >> 16 | word1(d) << 16; -#else -#define d0 word0(d) -#define d1 word1(d) -#endif - -#ifdef Pack_32 - b = Balloc(C, 1); -#else - b = Balloc(C, 2); -#endif - x = b->x; - - z = d0 & Frac_mask; - d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#ifndef IBM - z |= Exp_msk11; -#endif -#else - if ((de = (int)(d0 >> Exp_shift))) - z |= Exp_msk1; -#endif -#ifdef Pack_32 - if ((y = d1)) { - if ((k = lo0bits(C, &y))) { - x[0] = y | z << (32 - k); - z >>= k; - } - else - x[0] = y; -#ifndef Sudden_Underflow - i = -#endif - b->wds = (x[1] = z) ? 2 : 1; - } - else { - k = lo0bits(C, &z); - x[0] = z; -#ifndef Sudden_Underflow - i = -#endif - b->wds = 1; - k += 32; - } -#else - if (y = d1) { - if (k = lo0bits(C, &y)) - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k+16; - i = 3; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } - else { -#ifdef DEBUG - if (!z) - Bug("Zero passed to d2b"); -#endif - k = lo0bits(C, &z); - if (k >= 16) { - x[0] = z; - i = 0; - } - else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } - while(!x[i]) - --i; - b->wds = i + 1; -#endif -#ifndef Sudden_Underflow - if (de) { -#endif -#ifdef IBM - *e = (de - Bias - (P-1) << 2) + k; - *bits = 4*P + 8 - k - hi0bits(C, word0(d) & Frac_mask); -#else - *e = de - Bias - (P-1) + k; - *bits = P - k; -#endif -#ifndef Sudden_Underflow - } - else { - *e = de - Bias - (P-1) + 1 + k; -#ifdef Pack_32 - *bits = 32*i - hi0bits(C, x[i-1]); -#else - *bits = (i+2)*16 - hi0bits(C, x[i]); -#endif - } -#endif - return b; - } -#undef d0 -#undef d1 - - static double -ratio - (struct dtoa_context* C, Bigint *a, Bigint *b) -{ - U da, db; - int k, ka, kb; - - dval(&da) = b2d(C, a, &ka); - dval(&db) = b2d(C, b, &kb); -#ifdef Pack_32 - k = ka - kb + 32*(a->wds - b->wds); -#else - k = ka - kb + 16*(a->wds - b->wds); -#endif -#ifdef IBM - if (k > 0) { - word0(&da) += (k >> 2)*Exp_msk1; - if (k &= 3) - dval(&da) *= 1 << k; - } - else { - k = -k; - word0(&db) += (k >> 2)*Exp_msk1; - if (k &= 3) - dval(&db) *= 1 << k; - } -#else - if (k > 0) - word0(&da) += k*Exp_msk1; - else { - k = -k; - word0(&db) += k*Exp_msk1; - } -#endif - return dval(&da) / dval(&db); - } - - static CONST double -tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 -#ifdef VAX - , 1e23, 1e24 -#endif - }; - - static CONST double -#ifdef IEEE_Arith -bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; -static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, -#ifdef Avoid_Underflow - 9007199254740992.*9007199254740992.e-256 - /* = 2^106 * 1e-256 */ -#else - 1e-256 -#endif - }; -/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ -/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ -#define Scale_Bit 0x10 -#define n_bigtens 5 -#else -#ifdef IBM -bigtens[] = { 1e16, 1e32, 1e64 }; -static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; -#define n_bigtens 3 -#else -bigtens[] = { 1e16, 1e32 }; -static CONST double tinytens[] = { 1e-16, 1e-32 }; -#define n_bigtens 2 -#endif -#endif - -#undef Need_Hexdig -#ifdef INFNAN_CHECK -#ifndef No_Hex_NaN -#define Need_Hexdig -#endif -#endif - -#ifndef Need_Hexdig -#ifndef NO_HEX_FP -#define Need_Hexdig -#endif -#endif - -#ifdef Need_Hexdig /*{*/ -static unsigned char hexdig[256]; - - static void -htinit(unsigned char *h, unsigned char *s, int inc) -{ - int i, j; - for(i = 0; (j = s[i]) !=0; i++) - h[j] = i + inc; - } - - static void -hexdig_init(void) -{ -#define USC (unsigned char *) - htinit(hexdig, USC "0123456789", 0x10); - htinit(hexdig, USC "abcdef", 0x10 + 10); - htinit(hexdig, USC "ABCDEF", 0x10 + 10); - } -#endif /* } Need_Hexdig */ - -#ifdef INFNAN_CHECK - -#ifndef NAN_WORD0 -#define NAN_WORD0 0x7ff80000 -#endif - -#ifndef NAN_WORD1 -#define NAN_WORD1 0 -#endif - - static int -match - (struct dtoa_context* C, const char **sp, const char *t) -{ - int c, d; - CONST char *s = *sp; - - while((d = *t++)) { - if ((c = *++s) >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != d) - return 0; - } - *sp = s + 1; - return 1; - } - -#ifndef No_Hex_NaN - static void -hexnan - (struct dtoa_context* C, U *rvp, const char **sp) -{ - ULong c, x[2]; - CONST char *s; - int c1, havedig, udx0, xshift; - - if (!hexdig['0']) - hexdig_init(); - x[0] = x[1] = 0; - havedig = xshift = 0; - udx0 = 1; - s = *sp; - /* allow optional initial 0x or 0X */ - while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') - ++s; - if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) - s += 2; - while((c = *(CONST unsigned char*)++s)) { - if ((c1 = hexdig[c])) - c = c1 & 0xf; - else if (c <= ' ') { - if (udx0 && havedig) { - udx0 = 0; - xshift = 1; - } - continue; - } -#ifdef GDTOA_NON_PEDANTIC_NANCHECK - else if (/*(*/ c == ')' && havedig) { - *sp = s + 1; - break; - } - else - return; /* invalid form: don't change *sp */ -#else - else { - do { - if (/*(*/ c == ')') { - *sp = s + 1; - break; - } - } while((c = *++s)); - break; - } -#endif - havedig = 1; - if (xshift) { - xshift = 0; - x[0] = x[1]; - x[1] = 0; - } - if (udx0) - x[0] = (x[0] << 4) | (x[1] >> 28); - x[1] = (x[1] << 4) | c; - } - if ((x[0] &= 0xfffff) || x[1]) { - word0(rvp) = Exp_mask | x[0]; - word1(rvp) = x[1]; - } - } -#endif /*No_Hex_NaN*/ -#endif /* INFNAN_CHECK */ - -#ifdef Pack_32 -#define ULbits 32 -#define kshift 5 -#define kmask 31 -#else -#define ULbits 16 -#define kshift 4 -#define kmask 15 -#endif - -#if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/ - static Bigint * -increment(struct dtoa_context* C, Bigint *b) -{ - ULong *x, *xe; - Bigint *b1; - - x = b->x; - xe = x + b->wds; - do { - if (*x < (ULong)0xffffffffL) { - ++*x; - return b; - } - *x++ = 0; - } while(x < xe); - { - if (b->wds >= b->maxwds) { - b1 = Balloc(C, b->k+1); - Bcopy(b1,b); - Bfree(C, b); - b = b1; - } - b->x[b->wds++] = 1; - } - return b; - } - -#endif /*}*/ - -#ifndef NO_HEX_FP /*{*/ - - static void -rshift(struct dtoa_context* C, Bigint *b, int k) -{ - ULong *x, *x1, *xe, y; - int n; - - x = x1 = b->x; - n = k >> kshift; - if (n < b->wds) { - xe = x + b->wds; - x += n; - if (k &= kmask) { - n = 32 - k; - y = *x++ >> k; - while(x < xe) { - *x1++ = (y | (*x << n)) & 0xffffffff; - y = *x++ >> k; - } - if ((*x1 = y) !=0) - x1++; - } - else - while(x < xe) - *x1++ = *x++; - } - if ((b->wds = x1 - b->x) == 0) - b->x[0] = 0; - } - - static ULong -any_on(Bigint *b, int k) -{ - int n, nwds; - ULong *x, *x0, x1, x2; - - x = b->x; - nwds = b->wds; - n = k >> kshift; - if (n > nwds) - n = nwds; - else if (n < nwds && (k &= kmask)) { - x1 = x2 = x[n]; - x1 >>= k; - x1 <<= k; - if (x1 != x2) - return 1; - } - x0 = x; - x += n; - while(x > x0) - if (*--x) - return 1; - return 0; - } - -enum { /* rounding values: same as FLT_ROUNDS */ - Round_zero = 0, - Round_near = 1, - Round_up = 2, - Round_down = 3 - }; - -static void -gethex(struct dtoa_context* C, CONST char **sp, U *rvp, int rounding, int sign) -{ - Bigint *b; - CONST unsigned char *decpt, *s0, *s, *s1; - Long e, e1; - ULong L, lostbits, *x; - int big, denorm, esign, havedig, k, n, nbits, up, zret; -#ifdef IBM - int j; -#endif - enum { -#ifdef IEEE_Arith /*{{*/ - emax = 0x7fe - Bias - P + 1, - emin = Emin - P + 1 -#else /*}{*/ - emin = Emin - P, -#ifdef VAX - emax = 0x7ff - Bias - P + 1 -#endif -#ifdef IBM - emax = 0x7f - Bias - P -#endif -#endif /*}}*/ - }; -#ifdef USE_LOCALE - int i; -#ifdef NO_LOCALE_CACHE - const unsigned char *decimalpoint = (unsigned char*) - localeconv()->decimal_point; -#else - const unsigned char *decimalpoint; - static unsigned char *decimalpoint_cache; - if (!(s0 = decimalpoint_cache)) { - s0 = (unsigned char*)localeconv()->decimal_point; - if ((decimalpoint_cache = (unsigned char*) - MALLOC(strlen((CONST char*)s0) + 1))) { - strcpy((char*)decimalpoint_cache, (CONST char*)s0); - s0 = decimalpoint_cache; - } - } - decimalpoint = s0; -#endif -#endif - - if (!hexdig['0']) - hexdig_init(); - havedig = 0; - s0 = *(CONST unsigned char **)sp + 2; - while(s0[havedig] == '0') - havedig++; - s0 += havedig; - s = s0; - decpt = 0; - zret = 0; - e = 0; - if (hexdig[*s]) - havedig++; - else { - zret = 1; -#ifdef USE_LOCALE - for(i = 0; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) - goto pcheck; - } - decpt = s += i; -#else - if (*s != '.') - goto pcheck; - decpt = ++s; -#endif - if (!hexdig[*s]) - goto pcheck; - while(*s == '0') - s++; - if (hexdig[*s]) - zret = 0; - havedig = 1; - s0 = s; - } - while(hexdig[*s]) - s++; -#ifdef USE_LOCALE - if (*s == *decimalpoint && !decpt) { - for(i = 1; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) - goto pcheck; - } - decpt = s += i; -#else - if (*s == '.' && !decpt) { - decpt = ++s; -#endif - while(hexdig[*s]) - s++; - }/*}*/ - if (decpt) - e = -(((Long)(s-decpt)) << 2); - pcheck: - s1 = s; - big = esign = 0; - switch(*s) { - case 'p': - case 'P': - switch(*++s) { - case '-': - esign = 1; - /* no break */ - case '+': - s++; - } - if ((n = hexdig[*s]) == 0 || n > 0x19) { - s = s1; - break; - } - e1 = n - 0x10; - while((n = hexdig[*++s]) !=0 && n <= 0x19) { - if (e1 & 0xf8000000) - big = 1; - e1 = 10*e1 + n - 0x10; - } - if (esign) - e1 = -e1; - e += e1; - } - *sp = (char*)s; - if (!havedig) - *sp = (char*)s0 - 1; - if (zret) - goto retz1; - if (big) { - if (esign) { -#ifdef IEEE_Arith - switch(rounding) { - case Round_up: - if (sign) - break; - goto ret_tiny; - case Round_down: - if (!sign) - break; - goto ret_tiny; - } -#endif - goto retz; -#ifdef IEEE_Arith - ret_tiny: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - word0(rvp) = 0; - word1(rvp) = 1; - return; -#endif /* IEEE_Arith */ - } - switch(rounding) { - case Round_near: - goto ovfl1; - case Round_up: - if (!sign) - goto ovfl1; - goto ret_big; - case Round_down: - if (sign) - goto ovfl1; - goto ret_big; - } - ret_big: - word0(rvp) = Big0; - word1(rvp) = Big1; - return; - } - n = s1 - s0 - 1; - for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) - k++; - b = Balloc(C, k); - x = b->x; - n = 0; - L = 0; -#ifdef USE_LOCALE - for(i = 0; decimalpoint[i+1]; ++i); -#endif - while(s1 > s0) { -#ifdef USE_LOCALE - if (*--s1 == decimalpoint[i]) { - s1 -= i; - continue; - } -#else - if (*--s1 == '.') - continue; -#endif - if (n == ULbits) { - *x++ = L; - L = 0; - n = 0; - } - L |= (hexdig[*s1] & 0x0f) << n; - n += 4; - } - *x++ = L; - b->wds = n = x - b->x; - n = ULbits*n - hi0bits(C, L); - nbits = Nbits; - lostbits = 0; - x = b->x; - if (n > nbits) { - n -= nbits; - if (any_on(b,n)) { - lostbits = 1; - k = n - 1; - if (x[k>>kshift] & 1 << (k & kmask)) { - lostbits = 2; - if (k > 0 && any_on(b,k)) - lostbits = 3; - } - } - rshift(C, b, n); - e += n; - } - else if (n < nbits) { - n = nbits - n; - b = lshift(C, b, n); - e -= n; - x = b->x; - } - if (e > Emax) { - ovfl: - Bfree(C, b); - ovfl1: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - word0(rvp) = Exp_mask; - word1(rvp) = 0; - return; - } - denorm = 0; - if (e < emin) { - denorm = 1; - n = emin - e; - if (n >= nbits) { -#ifdef IEEE_Arith /*{*/ - switch (rounding) { - case Round_near: - if (n == nbits && (n < 2 || any_on(b,n-1))) - goto ret_tiny; - break; - case Round_up: - if (!sign) - goto ret_tiny; - break; - case Round_down: - if (sign) - goto ret_tiny; - } -#endif /* } IEEE_Arith */ - Bfree(C, b); - retz: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - retz1: - rvp->d = 0.; - return; - } - k = n - 1; - if (lostbits) - lostbits = 1; - else if (k > 0) - lostbits = any_on(b,k); - if (x[k>>kshift] & 1 << (k & kmask)) - lostbits |= 2; - nbits -= n; - rshift(C, b,n); - e = emin; - } - if (lostbits) { - up = 0; - switch(rounding) { - case Round_zero: - break; - case Round_near: - if (lostbits & 2 - && (lostbits & 1) | (x[0] & 1)) - up = 1; - break; - case Round_up: - up = 1 - sign; - break; - case Round_down: - up = sign; - } - if (up) { - k = b->wds; - b = increment(C, b); - x = b->x; - if (denorm) { -#if 0 - if (nbits == Nbits - 1 - && x[nbits >> kshift] & 1 << (nbits & kmask)) - denorm = 0; /* not currently used */ -#endif - } - else if (b->wds > k - || ((n = nbits & kmask) !=0 - && hi0bits(C, x[k-1]) < 32-n)) { - rshift(C, b,1); - if (++e > Emax) - goto ovfl; - } - } - } -#ifdef IEEE_Arith - if (denorm) - word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0; - else - word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20); - word1(rvp) = b->x[0]; -#endif -#ifdef IBM - if ((j = e & 3)) { - k = b->x[0] & ((1 << j) - 1); - rshift(C, b,j); - if (k) { - switch(rounding) { - case Round_up: - if (!sign) - increment(b); - break; - case Round_down: - if (sign) - increment(b); - break; - case Round_near: - j = 1 << (j-1); - if (k & j && ((k & (j-1)) | lostbits)) - increment(b); - } - } - } - e >>= 2; - word0(rvp) = b->x[1] | ((e + 65 + 13) << 24); - word1(rvp) = b->x[0]; -#endif -#ifdef VAX - /* The next two lines ignore swap of low- and high-order 2 bytes. */ - /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */ - /* word1(rvp) = b->x[0]; */ - word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); - word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); -#endif - Bfree(C, b); - } -#endif /*!NO_HEX_FP}*/ - - static int -dshift(struct dtoa_context* C, Bigint *b, int p2) -{ - int rv = hi0bits(C, b->x[b->wds-1]) - 4; - if (p2 > 0) - rv -= p2; - return rv & kmask; - } - - static int -quorem - (struct dtoa_context* C, Bigint *b, Bigint *S) -{ - int n; - ULong *bx, *bxe, q, *sx, *sxe; -#ifdef ULLong - ULLong borrow, carry, y, ys; -#else - ULong borrow, carry, y, ys; -#ifdef Pack_32 - ULong si, z, zs; -#endif -#endif - - n = S->wds; -#ifdef DEBUG - /*debug*/ if (b->wds > n) - /*debug*/ Bug("oversize b in quorem"); -#endif - if (b->wds < n) - return 0; - sx = S->x; - sxe = sx + --n; - bx = b->x; - bxe = bx + n; - q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ -#ifdef DEBUG -#ifdef NO_STRTOD_BIGCOMP - /*debug*/ if (q > 9) -#else - /* An oversized q is possible when quorem is called from bigcomp and */ - /* the input is near, e.g., twice the smallest denormalized number. */ - /*debug*/ if (q > 15) -#endif - /*debug*/ Bug("oversized quotient in quorem"); -#endif - if (q) { - borrow = 0; - carry = 0; - do { -#ifdef ULLong - ys = *sx++ * (ULLong)q + carry; - carry = ys >> 32; - y = *bx - (ys & FFFFFFFF) - borrow; - borrow = y >> 32 & (ULong)1; - *bx++ = y & FFFFFFFF; -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } - while(sx <= sxe); - if (!*bxe) { - bx = b->x; - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - if (cmp(C, b, S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = b->x; - sx = S->x; - do { -#ifdef ULLong - ys = *sx++ + carry; - carry = ys >> 32; - y = *bx - (ys & FFFFFFFF) - borrow; - borrow = y >> 32 & (ULong)1; - *bx++ = y & FFFFFFFF; -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } - while(sx <= sxe); - bx = b->x; - bxe = bx + n; - if (!*bxe) { - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - return q; - } - -#if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/ - static double -sulp - (struct dtoa_context* C, U *x, BCinfo *bc) -{ - U u; - double rv; - int i; - - rv = ulp(C, x); - if (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) - return rv; /* Is there an example where i <= 0 ? */ - word0(&u) = Exp_1 + (i << Exp_shift); - word1(&u) = 0; - return rv * u.d; - } -#endif /*}*/ - -#ifndef NO_STRTOD_BIGCOMP - static void -bigcomp - (struct dtoa_context* C, U *rv, const char *s0, BCinfo *bc) -{ - Bigint *b, *d; - int b2, bbits, d2, dd=0, dig, dsign, i, j, nd, nd0, p2, p5, speccase; - - dsign = bc->dsign; - nd = bc->nd; - nd0 = bc->nd0; - p5 = nd + bc->e0 - 1; - speccase = 0; -#ifndef Sudden_Underflow - if (rv->d == 0.) { /* special case: value near underflow-to-zero */ - /* threshold was rounded to zero */ - b = i2b(C, 1); - p2 = Emin - P + 1; - bbits = 1; -#ifdef Avoid_Underflow - word0(rv) = (P+2) << Exp_shift; -#else - word1(rv) = 1; -#endif - i = 0; -#ifdef Honor_FLT_ROUNDS - if (bc->rounding == 1) -#endif - { - speccase = 1; - --p2; - dsign = 0; - goto have_i; - } - } - else -#endif - b = d2b(C, rv, &p2, &bbits); -#ifdef Avoid_Underflow - p2 -= bc->scale; -#endif - /* floor(log2(rv)) == bbits - 1 + p2 */ - /* Check for denormal case. */ - i = P - bbits; - if (i > (j = P - Emin - 1 + p2)) { -#ifdef Sudden_Underflow - Bfree(C, b); - b = i2b(C, 1); - p2 = Emin; - i = P - 1; -#ifdef Avoid_Underflow - word0(rv) = (1 + bc->scale) << Exp_shift; -#else - word0(rv) = Exp_msk1; -#endif - word1(rv) = 0; -#else - i = j; -#endif - } -#ifdef Honor_FLT_ROUNDS - if (bc->rounding != 1) { - if (i > 0) - b = lshift(C, b, i); - if (dsign) - b = increment(b); - } - else -#endif - { - b = lshift(C, b, ++i); - b->x[0] |= 1; - } -#ifndef Sudden_Underflow - have_i: -#endif - p2 -= p5 + i; - d = i2b(C, 1); - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - */ - if (p5 > 0) - d = pow5mult(C, d, p5); - else if (p5 < 0) - b = pow5mult(C, b, -p5); - if (p2 > 0) { - b2 = p2; - d2 = 0; - } - else { - b2 = 0; - d2 = -p2; - } - i = dshift(C, d, d2); - if ((b2 += i) > 0) - b = lshift(C, b, b2); - if ((d2 += i) > 0) - d = lshift(C, d, d2); - - /* Now b/d = exactly half-way between the two floating-point values */ - /* on either side of the input string. Compute first digit of b/d. */ - - if (!(dig = quorem(C, b,d))) { - b = multadd(C, b, 10, 0); /* very unlikely */ - dig = quorem(C, b,d); - } - - /* Compare b/d with s0 */ - - for(i = 0; i < nd0; ) { - if ((dd = s0[i++] - '0' - dig)) - goto ret; - if (!b->x[0] && b->wds == 1) { - if (i < nd) - dd = 1; - goto ret; - } - b = multadd(C, b, 10, 0); - dig = quorem(C, b,d); - } - for(j = bc->dp1; i++ < nd;) { - if ((dd = s0[j++] - '0' - dig)) - goto ret; - if (!b->x[0] && b->wds == 1) { - if (i < nd) - dd = 1; - goto ret; - } - b = multadd(C, b, 10, 0); - dig = quorem(C, b,d); - } - if (dig > 0 || b->x[0] || b->wds > 1) - dd = -1; - ret: - Bfree(C, b); - Bfree(C, d); -#ifdef Honor_FLT_ROUNDS - if (bc->rounding != 1) { - if (dd < 0) { - if (bc->rounding == 0) { - if (!dsign) - goto retlow1; - } - else if (dsign) - goto rethi1; - } - else if (dd > 0) { - if (bc->rounding == 0) { - if (dsign) - goto rethi1; - goto ret1; - } - if (!dsign) - goto rethi1; - dval(rv) += 2.*sulp(C, rv,bc); - } - else { - bc->inexact = 0; - if (dsign) - goto rethi1; - } - } - else -#endif - if (speccase) { - if (dd <= 0) - rv->d = 0.; - } - else if (dd < 0) { - if (!dsign) /* does not happen for round-near */ -retlow1: - dval(rv) -= sulp(C, rv,bc); - } - else if (dd > 0) { - if (dsign) { - rethi1: - dval(rv) += sulp(C, rv,bc); - } - } - else { - /* Exact half-way case: apply round-even rule. */ - if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) { - i = 1 - j; - if (i <= 31) { - if (word1(rv) & (0x1 << i)) - goto odd; - } - else if (word0(rv) & (0x1 << (i-32))) - goto odd; - } - else if (word1(rv) & 1) { - odd: - if (dsign) - goto rethi1; - goto retlow1; - } - } - -#ifdef Honor_FLT_ROUNDS - ret1: -#endif - return; - } -#endif /* NO_STRTOD_BIGCOMP */ - - double -jvp_strtod - (struct dtoa_context* C, const char *s00, char **se) -{ - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1, test_scale; - int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign; - CONST char *s, *s0, *s1; - double aadj, aadj1; - Long L; - U aadj2, adj, rv, rv0; - ULong y, z; - BCinfo bc; - Bigint *bb=0, *bb1, *bd=0, *bd0, *bs=0, *delta=0; -#ifdef Avoid_Underflow - ULong Lsb, Lsb1; -#endif -#ifdef SET_INEXACT - int oldinexact; -#endif -#ifndef NO_STRTOD_BIGCOMP - int req_bigcomp = 0; -#endif -#ifdef Honor_FLT_ROUNDS /*{*/ -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - bc.rounding = Flt_Rounds; -#else /*}{*/ - bc.rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: bc.rounding = 0; break; - case FE_UPWARD: bc.rounding = 2; break; - case FE_DOWNWARD: bc.rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ -#ifdef USE_LOCALE - CONST char *s2; -#endif - - sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0; - dval(&rv) = 0.; - for(s = s00;;s++) switch(*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - goto ret0; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } - break2: - if (*s == '0') { -#ifndef NO_HEX_FP /*{*/ - switch(s[1]) { - case 'x': - case 'X': -#ifdef Honor_FLT_ROUNDS - gethex(C, &s, &rv, bc.rounding, sign); -#else - gethex(C, &s, &rv, 1, sign); -#endif - goto ret; - } -#endif /*}*/ - nz0 = 1; - while(*++s == '0') ; - if (!*s) - goto ret; - } - s0 = s; - y = z = 0; - for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; - bc.dp0 = bc.dp1 = s - s0; - for(s1 = s; s1 > s0 && *--s1 == '0'; ) - ++nz1; -#ifdef USE_LOCALE - s1 = localeconv()->decimal_point; - if (c == *s1) { - c = '.'; - if (*++s1) { - s2 = s; - for(;;) { - if (*++s2 != *s1) { - c = 0; - break; - } - if (!*++s1) { - s = s2; - break; - } - } - } - } -#endif - if (c == '.') { - c = *++s; - bc.dp1 = s - s0; - bc.dplen = bc.dp1 - bc.dp0; - if (!nd) { - for(; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - bc.dp0 = s0 - s; - bc.dp1 = bc.dp0 + bc.dplen; - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for(; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for(i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = nz1 = 0; - } - } - } - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - goto ret0; - } - s00 = s; - esign = 0; - switch(c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while(c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = (int)L; - if (esign) - e = -e; - } - else - e = 0; - } - else - s = s00; - } - if (!nd) { - if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - if (!bc.dplen) - switch(c) { - case 'i': - case 'I': - if (match(C, &s,"nf")) { - --s; - if (!match(C, &s,"inity")) - ++s; - word0(&rv) = 0x7ff00000; - word1(&rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (match(C, &s, "an")) { - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; -#ifndef No_Hex_NaN - if (*s == '(') /*)*/ - hexnan(C, &rv, &s); -#endif - goto ret; - } - } -#endif /* INFNAN_CHECK */ - ret0: - s = s00; - sign = 0; - } - goto ret; - } - bc.e0 = e1 = e -= nf; - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - dval(&rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) - oldinexact = get_inexact(); -#endif - dval(&rv) = tens[k - 9] * dval(&rv) + z; - } - bd0 = 0; - if (nd <= DBL_DIG -#ifndef RND_PRODQUOT -#ifndef Honor_FLT_ROUNDS - && Flt_Rounds == 1 -#endif -#endif - ) { - if (!e) - goto ret; -#ifndef ROUND_BIASED_without_Round_Up - if (e > 0) { - if (e <= Ten_pmax) { -#ifdef VAX - goto vax_ovfl_check; -#else -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_product(dval(&rv), tens[e]); - goto ret; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - e -= i; - dval(&rv) *= tens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - word0(&rv) -= P*Exp_msk1; - /* rv = */ rounded_product(dval(&rv), tens[e]); - if ((word0(&rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) - goto ovfl; - word0(&rv) += P*Exp_msk1; -#else - /* rv = */ rounded_product(dval(&rv), tens[e]); -#endif - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_quotient(dval(&rv), tens[-e]); - goto ret; - } -#endif -#endif /* ROUND_BIASED_without_Round_Up */ - } - e1 += nd - k; - -#ifdef IEEE_Arith -#ifdef SET_INEXACT - bc.inexact = 1; - if (k <= DBL_DIG) - oldinexact = get_inexact(); -#endif -#ifdef Avoid_Underflow - bc.scale = 0; -#endif -#ifdef Honor_FLT_ROUNDS - if (bc.rounding >= 2) { - if (sign) - bc.rounding = bc.rounding == 2 ? 0 : 2; - else - if (bc.rounding != 2) - bc.rounding = 0; - } -#endif -#endif /*IEEE_Arith*/ - - /* Get starting approximation = rv * 10**e1 */ - - if (e1 > 0) { - if ((i = e1 & 15)) - dval(&rv) *= tens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { - ovfl: - /* Can't trust HUGE_VAL */ -#ifdef IEEE_Arith -#ifdef Honor_FLT_ROUNDS - switch(bc.rounding) { - case 0: /* toward 0 */ - case 3: /* toward -infinity */ - word0(&rv) = Big0; - word1(&rv) = Big1; - break; - default: - word0(&rv) = Exp_mask; - word1(&rv) = 0; - } -#else /*Honor_FLT_ROUNDS*/ - word0(&rv) = Exp_mask; - word1(&rv) = 0; -#endif /*Honor_FLT_ROUNDS*/ -#ifdef SET_INEXACT - /* set overflow bit */ - dval(&rv0) = 1e300; - dval(&rv0) *= dval(&rv0); -#endif -#else /*IEEE_Arith*/ - word0(&rv) = Big0; - word1(&rv) = Big1; -#endif /*IEEE_Arith*/ - range_err: - if (bd0) { - Bfree(C, bb); - Bfree(C, bd); - Bfree(C, bs); - Bfree(C, bd0); - Bfree(C, delta); - } -#ifndef NO_ERRNO - errno = ERANGE; -#endif - goto ret; - } - e1 >>= 4; - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= bigtens[j]; - /* The last multiplication could overflow. */ - word0(&rv) -= P*Exp_msk1; - dval(&rv) *= bigtens[j]; - if ((z = word0(&rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-P)) - goto ovfl; - if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - word0(&rv) = Big0; - word1(&rv) = Big1; - } - else - word0(&rv) += P*Exp_msk1; - } - } - else if (e1 < 0) { - e1 = -e1; - if ((i = e1 & 15)) - dval(&rv) /= tens[i]; - if (e1 >>= 4) { - if (e1 >= 1 << n_bigtens) - goto undfl; -#ifdef Avoid_Underflow - if (e1 & Scale_Bit) - bc.scale = 2*P; - for(j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) - >> Exp_shift)) > 0) { - /* scaled rv is denormal; clear j low bits */ - if (j >= 32) { - if (j > 54) - goto undfl; - word1(&rv) = 0; - if (j >= 53) - word0(&rv) = (P+2)*Exp_msk1; - else - word0(&rv) &= 0xffffffff << (j-32); - } - else - word1(&rv) &= 0xffffffff << j; - } -#else - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - /* The last multiplication could underflow. */ - dval(&rv0) = dval(&rv); - dval(&rv) *= tinytens[j]; - if (!dval(&rv)) { - dval(&rv) = 2.*dval(&rv0); - dval(&rv) *= tinytens[j]; -#endif - if (!dval(&rv)) { - undfl: - dval(&rv) = 0.; - goto range_err; - } -#ifndef Avoid_Underflow - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif - } - } - - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ - - bc.nd = nd - nz1; -#ifndef NO_STRTOD_BIGCOMP - bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */ - /* to silence an erroneous warning about bc.nd0 */ - /* possibly not being initialized. */ - if (nd > strtod_diglim) { - /* ASSERT(strtod_diglim >= 18); 18 == one more than the */ - /* minimum number of decimal digits to distinguish double values */ - /* in IEEE arithmetic. */ - i = j = 18; - if (i > nd0) - j += bc.dplen; - for(;;) { - if (--j < bc.dp1 && j >= bc.dp0) - j = bc.dp0 - 1; - if (s0[j] != '0') - break; - --i; - } - e += nd - i; - nd = i; - if (nd0 > nd) - nd0 = nd; - if (nd < 9) { /* must recompute y */ - y = 0; - for(i = 0; i < nd0; ++i) - y = 10*y + s0[i] - '0'; - for(j = bc.dp1; i < nd; ++i) - y = 10*y + s0[j++] - '0'; - } - } -#endif - bd0 = s2b(C, s0, nd0, nd, y, bc.dplen); - - for(;;) { - bd = Balloc(C, bd0->k); - Bcopy(bd, bd0); - bb = d2b(C, &rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(C, 1); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; -#ifdef Honor_FLT_ROUNDS - if (bc.rounding != 1) - bs2++; -#endif -#ifdef Avoid_Underflow - Lsb = LSB; - Lsb1 = 0; - j = bbe - bc.scale; - i = j + bbbits - 1; /* logb(rv) */ - j = P + 1 - bbbits; - if (i < Emin) { /* denormal */ - i = Emin - i; - j -= i; - if (i < 32) - Lsb <<= i; - else if (i < 52) - Lsb1 = Lsb << (i-32); - else - Lsb1 = Exp_mask; - } -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow -#ifdef IBM - j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); -#else - j = P + 1 - bbbits; -#endif -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - bb2 += j; - bd2 += j; -#ifdef Avoid_Underflow - bd2 += bc.scale; -#endif - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(C, bs, bb5); - bb1 = mult(C, bs, bb); - Bfree(C, bb); - bb = bb1; - } - if (bb2 > 0) - bb = lshift(C, bb, bb2); - if (bd5 > 0) - bd = pow5mult(C, bd, bd5); - if (bd2 > 0) - bd = lshift(C, bd, bd2); - if (bs2 > 0) - bs = lshift(C, bs, bs2); - delta = diff(C, bb, bd); - bc.dsign = delta->sign; - delta->sign = 0; - i = cmp(C, delta, bs); -#ifndef NO_STRTOD_BIGCOMP /*{*/ - if (bc.nd > nd && i <= 0) { - if (bc.dsign) { - /* Must use bigcomp(C, ). */ - req_bigcomp = 1; - break; - } -#ifdef Honor_FLT_ROUNDS - if (bc.rounding != 1) { - if (i < 0) { - req_bigcomp = 1; - break; - } - } - else -#endif - i = -1; /* Discarded digits make delta smaller. */ - } -#endif /*}*/ -#ifdef Honor_FLT_ROUNDS /*{*/ - if (bc.rounding != 1) { - if (i < 0) { - /* Error is less than an ulp */ - if (!delta->x[0] && delta->wds <= 1) { - /* exact */ -#ifdef SET_INEXACT - bc.inexact = 0; -#endif - break; - } - if (bc.rounding) { - if (bc.dsign) { - adj.d = 1.; - goto apply_adj; - } - } - else if (!bc.dsign) { - adj.d = -1.; - if (!word1(&rv) - && !(word0(&rv) & Frac_mask)) { - y = word0(&rv) & Exp_mask; - test_scale = y; -#ifdef Avoid_Underflow - test_scale = (!bc.scale || y > 2*P*Exp_msk1); -#endif - if (test_scale) { - delta = lshift(C, delta,Log2P); - if (cmp(C, delta, bs) <= 0) - adj.d = -0.5; - } - } - apply_adj: -#ifdef Avoid_Underflow /*{*/ - if (bc.scale && (y = word0(&rv) & Exp_mask) - <= 2*P*Exp_msk1) - word0(&adj) += (2*P+1)*Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= - P*Exp_msk1) { - word0(&rv) += P*Exp_msk1; - dval(&rv) += adj.d*ulp(C, dval(&rv)); - word0(&rv) -= P*Exp_msk1; - } - else -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow}*/ - dval(&rv) += adj.d*ulp(C, &rv); - } - break; - } - adj.d = ratio(C, delta, bs); - if (adj.d < 1.) - adj.d = 1.; - if (adj.d <= 0x7ffffffe) { - /* adj = rounding ? ceil(adj) : floor(adj); */ - y = adj.d; - if (y != adj.d) { - if (!((bc.rounding>>1) ^ bc.dsign)) - y++; - adj.d = y; - } - } -#ifdef Avoid_Underflow /*{*/ - if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) - word0(&adj) += (2*P+1)*Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { - word0(&rv) += P*Exp_msk1; - adj.d *= ulp(C, dval(&rv)); - if (bc.dsign) - dval(&rv) += adj.d; - else - dval(&rv) -= adj.d; - word0(&rv) -= P*Exp_msk1; - goto cont; - } -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow}*/ - adj.d *= ulp(C, &rv); - if (bc.dsign) { - if (word0(&rv) == Big0 && word1(&rv) == Big1) - goto ovfl; - dval(&rv) += adj.d; - } - else - dval(&rv) -= adj.d; - goto cont; - } -#endif /*}Honor_FLT_ROUNDS*/ - - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask -#ifdef IEEE_Arith /*{*/ -#ifdef Avoid_Underflow - || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 -#else - || (word0(&rv) & Exp_mask) <= Exp_msk1 -#endif -#endif /*}*/ - ) { -#ifdef SET_INEXACT - if (!delta->x[0] && delta->wds <= 1) - bc.inexact = 0; -#endif - break; - } - if (!delta->x[0] && delta->wds <= 1) { - /* exact result */ -#ifdef SET_INEXACT - bc.inexact = 0; -#endif - break; - } - delta = lshift(C, delta,Log2P); - if (cmp(C, delta, bs) > 0) - goto drop_down; - break; - } - if (i == 0) { - /* exactly half-way between */ - if (bc.dsign) { - if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 - && word1(&rv) == ( -#ifdef Avoid_Underflow - (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) - ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : -#endif - 0xffffffff)) { - /*boundary case -- increment exponent*/ - if (word0(&rv) == Big0 && word1(&rv) == Big1) - goto ovfl; - word0(&rv) = (word0(&rv) & Exp_mask) - + Exp_msk1 -#ifdef IBM - | Exp_msk1 >> 4 -#endif - ; - word1(&rv) = 0; -#ifdef Avoid_Underflow - bc.dsign = 0; -#endif - break; - } - } - else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { - drop_down: - /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(&rv) & Exp_mask; -#ifdef IBM - if (L < Exp_msk1) -#else -#ifdef Avoid_Underflow - if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ -#endif /*IBM*/ - { - if (bc.nd >nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow - if (bc.scale) { - L = word0(&rv) & Exp_mask; - if (L <= (2*P+1)*Exp_msk1) { - if (L > (P+2)*Exp_msk1) - /* round even ==> */ - /* accept rv */ - break; - /* rv = smallest denormal */ - if (bc.nd >nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } - } -#endif /*Avoid_Underflow*/ - L = (word0(&rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ - word0(&rv) = L | Bndry_mask1; - word1(&rv) = 0xffffffff; -#ifdef IBM - goto cont; -#else -#ifndef NO_STRTOD_BIGCOMP - if (bc.nd > nd) - goto cont; -#endif - break; -#endif - } -#ifndef ROUND_BIASED -#ifdef Avoid_Underflow - if (Lsb1) { - if (!(word0(&rv) & Lsb1)) - break; - } - else if (!(word1(&rv) & Lsb)) - break; -#else - if (!(word1(&rv) & LSB)) - break; -#endif -#endif - if (bc.dsign) -#ifdef Avoid_Underflow - dval(&rv) += sulp(C, &rv, &bc); -#else - dval(&rv) += ulp(C, &rv); -#endif -#ifndef ROUND_BIASED - else { -#ifdef Avoid_Underflow - dval(&rv) -= sulp(C, &rv, &bc); -#else - dval(&rv) -= ulp(C, &rv); -#endif -#ifndef Sudden_Underflow - if (!dval(&rv)) { - if (bc.nd >nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } -#endif - } -#ifdef Avoid_Underflow - bc.dsign = 1 - bc.dsign; -#endif -#endif - break; - } - if ((aadj = ratio(C, delta, bs)) <= 2.) { - if (bc.dsign) - aadj = aadj1 = 1.; - else if (word1(&rv) || word0(&rv) & Bndry_mask) { -#ifndef Sudden_Underflow - if (word1(&rv) == Tiny1 && !word0(&rv)) { - if (bc.nd >nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } -#endif - aadj = 1.; - aadj1 = -1.; - } - else { - /* special case -- power of FLT_RADIX to be */ - /* rounded down... */ - - if (aadj < 2./FLT_RADIX) - aadj = 1./FLT_RADIX; - else - aadj *= 0.5; - aadj1 = -aadj; - } - } - else { - aadj *= 0.5; - aadj1 = bc.dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch(bc.rounding) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (Flt_Rounds == 0) - aadj1 += 0.5; -#endif /*Check_FLT_ROUNDS*/ - } - y = word0(&rv) & Exp_mask; - - /* Check for overflow */ - - if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { - dval(&rv0) = dval(&rv); - word0(&rv) -= P*Exp_msk1; - adj.d = aadj1 * ulp(C, &rv); - dval(&rv) += adj.d; - if ((word0(&rv) & Exp_mask) >= - Exp_msk1*(DBL_MAX_EXP+Bias-P)) { - if (word0(&rv0) == Big0 && word1(&rv0) == Big1) - goto ovfl; - word0(&rv) = Big0; - word1(&rv) = Big1; - goto cont; - } - else - word0(&rv) += P*Exp_msk1; - } - else { -#ifdef Avoid_Underflow - if (bc.scale && y <= 2*P*Exp_msk1) { - if (aadj <= 0x7fffffff) { - if ((z = aadj) <= 0) - z = 1; - aadj = z; - aadj1 = bc.dsign ? aadj : -aadj; - } - dval(&aadj2) = aadj1; - word0(&aadj2) += (2*P+1)*Exp_msk1 - y; - aadj1 = dval(&aadj2); - adj.d = aadj1 * ulp(C, &rv); - dval(&rv) += adj.d; - if (rv.d == 0.) -#ifdef NO_STRTOD_BIGCOMP - goto undfl; -#else - { - if (bc.nd > nd) - bc.dsign = 1; - break; - } -#endif - } - else { - adj.d = aadj1 * ulp(C, &rv); - dval(&rv) += adj.d; - } -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { - dval(&rv0) = dval(&rv); - word0(&rv) += P*Exp_msk1; - adj.d = aadj1 * ulp(C, &rv); - dval(&rv) += adj.d; -#ifdef IBM - if ((word0(&rv) & Exp_mask) < P*Exp_msk1) -#else - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) -#endif - { - if (word0(&rv0) == Tiny0 - && word1(&rv0) == Tiny1) { - if (bc.nd >nd) { - bc.uflchk = 1; - break; - } - goto undfl; - } - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - goto cont; - } - else - word0(&rv) -= P*Exp_msk1; - } - else { - adj.d = aadj1 * ulp(C, &rv); - dval(&rv) += adj.d; - } -#else /*Sudden_Underflow*/ - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(C, rv) is denormalized (i.e., - * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P-1)*Exp_msk1 && aadj > 1.) { - aadj1 = (double)(int)(aadj + 0.5); - if (!bc.dsign) - aadj1 = -aadj1; - } - adj.d = aadj1 * ulp(C, &rv); - dval(&rv) += adj.d; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - } - z = word0(&rv) & Exp_mask; -#ifndef SET_INEXACT - if (bc.nd == nd) { -#ifdef Avoid_Underflow - if (!bc.scale) -#endif - if (y == z) { - /* Can we stop now? */ - L = (Long)aadj; - aadj -= L; - /* The tolerances below are conservative. */ - if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) - break; - } - else if (aadj < .4999999/FLT_RADIX) - break; - } - } -#endif - cont: - Bfree(C, bb); - Bfree(C, bd); - Bfree(C, bs); - Bfree(C, delta); - } - Bfree(C, bb); - Bfree(C, bd); - Bfree(C, bs); - Bfree(C, bd0); - Bfree(C, delta); -#ifndef NO_STRTOD_BIGCOMP - if (req_bigcomp) { - bd0 = 0; - bc.e0 += nz1; - bigcomp(C, &rv, s0, &bc); - y = word0(&rv) & Exp_mask; - if (y == Exp_mask) - goto ovfl; - if (y == 0 && rv.d == 0.) - goto undfl; - } -#endif -#ifdef SET_INEXACT - if (bc.inexact) { - if (!oldinexact) { - word0(&rv0) = Exp_1 + (70 << Exp_shift); - word1(&rv0) = 0; - dval(&rv0) += 1.; - } - } - else if (!oldinexact) - clear_inexact(); -#endif -#ifdef Avoid_Underflow - if (bc.scale) { - word0(&rv0) = Exp_1 - 2*P*Exp_msk1; - word1(&rv0) = 0; - dval(&rv) *= dval(&rv0); -#ifndef NO_ERRNO - /* try to avoid the bug of testing an 8087 register value */ -#ifdef IEEE_Arith - if (!(word0(&rv) & Exp_mask)) -#else - if (word0(&rv) == 0 && word1(&rv) == 0) -#endif - errno = ERANGE; -#endif - } -#endif /* Avoid_Underflow */ -#ifdef SET_INEXACT - if (bc.inexact && !(word0(&rv) & Exp_mask)) { - /* set underflow bit */ - dval(&rv0) = 1e-300; - dval(&rv0) *= dval(&rv0); - } -#endif - ret: - if (se) - *se = (char *)s; - return sign ? -dval(&rv) : dval(&rv); - } - - static char * -rv_alloc(struct dtoa_context* C, int i) -{ - int j, k, *r; - - j = sizeof(ULong); - for(k = 0; - (int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i; - j <<= 1) - k++; - r = (int*)Balloc(C, k); - *r = k; - return - (char *)(r+1); - } - - static char * -nrv_alloc(struct dtoa_context* C, const char *s, char **rve, int n) -{ - char *rv, *t; - - t = rv = rv_alloc(C, n); - while((*t = *s++)) t++; - if (rve) - *rve = t; - return rv; - } - -/* freedtoa(s) must be used to free values s returned by dtoa - * when MULTIPLE_THREADS is #defined. It should be used in all cases, - * but for consistency with earlier versions of dtoa, it is optional - * when MULTIPLE_THREADS is not defined. - */ - - void -jvp_freedtoa(struct dtoa_context* C, char *s) -{ - Bigint *b = (Bigint *)((int *)s - 1); - b->maxwds = 1 << (b->k = *(int*)b); - Bfree(C, b); - } - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - - char * -jvp_dtoa - (struct dtoa_context* C, double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) -{ - /* Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4,5 ==> similar to 2 and 3, respectively, but (in - round-nearest mode) with the tests of mode 0 to - possibly return a shorter string that rounds to d. - With IEEE arithmetic and compilation with - -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same - as modes 2 and 3 when FLT_ROUNDS != 1. - 6-9 ==> Debugging modes similar to mode - 4: don't try - fast floating-point estimate (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - */ - - int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, - j, j1=0, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; - Long L; -#ifndef Sudden_Underflow - int denorm; - ULong x; -#endif - Bigint *b, *b1, *delta, *mlo, *mhi, *S; - U d2, eps, u; - double ds; - char *s, *s0; -#ifndef No_leftright -#ifdef IEEE_Arith - U eps1; -#endif -#endif -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif -#ifdef Honor_FLT_ROUNDS /*{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ - - - u.d = dd; - if (word0(&u) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(&u) &= ~Sign_bit; /* clear sign bit */ - } - else - *sign = 0; - -#if defined(IEEE_Arith) + defined(VAX) -#ifdef IEEE_Arith - if ((word0(&u) & Exp_mask) == Exp_mask) -#else - if (word0(&u) == 0x8000) -#endif - { - /* Infinity or NaN */ - *decpt = 9999; -#ifdef IEEE_Arith - if (!word1(&u) && !(word0(&u) & 0xfffff)) - return nrv_alloc(C, "Infinity", rve, 8); -#endif - return nrv_alloc(C, "NaN", rve, 3); - } -#endif -#ifdef IBM - dval(&u) += 0; /* normalize */ -#endif - if (!dval(&u)) { - *decpt = 1; - return nrv_alloc(C, "0", rve, 1); - } - -#ifdef SET_INEXACT - try_quick = oldinexact = get_inexact(); - inexact = 1; -#endif -#ifdef Honor_FLT_ROUNDS - if (Rounding >= 2) { - if (*sign) - Rounding = Rounding == 2 ? 0 : 2; - else - if (Rounding != 2) - Rounding = 0; - } -#endif - - b = d2b(C, &u, &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); -#else - if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { -#endif - dval(&d2) = dval(&u); - word0(&d2) &= Frac_mask1; - word0(&d2) |= Exp_11; -#ifdef IBM - if (j = 11 - hi0bits(C, word0(&d2) & Frac_mask)) - dval(&d2) /= 1 << j; -#endif - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ - - i -= Bias; -#ifdef IBM - i <<= 2; - i += j; -#endif -#ifndef Sudden_Underflow - denorm = 0; - } - else { - /* d is denormalized */ - - i = bbits + be + (Bias + (P-1) - 1); - x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) - : word1(&u) << (32 - i); - dval(&d2) = x; - word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ - i -= (Bias + (P-1) - 1) + 1; - denorm = 1; - } -#endif - ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - k = (int)ds; - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (dval(&u) < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - if (mode < 0 || mode > 9) - mode = 0; - -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#else - try_quick = 1; -#endif -#endif /*SET_INEXACT*/ - - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - leftright = 1; - ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ - /* silence erroneous "gcc -Wall" warning. */ - switch(mode) { - case 0: - case 1: - i = 18; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - s = s0 = rv_alloc(C, i); - -#ifdef Honor_FLT_ROUNDS - if (mode > 1 && Rounding != 1) - leftright = 0; -#endif - - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - dval(&d2) = dval(&u); - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - dval(&u) /= bigtens[n_bigtens-1]; - ieps++; - } - for(; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - dval(&u) /= ds; - } - else if ((j1 = -k)) { - dval(&u) *= tens[j1 & 0xf]; - for(j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - dval(&u) *= bigtens[i]; - } - } - if (k_check && dval(&u) < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - dval(&u) *= 10.; - ieps++; - } - dval(&eps) = ieps*dval(&u) + 7.; - word0(&eps) -= (P-1)*Exp_msk1; - if (ilim == 0) { - S = mhi = 0; - dval(&u) -= 5.; - if (dval(&u) > dval(&eps)) - goto one_digit; - if (dval(&u) < -dval(&eps)) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); -#ifdef IEEE_Arith - if (k0 < 0 && j1 >= 307) { - eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */ - word0(&eps1) -= Exp_msk1 * (Bias+P-1); - dval(&eps1) *= tens[j1 & 0xf]; - for(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++) - if (j & 1) - dval(&eps1) *= bigtens[i]; - if (eps.d < eps1.d) - eps.d = eps1.d; - } -#endif - for(i = 0;;) { - L = dval(&u); - dval(&u) -= L; - *s++ = '0' + (int)L; - if (1. - dval(&u) < dval(&eps)) - goto bump_up; - if (dval(&u) < dval(&eps)) - goto ret1; - if (++i >= ilim) - break; - dval(&eps) *= 10.; - dval(&u) *= 10.; - } - } - else { -#endif - /* Generate ilim digits, then fix them up. */ - dval(&eps) *= tens[ilim-1]; - for(i = 1;; i++, dval(&u) *= 10.) { - L = (Long)(dval(&u)); - if (!(dval(&u) -= L)) - ilim = i; - *s++ = '0' + (int)L; - if (i == ilim) { - if (dval(&u) > 0.5 + dval(&eps)) - goto bump_up; - else if (dval(&u) < 0.5 - dval(&eps)) { - while(*--s == '0'); - s++; - goto ret1; - } - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = s0; - dval(&u) = dval(&d2); - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= Int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || dval(&u) <= 5*ds) - goto no_digits; - goto one_digit; - } - for(i = 1;; i++, dval(&u) *= 10.) { - L = (Long)(dval(&u) / ds); - dval(&u) -= L*ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&u) < 0) { - L--; - dval(&u) += ds; - } -#endif - *s++ = '0' + (int)L; - if (!dval(&u)) { -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - if (i == ilim) { -#ifdef Honor_FLT_ROUNDS - if (mode > 1) - switch(Rounding) { - case 0: goto ret1; - case 2: goto bump_up; - } -#endif - dval(&u) += dval(&u); -#ifdef ROUND_BIASED - if (dval(&u) >= ds) -#else - if (dval(&u) > ds || (dval(&u) == ds && L & 1)) -#endif - { - bump_up: - while(*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - break; - } - } - goto ret1; - } - - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P-1) - 1 + 1) : -#endif -#ifdef IBM - 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); -#else - 1 + P - bbits; -#endif - b2 += i; - s2 += i; - mhi = i2b(C, 1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(C, mhi, m5); - b1 = mult(C, mhi, b); - Bfree(C, b); - b = b1; - } - if ((j = b5 - m5)) - b = pow5mult(C, b, j); - } - else - b = pow5mult(C, b, b5); - } - S = i2b(C, 1); - if (s5 > 0) - S = pow5mult(C, S, s5); - - /* Check for special case that d is a normalized power of 2. */ - - spec_case = 0; - if ((mode < 2 || leftright) -#ifdef Honor_FLT_ROUNDS - && Rounding == 1 -#endif - ) { - if (!word1(&u) && !(word0(&u) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(&u) & (Exp_mask & ~Exp_msk1) -#endif - ) { - /* The special case */ - b2 += Log2P; - s2 += Log2P; - spec_case = 1; - } - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ - i = dshift(C, S, s2); - b2 += i; - m2 += i; - s2 += i; - if (b2 > 0) - b = lshift(C, b, b2); - if (s2 > 0) - S = lshift(C, S, s2); - if (k_check) { - if (cmp(C, b,S) < 0) { - k--; - b = multadd(C, b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(C, mhi, 10, 0); - ilim = ilim1; - } - } - if (ilim <= 0 && (mode == 3 || mode == 5)) { - if (ilim < 0 || cmp(C, b,S = multadd(C, S,5,0)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - goto ret; - } - one_digit: - *s++ = '1'; - k++; - goto ret; - } - if (leftright) { - if (m2 > 0) - mhi = lshift(C, mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(C, mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(C, mhi, Log2P); - } - - for(i = 1;;i++) { - dig = quorem(C, b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(C, b, mlo); - delta = diff(C, S, mhi); - j1 = delta->sign ? 1 : cmp(C, b, delta); - Bfree(C, delta); -#ifndef ROUND_BIASED - if (j1 == 0 && mode != 1 && !(word1(&u) & 1) -#ifdef Honor_FLT_ROUNDS - && Rounding >= 1 -#endif - ) { - if (dig == '9') - goto round_9_up; - if (j > 0) - dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && mode != 1 -#ifndef ROUND_BIASED - && !(word1(&u) & 1) -#endif - )) { - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto accept_dig; - } -#ifdef Honor_FLT_ROUNDS - if (mode > 1) - switch(Rounding) { - case 0: goto accept_dig; - case 2: goto keep_dig; - } -#endif /*Honor_FLT_ROUNDS*/ - if (j1 > 0) { - b = lshift(C, b, 1); - j1 = cmp(C, b, S); -#ifdef ROUND_BIASED - if (j1 >= 0 /*)*/ -#else - if ((j1 > 0 || (j1 == 0 && dig & 1)) -#endif - && dig++ == '9') - goto round_9_up; - } - accept_dig: - *s++ = dig; - goto ret; - } - if (j1 > 0) { -#ifdef Honor_FLT_ROUNDS - if (!Rounding) - goto accept_dig; -#endif - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = dig + 1; - goto ret; - } -#ifdef Honor_FLT_ROUNDS - keep_dig: -#endif - *s++ = dig; - if (i == ilim) - break; - b = multadd(C, b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(C, mhi, 10, 0); - else { - mlo = multadd(C, mlo, 10, 0); - mhi = multadd(C, mhi, 10, 0); - } - } - } - else - for(i = 1;; i++) { - *s++ = dig = quorem(C, b,S) + '0'; - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto ret; - } - if (i >= ilim) - break; - b = multadd(C, b, 10, 0); - } - - /* Round off last digit */ - -#ifdef Honor_FLT_ROUNDS - switch(Rounding) { - case 0: goto trimzeros; - case 2: goto roundoff; - } -#endif - b = lshift(C, b, 1); - j = cmp(C, b, S); -#ifdef ROUND_BIASED - if (j >= 0) -#else - if (j > 0 || (j == 0 && dig & 1)) -#endif - { - roundoff: - while(*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { -#ifdef Honor_FLT_ROUNDS - trimzeros: -#endif - while(*--s == '0'); - s++; - } - ret: - Bfree(C, S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(C, mlo); - Bfree(C, mhi); - } - ret1: -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&u) = Exp_1 + (70 << Exp_shift); - word1(&u) = 0; - dval(&u) += 1.; - } - } - else if (!oldinexact) - clear_inexact(); -#endif - Bfree(C, b); - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - return s0; - } -#ifdef __cplusplus -} -#endif - - - - - - - - -/**************************************************************** - * - * The author of this software is David M. Gay. - * - * Copyright (c) 1991, 1996 by Lucent Technologies. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - * - ***************************************************************/ - -/* g_fmt(buf,x) stores the closest decimal approximation to x in buf; - * it suffices to declare buf - * char buf[32]; - */ - - char * - jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x) -{ - register int i, k; - register char *s; - int decpt, j, sign; - char *b0, *s0, *se; - - b0 = b; -#ifdef IGNORE_ZERO_SIGN - if (!x) { - *b++ = '0'; - *b = 0; - goto done; - } -#endif - s = s0 = jvp_dtoa(C, x, 0, 0, &decpt, &sign, &se); - if (sign) - *b++ = '-'; - if (decpt == 9999) /* Infinity or Nan */ { - while((*b++ = *s++)); - goto done0; - } - if (decpt <= -4 || decpt > se - s + 15) { - *b++ = *s++; - if (*s) { - *b++ = '.'; - while((*b = *s++)) - b++; - } - *b++ = 'e'; - /* sprintf(b, "%+.2d", decpt - 1); */ - if (--decpt < 0) { - *b++ = '-'; - decpt = -decpt; - } - else - *b++ = '+'; - for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); - for(;;) { - i = decpt / k; - *b++ = i + '0'; - if (--j <= 0) - break; - decpt -= i*k; - decpt *= 10; - } - *b = 0; - } - else if (decpt <= 0) { - *b++ = '0'; - *b++ = '.'; - for(; decpt < 0; decpt++) - *b++ = '0'; - while((*b++ = *s++)); - } - else { - while((*b = *s++)) { - b++; - if (--decpt == 0 && *s) - *b++ = '.'; - } - for(; decpt > 0; decpt--) - *b++ = '0'; - *b = 0; - } - done0: - jvp_freedtoa(C, s0); - goto done; - done: - return b0; - } diff --git a/src/jq/jv_dtoa.h b/src/jq/jv_dtoa.h deleted file mode 100644 index 7aa5f08..0000000 --- a/src/jq/jv_dtoa.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef JV_DTOA_H -#define JV_DTOA_H -#define Kmax 7 - -struct Bigint; -struct dtoa_context { - struct Bigint *freelist[Kmax+1]; - struct Bigint *p5s; -}; - -void jvp_dtoa_context_init(struct dtoa_context* ctx); -void jvp_dtoa_context_free(struct dtoa_context* ctx); - -double jvp_strtod(struct dtoa_context* C, const char* s, char** se); - - -char* jvp_dtoa(struct dtoa_context* C, double dd, int mode, int ndigits, int *decpt, int *sign, char **rve); -void jvp_freedtoa(struct dtoa_context* C, char *s); - -#define JVP_DTOA_FMT_MAX_LEN 64 -char* jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x); -#endif diff --git a/src/jq/jv_file.c b/src/jq/jv_file.c deleted file mode 100644 index 3159df5..0000000 --- a/src/jq/jv_file.c +++ /dev/null @@ -1,62 +0,0 @@ - -#include -#include -#include -#include -#include "jv.h" -#include "jv_unicode.h" - -jv jv_load_file(const char* filename, int raw) { - FILE* file = fopen(filename, "r"); - struct jv_parser* parser; - jv data; - if (!file) { - return jv_invalid_with_msg(jv_string_fmt("Could not open %s: %s", - filename, - strerror(errno))); - } - if (raw) { - data = jv_string(""); - } else { - data = jv_array(); - parser = jv_parser_new(0); - } - - // 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; - char buf[4096+max_utf8_len]; - while (!feof(file) && !ferror(file)) { - size_t n = fread(buf, 1, sizeof(buf)-max_utf8_len, file); - int len = 0; - if (jvp_utf8_backtrack(buf+(n-1), buf, &len) && len > 0) { - if (!feof(file) && !ferror(file)) { - n += fread(buf+n, 1, len, file); - } - } - - if (raw) { - data = jv_string_append_buf(data, buf, n); - } else { - jv_parser_set_buf(parser, buf, n, !feof(file)); - jv value; - while (jv_is_valid((value = jv_parser_next(parser)))) - data = jv_array_append(data, value); - if (jv_invalid_has_msg(jv_copy(value))) { - jv_free(data); - data = value; - break; - } - } - } - if (!raw) - jv_parser_free(parser); - int badread = ferror(file); - if (fclose(file) != 0 || badread) { - jv_free(data); - return jv_invalid_with_msg(jv_string_fmt("Error reading from %s", - filename)); - } - return data; -} diff --git a/src/jq/jv_parse.c b/src/jq/jv_parse.c deleted file mode 100644 index 51ad9f0..0000000 --- a/src/jq/jv_parse.c +++ /dev/null @@ -1,858 +0,0 @@ -#include -#include -#include -#include -#include "jv.h" -#include "jv_dtoa.h" -#include "jv_unicode.h" -#include "jv_alloc.h" -#include "jv_dtoa.h" - -typedef const char* presult; - -#ifndef MAX_PARSING_DEPTH -#define MAX_PARSING_DEPTH (256) -#endif - -#define TRY(x) do {presult msg__ = (x); if (msg__) return msg__; } while(0) -#ifdef __GNUC__ -#define pfunc __attribute__((warn_unused_result)) presult -#else -#define pfunc presult -#endif - -enum last_seen { - JV_LAST_NONE = 0, - JV_LAST_OPEN_ARRAY = '[', - JV_LAST_OPEN_OBJECT = '{', - JV_LAST_COLON = ':', - JV_LAST_COMMA = ',', - JV_LAST_VALUE = 'V', -}; - -struct jv_parser { - const char* curr_buf; - int curr_buf_length; - int curr_buf_pos; - int curr_buf_is_partial; - int eof; - unsigned bom_strip_position; - - int flags; - - jv* stack; // parser - int stackpos; // parser - int stacklen; // both (optimization; it's really pathlen for streaming) - jv path; // streamer - enum last_seen last_seen; // streamer - jv output; // streamer - jv next; // both - - char* tokenbuf; - int tokenpos; - int tokenlen; - - int line, column; - - struct dtoa_context dtoa; - - enum { - JV_PARSER_NORMAL, - JV_PARSER_STRING, - JV_PARSER_STRING_ESCAPE, - JV_PARSER_WAITING_FOR_RS // parse error, waiting for RS - } st; - unsigned int last_ch_was_ws:1; -}; - - -static void parser_init(struct jv_parser* p, int flags) { - p->flags = flags; - if ((p->flags & JV_PARSE_STREAMING)) { - p->path = jv_array(); - } else { - p->path = jv_invalid(); - p->flags &= ~(JV_PARSE_STREAM_ERRORS); - } - p->stack = 0; - p->stacklen = p->stackpos = 0; - p->last_seen = JV_LAST_NONE; - p->output = jv_invalid(); - p->next = jv_invalid(); - p->tokenbuf = 0; - p->tokenlen = p->tokenpos = 0; - if ((p->flags & JV_PARSE_SEQ)) - p->st = JV_PARSER_WAITING_FOR_RS; - else - p->st = JV_PARSER_NORMAL; - p->eof = 0; - p->curr_buf = 0; - p->curr_buf_length = p->curr_buf_pos = p->curr_buf_is_partial = 0; - p->bom_strip_position = 0; - p->last_ch_was_ws = 0; - p->line = 1; - p->column = 0; - jvp_dtoa_context_init(&p->dtoa); -} - -static void parser_reset(struct jv_parser* p) { - if ((p->flags & JV_PARSE_STREAMING)) { - jv_free(p->path); - p->path = jv_array(); - p->stacklen = 0; - } - p->last_seen = JV_LAST_NONE; - jv_free(p->output); - p->output = jv_invalid(); - jv_free(p->next); - p->next = jv_invalid(); - for (int i=0; istackpos; i++) - jv_free(p->stack[i]); - p->stackpos = 0; - p->tokenpos = 0; - p->st = JV_PARSER_NORMAL; -} - -static void parser_free(struct jv_parser* p) { - parser_reset(p); - jv_free(p->path); - jv_free(p->output); - jv_mem_free(p->stack); - jv_mem_free(p->tokenbuf); - jvp_dtoa_context_free(&p->dtoa); -} - -static pfunc value(struct jv_parser* p, jv val) { - if ((p->flags & JV_PARSE_STREAMING)) { - if (jv_is_valid(p->next) || p->last_seen == JV_LAST_VALUE) - return "Expected separator between values"; - if (p->stacklen > 0) - p->last_seen = JV_LAST_VALUE; - else - p->last_seen = JV_LAST_NONE; - } else { - if (jv_is_valid(p->next)) return "Expected separator between values"; - } - jv_free(p->next); - p->next = val; - return 0; -} - -static void push(struct jv_parser* p, jv v) { - assert(p->stackpos <= p->stacklen); - if (p->stackpos == p->stacklen) { - p->stacklen = p->stacklen * 2 + 10; - p->stack = jv_mem_realloc(p->stack, p->stacklen * sizeof(jv)); - } - assert(p->stackpos < p->stacklen); - p->stack[p->stackpos++] = v; -} - -static pfunc parse_token(struct jv_parser* p, char ch) { - switch (ch) { - case '[': - if (p->stackpos >= MAX_PARSING_DEPTH) return "Exceeds depth limit for parsing"; - if (jv_is_valid(p->next)) return "Expected separator between values"; - push(p, jv_array()); - break; - - case '{': - if (p->stackpos >= MAX_PARSING_DEPTH) return "Exceeds depth limit for parsing"; - if (jv_is_valid(p->next)) return "Expected separator between values"; - push(p, jv_object()); - break; - - case ':': - if (!jv_is_valid(p->next)) - return "Expected string key before ':'"; - if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) - return "':' not as part of an object"; - if (jv_get_kind(p->next) != JV_KIND_STRING) - return "Object keys must be strings"; - push(p, p->next); - p->next = jv_invalid(); - break; - - case ',': - if (!jv_is_valid(p->next)) - return "Expected value before ','"; - if (p->stackpos == 0) - return "',' not as part of an object or array"; - if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) { - p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); - p->next = jv_invalid(); - } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) { - assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); - p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], - p->stack[p->stackpos-1], p->next); - p->stackpos--; - p->next = jv_invalid(); - } else { - // this case hits on input like {"a", "b"} - return "Objects must consist of key:value pairs"; - } - break; - - case ']': - if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY) - return "Unmatched ']'"; - if (jv_is_valid(p->next)) { - p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); - p->next = jv_invalid(); - } else { - if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) { - // this case hits on input like [1,2,3,] - return "Expected another array element"; - } - } - jv_free(p->next); - p->next = p->stack[--p->stackpos]; - break; - - case '}': - if (p->stackpos == 0) - return "Unmatched '}'"; - if (jv_is_valid(p->next)) { - if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING) - return "Objects must consist of key:value pairs"; - assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); - p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], - p->stack[p->stackpos-1], p->next); - p->stackpos--; - p->next = jv_invalid(); - } else { - if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) - return "Unmatched '}'"; - if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0) - return "Expected another key-value pair"; - } - jv_free(p->next); - p->next = p->stack[--p->stackpos]; - break; - } - return 0; -} - -static pfunc stream_token(struct jv_parser* p, char ch) { - jv_kind k; - jv last; - - switch (ch) { - case '[': - if (jv_is_valid(p->next)) - return "Expected a separator between values"; - p->path = jv_array_append(p->path, jv_number(0)); // push - p->last_seen = JV_LAST_OPEN_ARRAY; - p->stacklen++; - break; - - case '{': - if (p->last_seen == JV_LAST_VALUE) - return "Expected a separator between values"; - // Push object key: null, since we don't know it yet - p->path = jv_array_append(p->path, jv_null()); // push - p->last_seen = JV_LAST_OPEN_OBJECT; - p->stacklen++; - break; - - case ':': - if (p->stacklen == 0 || jv_get_kind(jv_array_get(jv_copy(p->path), p->stacklen - 1)) == JV_KIND_NUMBER) - return "':' not as part of an object"; - if (!jv_is_valid(p->next) || p->last_seen == JV_LAST_NONE) - return "Expected string key before ':'"; - if (jv_get_kind(p->next) != JV_KIND_STRING) - return "Object keys must be strings"; - if (p->last_seen != JV_LAST_VALUE) - return "':' should follow a key"; - p->last_seen = JV_LAST_COLON; - p->path = jv_array_set(p->path, p->stacklen - 1, p->next); - p->next = jv_invalid(); - break; - - case ',': - if (p->last_seen != JV_LAST_VALUE) - return "Expected value before ','"; - if (p->stacklen == 0) - return "',' not as part of an object or array"; - last = jv_array_get(jv_copy(p->path), p->stacklen - 1); - k = jv_get_kind(last); - if (k == JV_KIND_NUMBER) { - int idx = jv_number_value(last); - - if (jv_is_valid(p->next)) { - p->output = JV_ARRAY(jv_copy(p->path), p->next); - p->next = jv_invalid(); - } - p->path = jv_array_set(p->path, p->stacklen - 1, jv_number(idx + 1)); - p->last_seen = JV_LAST_COMMA; - } else if (k == JV_KIND_STRING) { - if (jv_is_valid(p->next)) { - p->output = JV_ARRAY(jv_copy(p->path), p->next); - p->next = jv_invalid(); - } - p->path = jv_array_set(p->path, p->stacklen - 1, jv_true()); // ready for another name:value pair - p->last_seen = JV_LAST_COMMA; - } else { - assert(k == JV_KIND_NULL); - // this case hits on input like {,} - // make sure to handle input like {"a", "b"} and {"a":, ...} - jv_free(last); - return "Objects must consist of key:value pairs"; - } - jv_free(last); - break; - - case ']': - if (p->stacklen == 0) - return "Unmatched ']' at the top-level"; - if (p->last_seen == JV_LAST_COMMA) - return "Expected another array element"; - if (p->last_seen == JV_LAST_OPEN_ARRAY) - assert(!jv_is_valid(p->next)); - - last = jv_array_get(jv_copy(p->path), p->stacklen - 1); - k = jv_get_kind(last); - jv_free(last); - - if (k != JV_KIND_NUMBER) - return "Unmatched ']' in the middle of an object"; - if (jv_is_valid(p->next)) { - p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true()); - p->next = jv_invalid(); - } else if (p->last_seen != JV_LAST_OPEN_ARRAY) { - p->output = JV_ARRAY(jv_copy(p->path)); - } - - p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop - //assert(!jv_is_valid(p->next)); - jv_free(p->next); - p->next = jv_invalid(); - - if (p->last_seen == JV_LAST_OPEN_ARRAY) - p->output = JV_ARRAY(jv_copy(p->path), jv_array()); // Empty arrays are leaves - - if (p->stacklen == 0) - p->last_seen = JV_LAST_NONE; - else - p->last_seen = JV_LAST_VALUE; - break; - - case '}': - if (p->stacklen == 0) - return "Unmatched '}' at the top-level"; - if (p->last_seen == JV_LAST_COMMA) - return "Expected another key:value pair"; - if (p->last_seen == JV_LAST_OPEN_OBJECT) - assert(!jv_is_valid(p->next)); - - last = jv_array_get(jv_copy(p->path), p->stacklen - 1); - k = jv_get_kind(last); - jv_free(last); - if (k == JV_KIND_NUMBER) - return "Unmatched '}' in the middle of an array"; - - if (jv_is_valid(p->next)) { - if (k != JV_KIND_STRING) - return "Objects must consist of key:value pairs"; - p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true()); - p->next = jv_invalid(); - } else { - // Perhaps {"a":[]} - if (p->last_seen == JV_LAST_COLON) - // Looks like {"a":} - return "Missing value in key:value pair"; - if (p->last_seen == JV_LAST_COMMA) - // Looks like {"a":0,} - return "Expected another key-value pair"; - if (p->last_seen == JV_LAST_OPEN_ARRAY) - return "Unmatched '}' in the middle of an array"; - if (p->last_seen != JV_LAST_VALUE && p->last_seen != JV_LAST_OPEN_OBJECT) - return "Unmatched '}'"; - if (p->last_seen != JV_LAST_OPEN_OBJECT) - p->output = JV_ARRAY(jv_copy(p->path)); - } - p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop - jv_free(p->next); - p->next = jv_invalid(); - - if (p->last_seen == JV_LAST_OPEN_OBJECT) - p->output = JV_ARRAY(jv_copy(p->path), jv_object()); // Empty arrays are leaves - - if (p->stacklen == 0) - p->last_seen = JV_LAST_NONE; - else - p->last_seen = JV_LAST_VALUE; - break; - } - return 0; -} - -static void tokenadd(struct jv_parser* p, char c) { - assert(p->tokenpos <= p->tokenlen); - if (p->tokenpos >= (p->tokenlen - 1)) { - p->tokenlen = p->tokenlen*2 + 256; - p->tokenbuf = jv_mem_realloc(p->tokenbuf, p->tokenlen); - } - assert(p->tokenpos < p->tokenlen); - p->tokenbuf[p->tokenpos++] = c; -} - -static int unhex4(char* hex) { - int r = 0; - for (int i=0; i<4; i++) { - char c = *hex++; - int n; - if ('0' <= c && c <= '9') n = c - '0'; - else if ('a' <= c && c <= 'f') n = c - 'a' + 10; - else if ('A' <= c && c <= 'F') n = c - 'A' + 10; - else return -1; - r <<= 4; - r |= n; - } - return r; -} - -static pfunc found_string(struct jv_parser* p) { - char* in = p->tokenbuf; - char* out = p->tokenbuf; - char* end = p->tokenbuf + p->tokenpos; - - while (in < end) { - char c = *in++; - if (c == '\\') { - if (in >= end) - return "Expected escape character at end of string"; - c = *in++; - switch (c) { - case '\\': - case '"': - case '/': *out++ = c; break; - case 'b': *out++ = '\b'; break; - case 'f': *out++ = '\f'; break; - case 't': *out++ = '\t'; break; - case 'n': *out++ = '\n'; break; - case 'r': *out++ = '\r'; break; - - case 'u': - /* ahh, the complicated case */ - if (in + 4 > end) - return "Invalid \\uXXXX escape"; - int hexvalue = unhex4(in); - if (hexvalue < 0) - return "Invalid characters in \\uXXXX escape"; - unsigned long codepoint = (unsigned long)hexvalue; - in += 4; - if (0xD800 <= codepoint && codepoint <= 0xDBFF) { - /* who thought UTF-16 surrogate pairs were a good idea? */ - if (in + 6 > end || in[0] != '\\' || in[1] != 'u') - return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; - unsigned long surrogate = unhex4(in+2); - if (!(0xDC00 <= surrogate && surrogate <= 0xDFFF)) - return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; - in += 6; - codepoint = 0x10000 + (((codepoint - 0xD800) << 10) - |(surrogate - 0xDC00)); - } - if (codepoint > 0x10FFFF) - codepoint = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER - out += jvp_utf8_encode(codepoint, out); - break; - - default: - return "Invalid escape"; - } - } else { - if (c > 0 && c < 0x001f) - return "Invalid string: control characters from U+0000 through U+001F must be escaped"; - *out++ = c; - } - } - TRY(value(p, jv_string_sized(p->tokenbuf, out - p->tokenbuf))); - p->tokenpos = 0; - return 0; -} - -static pfunc check_literal(struct jv_parser* p) { - if (p->tokenpos == 0) return 0; - - const char* pattern = 0; - int plen; - jv v; - switch (p->tokenbuf[0]) { - case 't': pattern = "true"; plen = 4; v = jv_true(); break; - case 'f': pattern = "false"; plen = 5; v = jv_false(); break; - case 'n': pattern = "null"; plen = 4; v = jv_null(); break; - } - if (pattern) { - if (p->tokenpos != plen) return "Invalid literal"; - for (int i=0; itokenbuf[i] != pattern[i]) - return "Invalid literal"; - TRY(value(p, v)); - } else { - // FIXME: better parser - p->tokenbuf[p->tokenpos] = 0; - char* end = 0; - double d = jvp_strtod(&p->dtoa, p->tokenbuf, &end); - if (end == 0 || *end != 0) - return "Invalid numeric literal"; - TRY(value(p, jv_number(d))); - } - p->tokenpos = 0; - return 0; -} - -typedef enum { - LITERAL, - WHITESPACE, - STRUCTURE, - QUOTE, - INVALID -} chclass; - -static chclass classify(char c) { - switch (c) { - case ' ': - case '\t': - case '\r': - case '\n': - return WHITESPACE; - case '"': - return QUOTE; - case '[': - case ',': - case ']': - case '{': - case ':': - case '}': - return STRUCTURE; - default: - return LITERAL; - } -} - - -static const presult OK = "output produced"; - -static int parse_check_done(struct jv_parser* p, jv* out) { - if (p->stackpos == 0 && jv_is_valid(p->next)) { - *out = p->next; - p->next = jv_invalid(); - return 1; - } else { - return 0; - } -} - -static int stream_check_done(struct jv_parser* p, jv* out) { - if (p->stacklen == 0 && jv_is_valid(p->next)) { - *out = JV_ARRAY(jv_copy(p->path),p->next); - p->next = jv_invalid(); - return 1; - } else if (jv_is_valid(p->output)) { - if (jv_array_length(jv_copy(p->output)) > 2) { - // At end of an array or object, necessitating one more output by - // which to indicate this - *out = jv_array_slice(jv_copy(p->output), 0, 2); - p->output = jv_array_slice(p->output, 0, 1); // arrange one more output - } else { - // No further processing needed - *out = p->output; - p->output = jv_invalid(); - } - return 1; - } else { - return 0; - } -} - -static int parse_check_truncation(struct jv_parser* p) { - return ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && (p->stackpos > 0 || p->tokenpos > 0 || jv_get_kind(p->next) == JV_KIND_NUMBER)); -} - -static int stream_check_truncation(struct jv_parser* p) { - jv_kind k = jv_get_kind(p->next); - return (p->stacklen > 0 || k == JV_KIND_NUMBER || k == JV_KIND_TRUE || k == JV_KIND_FALSE || k == JV_KIND_NULL); -} - -static int parse_is_top_num(struct jv_parser* p) { - return (p->stackpos == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER); -} - -static int stream_is_top_num(struct jv_parser* p) { - return (p->stacklen == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER); -} - -#define check_done(p, o) \ - (((p)->flags & JV_PARSE_STREAMING) ? stream_check_done((p), (o)) : parse_check_done((p), (o))) - -#define token(p, ch) \ - (((p)->flags & JV_PARSE_STREAMING) ? stream_token((p), (ch)) : parse_token((p), (ch))) - -#define check_truncation(p) \ - (((p)->flags & JV_PARSE_STREAMING) ? stream_check_truncation((p)) : parse_check_truncation((p))) - -#define is_top_num(p) \ - (((p)->flags & JV_PARSE_STREAMING) ? stream_is_top_num((p)) : parse_is_top_num((p))) - -static pfunc scan(struct jv_parser* p, char ch, jv* out) { - p->column++; - if (ch == '\n') { - p->line++; - p->column = 0; - } - if (ch == '\036' /* ASCII RS; see draft-ietf-json-sequence-07 */) { - if (check_truncation(p)) { - if (check_literal(p) == 0 && is_top_num(p)) - return "Potentially truncated top-level numeric value"; - return "Truncated value"; - } - TRY(check_literal(p)); - if (p->st == JV_PARSER_NORMAL && check_done(p, out)) - return OK; - // shouldn't happen? - assert(!jv_is_valid(*out)); - parser_reset(p); - jv_free(*out); - *out = jv_invalid(); - return OK; - } - presult answer = 0; - p->last_ch_was_ws = 0; - if (p->st == JV_PARSER_NORMAL) { - chclass cls = classify(ch); - if (cls == WHITESPACE) - p->last_ch_was_ws = 1; - if (cls != LITERAL) { - TRY(check_literal(p)); - if (check_done(p, out)) answer = OK; - } - switch (cls) { - case LITERAL: - tokenadd(p, ch); - break; - case WHITESPACE: - break; - case QUOTE: - p->st = JV_PARSER_STRING; - break; - case STRUCTURE: - TRY(token(p, ch)); - break; - case INVALID: - return "Invalid character"; - } - if (check_done(p, out)) answer = OK; - } else { - if (ch == '"' && p->st == JV_PARSER_STRING) { - TRY(found_string(p)); - p->st = JV_PARSER_NORMAL; - if (check_done(p, out)) answer = OK; - } else { - tokenadd(p, ch); - if (ch == '\\' && p->st == JV_PARSER_STRING) { - p->st = JV_PARSER_STRING_ESCAPE; - } else { - p->st = JV_PARSER_STRING; - } - } - } - return answer; -} - -struct jv_parser* jv_parser_new(int flags) { - struct jv_parser* p = jv_mem_alloc(sizeof(struct jv_parser)); - parser_init(p, flags); - p->flags = flags; - return p; -} - -void jv_parser_free(struct jv_parser* p) { - parser_free(p); - jv_mem_free(p); -} - -static const unsigned char UTF8_BOM[] = {0xEF,0xBB,0xBF}; - -int jv_parser_remaining(struct jv_parser* p) { - if (p->curr_buf == 0) - return 0; - return (p->curr_buf_length - p->curr_buf_pos); -} - -void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial) { - assert((p->curr_buf == 0 || p->curr_buf_pos == p->curr_buf_length) - && "previous buffer not exhausted"); - while (length > 0 && p->bom_strip_position < sizeof(UTF8_BOM)) { - if ((unsigned char)*buf == UTF8_BOM[p->bom_strip_position]) { - // matched a BOM character - buf++; - length--; - p->bom_strip_position++; - } else { - if (p->bom_strip_position == 0) { - // no BOM in this document - p->bom_strip_position = sizeof(UTF8_BOM); - } else { - // malformed BOM (prefix present, rest missing) - p->bom_strip_position = 0xff; - } - } - } - p->curr_buf = buf; - p->curr_buf_length = length; - p->curr_buf_pos = 0; - p->curr_buf_is_partial = is_partial; -} - -static jv make_error(struct jv_parser*, const char *, ...) JV_PRINTF_LIKE(2, 3); - -static jv make_error(struct jv_parser* p, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - jv e = jv_string_vfmt(fmt, ap); - va_end(ap); - if ((p->flags & JV_PARSE_STREAM_ERRORS)) - return JV_ARRAY(e, jv_copy(p->path)); - return jv_invalid_with_msg(e); -} - -jv jv_parser_next(struct jv_parser* p) { - if (p->eof) - return jv_invalid(); - if (!p->curr_buf) - return jv_invalid(); // Need a buffer - if (p->bom_strip_position == 0xff) { - if (!(p->flags & JV_PARSE_SEQ)) - return jv_invalid_with_msg(jv_string("Malformed BOM")); - p->st =JV_PARSER_WAITING_FOR_RS; - parser_reset(p); - } - jv value = jv_invalid(); - if ((p->flags & JV_PARSE_STREAMING) && stream_check_done(p, &value)) - return value; - char ch; - presult msg = 0; - while (!msg && p->curr_buf_pos < p->curr_buf_length) { - ch = p->curr_buf[p->curr_buf_pos++]; - if (p->st == JV_PARSER_WAITING_FOR_RS) { - if (ch == '\n') { - p->line++; - p->column = 0; - } else { - p->column++; - } - if (ch == '\036') - p->st = JV_PARSER_NORMAL; - continue; // need to resync, wait for RS - } - msg = scan(p, ch, &value); - } - if (msg == OK) { - return value; - } else if (msg) { - jv_free(value); - if (ch != '\036' && (p->flags & JV_PARSE_SEQ)) { - // Skip to the next RS - p->st = JV_PARSER_WAITING_FOR_RS; - value = make_error(p, "%s at line %d, column %d (need RS to resync)", msg, p->line, p->column); - parser_reset(p); - return value; - } - value = make_error(p, "%s at line %d, column %d", msg, p->line, p->column); - parser_reset(p); - if (!(p->flags & JV_PARSE_SEQ)) { - // We're not parsing a JSON text sequence; throw this buffer away. - // XXX We should fail permanently here. - p->curr_buf = 0; - p->curr_buf_pos = 0; - } // Else ch must be RS; don't clear buf so we can start parsing again after this ch - return value; - } else if (p->curr_buf_is_partial) { - assert(p->curr_buf_pos == p->curr_buf_length); - // need another buffer - return jv_invalid(); - } else { - // at EOF - p->eof = 1; - assert(p->curr_buf_pos == p->curr_buf_length); - jv_free(value); - if (p->st == JV_PARSER_WAITING_FOR_RS) - return make_error(p, "Unfinished abandoned text at EOF at line %d, column %d", p->line, p->column); - if (p->st != JV_PARSER_NORMAL) { - value = make_error(p, "Unfinished string at EOF at line %d, column %d", p->line, p->column); - parser_reset(p); - p->st = JV_PARSER_WAITING_FOR_RS; - return value; - } - if ((msg = check_literal(p))) { - value = make_error(p, "%s at EOF at line %d, column %d", msg, p->line, p->column); - parser_reset(p); - p->st = JV_PARSER_WAITING_FOR_RS; - return value; - } - if (((p->flags & JV_PARSE_STREAMING) && p->stacklen != 0) || - (!(p->flags & JV_PARSE_STREAMING) && p->stackpos != 0)) { - value = make_error(p, "Unfinished JSON term at EOF at line %d, column %d", p->line, p->column); - parser_reset(p); - p->st = JV_PARSER_WAITING_FOR_RS; - return value; - } - // p->next is either invalid (nothing here, but no syntax error) - // or valid (this is the value). either way it's the thing to return - if ((p->flags & JV_PARSE_STREAMING) && jv_is_valid(p->next)) { - value = JV_ARRAY(jv_copy(p->path), p->next); // except in streaming mode we've got to make it [path,value] - } else { - value = p->next; - } - p->next = jv_invalid(); - if ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && jv_get_kind(value) == JV_KIND_NUMBER) { - jv_free(value); - return make_error(p, "Potentially truncated top-level numeric value at EOF at line %d, column %d", p->line, p->column); - } - return value; - } -} - -jv jv_parse_sized(const char* string, int length) { - struct jv_parser parser; - parser_init(&parser, 0); - jv_parser_set_buf(&parser, string, length, 0); - jv value = jv_parser_next(&parser); - if (jv_is_valid(value)) { - jv next = jv_parser_next(&parser); - if (jv_is_valid(next)) { - // multiple JSON values, we only wanted one - jv_free(value); - jv_free(next); - value = jv_invalid_with_msg(jv_string("Unexpected extra JSON values")); - } else if (jv_invalid_has_msg(jv_copy(next))) { - // parser error after the first JSON value - jv_free(value); - value = next; - } else { - // a single valid JSON value - jv_free(next); - } - } else if (jv_invalid_has_msg(jv_copy(value))) { - // parse error, we'll return it - } else { - // no value at all - jv_free(value); - value = jv_invalid_with_msg(jv_string("Expected JSON value")); - } - parser_free(&parser); - - if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) { - jv msg = jv_invalid_get_msg(value); - value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')", - jv_string_value(msg), - string)); - jv_free(msg); - } - return value; -} - -jv jv_parse(const char* string) { - return jv_parse_sized(string, strlen(string)); -} diff --git a/src/jq/jv_print.c b/src/jq/jv_print.c deleted file mode 100644 index 7dd088d..0000000 --- a/src/jq/jv_print.c +++ /dev/null @@ -1,353 +0,0 @@ -#include -#include -#include -#include - -#ifdef WIN32 -#include -#include -#endif - -#include "jv.h" -#include "jv_dtoa.h" -#include "jv_unicode.h" - -#ifndef MAX_PRINT_DEPTH -#define MAX_PRINT_DEPTH (256) -#endif - -#define ESC "\033" -#define COL(c) (ESC "[" c "m") -#define COLRESET (ESC "[0m") - -// Color table. See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors -// for how to choose these. -static const jv_kind color_kinds[] = - {JV_KIND_NULL, JV_KIND_FALSE, JV_KIND_TRUE, JV_KIND_NUMBER, - JV_KIND_STRING, JV_KIND_ARRAY, JV_KIND_OBJECT}; -static const char* const colors[] = - {COL("1;30"), COL("0;39"), COL("0;39"), COL("0;39"), - COL("0;32"), COL("1;39"), COL("1;39")}; -#define FIELD_COLOR COL("34;1") - -static void put_buf(const char *s, int len, FILE *fout, jv *strout, int is_tty) { - if (strout) { - *strout = jv_string_append_buf(*strout, s, len); - } else { -#ifdef WIN32 - /* See util.h */ - if (is_tty) - WriteFile((HANDLE)_get_osfhandle(fileno(fout)), s, len, NULL, NULL); - else - fwrite(s, 1, len, fout); -#else - fwrite(s, 1, len, fout); -#endif - } -} - -static void put_char(char c, FILE* fout, jv* strout, int T) { - put_buf(&c, 1, fout, strout, T); -} - -static void put_str(const char* s, FILE* fout, jv* strout, int T) { - put_buf(s, strlen(s), fout, strout, T); -} - -static void put_indent(int n, int flags, FILE* fout, jv* strout, int T) { - if (flags & JV_PRINT_TAB) { - while (n--) - put_char('\t', fout, strout, T); - } else { - n *= ((flags & (JV_PRINT_SPACE0 | JV_PRINT_SPACE1 | JV_PRINT_SPACE2)) >> 8); - while (n--) - put_char(' ', fout, strout, T); - } -} - -static void jvp_dump_string(jv str, int ascii_only, FILE* F, jv* S, int T) { - assert(jv_get_kind(str) == JV_KIND_STRING); - const char* i = jv_string_value(str); - const char* end = i + jv_string_length_bytes(jv_copy(str)); - const char* cstart; - int c = 0; - char buf[32]; - put_char('"', F, S, T); - while ((i = jvp_utf8_next((cstart = i), end, &c))) { - assert(c != -1); - int unicode_escape = 0; - if (0x20 <= c && c <= 0x7E) { - // printable ASCII - if (c == '"' || c == '\\') { - put_char('\\', F, S, T); - } - put_char(c, F, S, T); - } else if (c < 0x20 || c == 0x7F) { - // ASCII control character - switch (c) { - case '\b': - put_char('\\', F, S, T); - put_char('b', F, S, T); - break; - case '\t': - put_char('\\', F, S, T); - put_char('t', F, S, T); - break; - case '\r': - put_char('\\', F, S, T); - put_char('r', F, S, T); - break; - case '\n': - put_char('\\', F, S, T); - put_char('n', F, S, T); - break; - case '\f': - put_char('\\', F, S, T); - put_char('f', F, S, T); - break; - default: - unicode_escape = 1; - break; - } - } else { - if (ascii_only) { - unicode_escape = 1; - } else { - put_buf(cstart, i - cstart, F, S, T); - } - } - if (unicode_escape) { - if (c <= 0xffff) { - snprintf(buf, sizeof(buf), "\\u%04x", c); - } else { - c -= 0x10000; - snprintf(buf, sizeof(buf), "\\u%04x\\u%04x", - 0xD800 | ((c & 0xffc00) >> 10), - 0xDC00 | (c & 0x003ff)); - } - put_str(buf, F, S, T); - } - } - assert(c != -1); - put_char('"', F, S, 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_str(jvp_dtoa_fmt(C, buf, refcnt), 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) { - char buf[JVP_DTOA_FMT_MAX_LEN]; - const char* color = 0; - double refcnt = (flags & JV_PRINT_REFCOUNT) ? jv_get_refcnt(x) - 1 : -1; - if (flags & JV_PRINT_COLOR) { - for (unsigned i=0; i MAX_PRINT_DEPTH) { - put_str("", F, S, flags & JV_PRINT_ISATTY); - } else switch (jv_get_kind(x)) { - default: - case JV_KIND_INVALID: - if (flags & JV_PRINT_INVALID) { - jv msg = jv_invalid_get_msg(jv_copy(x)); - if (jv_get_kind(msg) == JV_KIND_STRING) { - put_str("", F, S, flags & JV_PRINT_ISATTY); - } else { - put_str("", F, S, flags & JV_PRINT_ISATTY); - } - } else { - assert(0 && "Invalid value"); - } - break; - case JV_KIND_NULL: - put_str("null", F, S, flags & JV_PRINT_ISATTY); - break; - case JV_KIND_FALSE: - put_str("false", F, S, flags & JV_PRINT_ISATTY); - break; - case JV_KIND_TRUE: - put_str("true", F, S, flags & JV_PRINT_ISATTY); - break; - case JV_KIND_NUMBER: { - double d = jv_number_value(x); - if (d != d) { - // JSON doesn't have NaN, so we'll render it as "null" - put_str("null", F, S, flags & JV_PRINT_ISATTY); - } else { - // Normalise infinities to something we can print in valid JSON - if (d > DBL_MAX) d = DBL_MAX; - if (d < -DBL_MAX) d = -DBL_MAX; - put_str(jvp_dtoa_fmt(C, buf, d), F, S, flags & JV_PRINT_ISATTY); - } - 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); - break; - case JV_KIND_ARRAY: { - if (jv_array_length(jv_copy(x)) == 0) { - put_str("[]", F, S, flags & JV_PRINT_ISATTY); - break; - } - put_str("[", F, S, flags & JV_PRINT_ISATTY); - if (flags & JV_PRINT_PRETTY) { - put_char('\n', F, S, flags & JV_PRINT_ISATTY); - put_indent(indent + 1, flags, F, S, flags & JV_PRINT_ISATTY); - } - jv_array_foreach(x, i, elem) { - if (i!=0) { - if (flags & JV_PRINT_PRETTY) { - put_str(",\n", F, S, flags & JV_PRINT_ISATTY); - put_indent(indent + 1, flags, F, S, flags & JV_PRINT_ISATTY); - } else { - put_str(",", F, S, flags & JV_PRINT_ISATTY); - } - } - jv_dump_term(C, elem, flags, indent + 1, F, S); - if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); - } - if (flags & JV_PRINT_PRETTY) { - put_char('\n', F, S, flags & JV_PRINT_ISATTY); - put_indent(indent, flags, F, S, flags & JV_PRINT_ISATTY); - } - 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 (jv_object_length(jv_copy(x)) == 0) { - put_str("{}", F, S, flags & JV_PRINT_ISATTY); - break; - } - put_char('{', F, S, flags & JV_PRINT_ISATTY); - if (flags & JV_PRINT_PRETTY) { - put_char('\n', F, S, flags & JV_PRINT_ISATTY); - put_indent(indent + 1, flags, F, S, flags & JV_PRINT_ISATTY); - } - int first = 1; - int i = 0; - jv keyset = jv_null(); - while (1) { - jv key, value; - if (flags & JV_PRINT_SORTED) { - if (first) { - keyset = jv_keys(jv_copy(x)); - i = 0; - } else { - i++; - } - if (i >= jv_array_length(jv_copy(keyset))) { - jv_free(keyset); - break; - } - key = jv_array_get(jv_copy(keyset), i); - value = jv_object_get(jv_copy(x), jv_copy(key)); - } else { - if (first) { - i = jv_object_iter(x); - } else { - i = jv_object_iter_next(x, i); - } - if (!jv_object_iter_valid(x, i)) break; - key = jv_object_iter_key(x, i); - value = jv_object_iter_value(x, i); - } - - if (!first) { - if (flags & JV_PRINT_PRETTY){ - put_str(",\n", F, S, flags & JV_PRINT_ISATTY); - put_indent(indent + 1, flags, F, S, flags & JV_PRINT_ISATTY); - } else { - put_str(",", F, S, flags & JV_PRINT_ISATTY); - } - } - if (color) put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); - - first = 0; - if (color) put_str(FIELD_COLOR, F, S, flags & JV_PRINT_ISATTY); - jvp_dump_string(key, flags & JV_PRINT_ASCII, F, S, flags & JV_PRINT_ISATTY); - jv_free(key); - if (color) put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); - - if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); - put_str((flags & JV_PRINT_PRETTY) ? ": " : ":", F, S, flags & JV_PRINT_ISATTY); - if (color) put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); - - jv_dump_term(C, value, flags, indent + 1, F, S); - if (color) put_str(color, F, S, flags & JV_PRINT_ISATTY); - } - if (flags & JV_PRINT_PRETTY) { - put_char('\n', F, S, flags & JV_PRINT_ISATTY); - put_indent(indent, flags, F, S, flags & JV_PRINT_ISATTY); - } - 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); - if (color) { - put_str(COLRESET, F, S, flags & JV_PRINT_ISATTY); - } -} - -void jv_dumpf(jv x, FILE *f, int flags) { - struct dtoa_context C; - jvp_dtoa_context_init(&C); - jv_dump_term(&C, x, flags, 0, f, 0); - jvp_dtoa_context_free(&C); -} - -void jv_dump(jv x, int flags) { - jv_dumpf(x, stdout, flags); -} - -/* This one is nice for use in debuggers */ -void jv_show(jv x, int flags) { - if (flags == -1) - flags = JV_PRINT_PRETTY | JV_PRINT_COLOR | JV_PRINT_INDENT_FLAGS(2); - jv_dumpf(jv_copy(x), stderr, flags | JV_PRINT_INVALID); - fflush(stderr); -} - -jv jv_dump_string(jv x, int flags) { - struct dtoa_context C; - jvp_dtoa_context_init(&C); - jv s = jv_string(""); - jv_dump_term(&C, x, flags, 0, 0, &s); - jvp_dtoa_context_free(&C); - return s; -} - -char *jv_dump_string_trunc(jv x, char *outbuf, size_t bufsize) { - x = jv_dump_string(x,0); - const char* p = jv_string_value(x); - const size_t len = strlen(p); - strncpy(outbuf, p, bufsize); - outbuf[bufsize - 1] = 0; - if (len > bufsize - 1 && bufsize >= 4) { - // Indicate truncation with '...' - outbuf[bufsize - 2]='.'; - outbuf[bufsize - 3]='.'; - outbuf[bufsize - 4]='.'; - } - jv_free(x); - return outbuf; -} diff --git a/src/jq/jv_unicode.c b/src/jq/jv_unicode.c deleted file mode 100644 index b3a50b2..0000000 --- a/src/jq/jv_unicode.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include "jv_unicode.h" -#include "jv_utf8_tables.h" - -// jvp_utf8_backtrack returns the beginning of the last codepoint in the -// string, assuming that start is the last byte in the string. -// If the last codepoint is incomplete, returns the number of missing bytes via -// *missing_bytes. If there are no leading bytes or an invalid byte is -// encountered, NULL is returned and *missing_bytes is not altered. -const char* jvp_utf8_backtrack(const char* start, const char* min, int *missing_bytes) { - assert(min < start); - if (min == start) { - return min; - } - int length = 0; - int seen = 1; - while (start >= min && (length = utf8_coding_length[(unsigned char)*start]) == UTF8_CONTINUATION_BYTE) { - start--; - seen++; - } - if (length == 0 || length == UTF8_CONTINUATION_BYTE || length - seen < 0) { - return NULL; - } - if (missing_bytes) *missing_bytes = length - seen; - return start; -} - -const char* jvp_utf8_next(const char* in, const char* end, int* codepoint_ret) { - assert(in <= end); - if (in == end) { - return 0; - } - int codepoint = -1; - unsigned char first = (unsigned char)in[0]; - int length = utf8_coding_length[first]; - if ((first & 0x80) == 0) { - /* Fast-path for ASCII */ - codepoint = first; - length = 1; - } else if (length == 0 || length == UTF8_CONTINUATION_BYTE) { - /* Bad single byte - either an invalid byte or an out-of-place continuation byte */ - length = 1; - } else if (in + length > end) { - /* String ends before UTF8 sequence ends */ - length = end - in; - } else { - codepoint = ((unsigned)in[0]) & utf8_coding_bits[first]; - for (int i=1; i 0x10FFFF) { - /* Outside Unicode range */ - codepoint = -1; - } - } - assert(length > 0); - *codepoint_ret = codepoint; - return in + length; -} - -int jvp_utf8_is_valid(const char* in, const char* end) { - int codepoint; - while ((in = jvp_utf8_next(in, end, &codepoint))) { - if (codepoint == -1) return 0; - } - return 1; -} - -/* Assumes startchar is the first byte of a valid character sequence */ -int jvp_utf8_decode_length(char startchar) { - if ((startchar & 0x80) == 0) return 1; // 0___ ____ - else if ((startchar & 0xE0) == 0xC0) return 2; // 110_ ____ - else if ((startchar & 0xF0) == 0xE0) return 3; // 1110 ____ - else return 4; // 1111 ____ -} - -int jvp_utf8_encode_length(int codepoint) { - if (codepoint <= 0x7F) return 1; - else if (codepoint <= 0x7FF) return 2; - else if (codepoint <= 0xFFFF) return 3; - else return 4; -} - -int jvp_utf8_encode(int codepoint, char* out) { - assert(codepoint >= 0 && codepoint <= 0x10FFFF); - char* start = out; - if (codepoint <= 0x7F) { - *out++ = codepoint; - } else if (codepoint <= 0x7FF) { - *out++ = 0xC0 + ((codepoint & 0x7C0) >> 6); - *out++ = 0x80 + ((codepoint & 0x03F)); - } else if(codepoint <= 0xFFFF) { - *out++ = 0xE0 + ((codepoint & 0xF000) >> 12); - *out++ = 0x80 + ((codepoint & 0x0FC0) >> 6); - *out++ = 0x80 + ((codepoint & 0x003F)); - } else { - *out++ = 0xF0 + ((codepoint & 0x1C0000) >> 18); - *out++ = 0x80 + ((codepoint & 0x03F000) >> 12); - *out++ = 0x80 + ((codepoint & 0x000FC0) >> 6); - *out++ = 0x80 + ((codepoint & 0x00003F)); - } - assert(out - start == jvp_utf8_encode_length(codepoint)); - return out - start; -} diff --git a/src/jq/jv_unicode.h b/src/jq/jv_unicode.h deleted file mode 100644 index 558721a..0000000 --- a/src/jq/jv_unicode.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef JV_UNICODE_H -#define JV_UNICODE_H - -const char* jvp_utf8_backtrack(const char* start, const char* min, int *missing_bytes); -const char* jvp_utf8_next(const char* in, const char* end, int* codepoint); -int jvp_utf8_is_valid(const char* in, const char* end); - -int jvp_utf8_decode_length(char startchar); - -int jvp_utf8_encode_length(int codepoint); -int jvp_utf8_encode(int codepoint, char* out); -#endif diff --git a/src/jq/jv_utf8_tables.h b/src/jq/jv_utf8_tables.h deleted file mode 100644 index f1a4252..0000000 --- a/src/jq/jv_utf8_tables.h +++ /dev/null @@ -1,37 +0,0 @@ -#define UTF8_CONTINUATION_BYTE ((unsigned char)255) -static const unsigned char utf8_coding_length[] = - {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const unsigned char utf8_coding_bits[] = - {0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const int utf8_first_codepoint[] = - {0x00, 0x00, 0x80, 0x800, 0x10000}; diff --git a/src/jq/lexer.c b/src/jq/lexer.c deleted file mode 100644 index c369898..0000000 --- a/src/jq/lexer.c +++ /dev/null @@ -1,2442 +0,0 @@ -#line 2 "lexer.c" - -#line 4 "lexer.c" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yyg->yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yyg->yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE jq_yyrestart(yyin ,yyscanner ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k. - * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. - * Ditto for the __ia64__ case accordingly. - */ -#define YY_BUF_SIZE 32768 -#else -#define YY_BUF_SIZE 16384 -#endif /* __ia64__ */ -#endif - -/* The state buf must be large enough to hold one state per character in the main buffer. - */ -#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = yyg->yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via jq_yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ - ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ - : NULL) - -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] - -void jq_yyrestart (FILE *input_file ,yyscan_t yyscanner ); -void jq_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE jq_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void jq_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void jq_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void jq_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void jq_yypop_buffer_state (yyscan_t yyscanner ); - -static void jq_yyensure_buffer_stack (yyscan_t yyscanner ); -static void jq_yy_load_buffer_state (yyscan_t yyscanner ); -static void jq_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); - -#define YY_FLUSH_BUFFER jq_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) - -YY_BUFFER_STATE jq_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE jq_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE jq_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); - -void *jq_yyalloc (yy_size_t ,yyscan_t yyscanner ); -void *jq_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void jq_yyfree (void * ,yyscan_t yyscanner ); - -#define yy_new_buffer jq_yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - jq_yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - jq_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - jq_yyensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - jq_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define jq_yywrap(n) 1 -#define YY_SKIP_YYWRAP - -typedef unsigned char YY_CHAR; - -typedef int yy_state_type; - -#define yytext_ptr yytext_r - -static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); -static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yyg->yytext_ptr = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ - yyg->yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yyg->yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 49 -#define YY_END_OF_BUFFER 50 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static yyconst flex_int16_t yy_accept[154] = - { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 50, 48, 47, 47, 48, 39, 1, 34, - 34, 35, 36, 34, 34, 34, 34, 34, 38, 34, - 34, 34, 48, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 34, 43, 43, - 41, 44, 47, 2, 1, 29, 27, 25, 26, 33, - 38, 46, 46, 18, 28, 0, 31, 3, 32, 37, - 45, 0, 45, 45, 4, 45, 45, 45, 45, 45, - 45, 9, 45, 45, 45, 45, 14, 45, 45, 45, - 24, 43, 42, 40, 42, 46, 0, 38, 30, 38, - - 0, 45, 13, 45, 45, 8, 45, 45, 15, 45, - 45, 45, 45, 45, 45, 45, 19, 0, 42, 45, - 45, 45, 45, 12, 11, 45, 45, 45, 45, 45, - 45, 10, 42, 45, 22, 20, 45, 45, 45, 21, - 45, 45, 42, 45, 45, 5, 45, 7, 16, 23, - 17, 6, 0 - } ; - -static yyconst flex_int32_t yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 5, 6, 7, 8, 9, 1, 1, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 26, 26, 26, 27, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 28, 29, 30, 1, 31, 1, 32, 33, 34, 35, - - 36, 37, 26, 38, 39, 26, 40, 41, 42, 43, - 44, 45, 26, 46, 47, 48, 49, 26, 26, 26, - 50, 26, 51, 52, 53, 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, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst flex_int32_t 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 - } ; - -static yyconst flex_int16_t yy_base[167] = - { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 51, 52, 318, 319, 57, 59, 295, 319, 0, 319, - 294, 319, 319, 293, 292, 291, 47, 47, 50, 290, - 289, 288, 0, 290, 48, 51, 53, 52, 37, 59, - 57, 66, 56, 63, 68, 70, 72, 286, 0, 0, - 319, 80, 90, 319, 0, 319, 319, 319, 319, 95, - 99, 0, 106, 285, 319, 110, 319, 319, 319, 0, - 285, 281, 86, 77, 277, 97, 101, 111, 113, 115, - 117, 274, 119, 120, 118, 121, 270, 122, 123, 124, - 319, 0, 257, 319, 255, 0, 254, 249, 319, 245, - - 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, 319, 230, 239, 245, 250, 255, 264, 273, - 278, 283, 285, 290, 294, 298 - } ; - -static yyconst flex_int16_t yy_def[167] = - { 0, - 153, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 154, 154, 153, 153, 153, 153, 153, 153, 155, 153, - 153, 153, 153, 153, 153, 153, 156, 153, 153, 153, - 153, 153, 157, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 153, 159, 159, - 153, 160, 153, 153, 155, 153, 153, 153, 153, 153, - 153, 161, 161, 153, 153, 153, 153, 153, 153, 157, - 158, 153, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 153, 159, 153, 153, 162, 161, 153, 161, 153, 153, - - 163, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 160, 164, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 165, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 166, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 0, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153 - } ; - -static yyconst flex_int16_t yy_nxt[373] = - { 0, - 14, 15, 16, 14, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 20, 26, 27, 28, 29, 20, 20, - 30, 31, 32, 20, 33, 34, 34, 22, 14, 23, - 35, 36, 37, 38, 39, 40, 41, 34, 42, 34, - 43, 44, 34, 45, 34, 46, 34, 47, 34, 34, - 22, 48, 23, 50, 50, 72, 51, 51, 53, 53, - 53, 53, 60, 64, 61, 61, 72, 61, 65, 72, - 72, 72, 78, 63, 72, 72, 66, 72, 73, 52, - 52, 72, 63, 77, 72, 66, 72, 85, 72, 94, - 72, 53, 53, 74, 72, 72, 72, 75, 76, 79, - - 81, 80, 82, 72, 72, 88, 86, 83, 84, 89, - 61, 103, 61, 87, 61, 72, 61, 90, 97, 72, - 97, 66, 97, 98, 97, 66, 102, 100, 95, 72, - 66, 72, 104, 72, 66, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 106, 105, 109, - 113, 107, 72, 112, 72, 114, 115, 122, 116, 108, - 123, 72, 110, 111, 124, 72, 72, 72, 121, 125, - 72, 126, 72, 117, 153, 72, 72, 72, 72, 72, - 72, 72, 72, 129, 72, 72, 127, 128, 72, 72, - 134, 137, 72, 72, 72, 136, 132, 130, 135, 142, - - 131, 144, 72, 140, 141, 148, 138, 145, 72, 147, - 139, 149, 72, 95, 146, 72, 72, 72, 118, 72, - 150, 151, 72, 72, 118, 72, 72, 72, 72, 152, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 55, - 118, 55, 55, 55, 55, 55, 55, 55, 62, 62, - 72, 62, 72, 62, 70, 72, 70, 72, 70, 71, - 71, 71, 100, 71, 92, 92, 98, 92, 92, 92, - 92, 100, 92, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 96, 118, 96, 118, 96, 119, 72, 119, - 119, 120, 72, 120, 133, 72, 133, 133, 143, 101, - - 143, 143, 93, 72, 93, 93, 99, 91, 72, 69, - 68, 67, 59, 58, 57, 56, 54, 153, 13, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153 - } ; - -static yyconst flex_int16_t yy_chk[373] = - { 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, 39, 11, 12, 15, 15, - 16, 16, 27, 28, 27, 29, 35, 29, 28, 36, - 38, 37, 39, 27, 43, 41, 29, 40, 35, 11, - 12, 44, 27, 38, 42, 29, 45, 43, 46, 52, - 47, 53, 53, 36, 152, 74, 151, 36, 37, 40, - - 41, 40, 42, 150, 73, 46, 44, 42, 42, 47, - 60, 74, 60, 45, 61, 76, 61, 47, 63, 77, - 63, 60, 66, 63, 66, 61, 73, 66, 52, 78, - 60, 79, 76, 80, 61, 81, 85, 83, 84, 86, - 88, 89, 90, 102, 104, 105, 107, 78, 77, 80, - 85, 79, 108, 84, 110, 86, 88, 104, 89, 79, - 105, 111, 81, 83, 107, 112, 113, 114, 102, 108, - 115, 110, 116, 90, 118, 121, 123, 122, 126, 127, - 128, 129, 130, 113, 131, 138, 111, 112, 141, 134, - 121, 126, 137, 139, 142, 123, 116, 114, 122, 131, - - 115, 134, 145, 129, 130, 141, 127, 137, 144, 139, - 128, 142, 147, 118, 138, 149, 148, 146, 143, 140, - 144, 145, 136, 135, 133, 132, 125, 124, 120, 147, - 154, 154, 154, 154, 154, 154, 154, 154, 154, 155, - 119, 155, 155, 155, 155, 155, 155, 155, 156, 156, - 117, 156, 109, 156, 157, 106, 157, 103, 157, 158, - 158, 158, 100, 158, 159, 159, 98, 159, 159, 159, - 159, 97, 159, 160, 160, 160, 160, 160, 160, 160, - 160, 160, 161, 95, 161, 93, 161, 162, 87, 162, - 162, 163, 82, 163, 164, 75, 164, 164, 165, 72, - - 165, 165, 166, 71, 166, 166, 64, 48, 34, 32, - 31, 30, 26, 25, 24, 21, 17, 13, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153 - } ; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -#line 1 "lexer.l" -#line 2 "lexer.l" -#include -#include "jv_alloc.h" -#include "compile.h" - -struct lexer_param; - -#include "parser.h" /* Generated by bison. */ - -#define YY_USER_ACTION \ - do { \ - yylloc->start = jq_yyget_extra(yyscanner); \ - yylloc->end = yylloc->start + yyleng; \ - jq_yyset_extra(yylloc->end,yyscanner); \ - } while (0); - - - - - - -#line 25 "lexer.l" - static int enter(int opening, int state, yyscan_t yyscanner); - static int try_exit(int closing, int state, yyscan_t yyscanner); -#define YY_NO_INPUT 1 -#line 601 "lexer.c" - -#define INITIAL 0 -#define IN_PAREN 1 -#define IN_BRACKET 2 -#define IN_BRACE 3 -#define IN_QQINTERP 4 -#define IN_QQSTRING 5 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#define YY_EXTRA_TYPE int - -/* Holds the entire state of the reentrant scanner. */ -struct yyguts_t - { - - /* User-defined. Not touched by flex. */ - YY_EXTRA_TYPE yyextra_r; - - /* The rest are the same as the globals declared in the non-reentrant scanner. */ - FILE *yyin_r, *yyout_r; - size_t yy_buffer_stack_top; /**< index of top of stack. */ - size_t yy_buffer_stack_max; /**< capacity of stack. */ - YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ - char yy_hold_char; - int yy_n_chars; - int yyleng_r; - char *yy_c_buf_p; - int yy_init; - int yy_start; - int yy_did_buffer_switch_on_eof; - int yy_start_stack_ptr; - int yy_start_stack_depth; - int *yy_start_stack; - yy_state_type yy_last_accepting_state; - char* yy_last_accepting_cpos; - - int yylineno_r; - int yy_flex_debug_r; - - char *yytext_r; - int yy_more_flag; - int yy_more_len; - - YYSTYPE * yylval_r; - - YYLTYPE * yylloc_r; - - }; /* end struct yyguts_t */ - -static int yy_init_globals (yyscan_t yyscanner ); - - /* This must go here because YYSTYPE and YYLTYPE are included - * from bison output in section 1.*/ - # define yylval yyg->yylval_r - - # define yylloc yyg->yylloc_r - -int jq_yylex_init (yyscan_t* scanner); - -int jq_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int jq_yylex_destroy (yyscan_t yyscanner ); - -int jq_yyget_debug (yyscan_t yyscanner ); - -void jq_yyset_debug (int debug_flag ,yyscan_t yyscanner ); - -YY_EXTRA_TYPE jq_yyget_extra (yyscan_t yyscanner ); - -void jq_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); - -FILE *jq_yyget_in (yyscan_t yyscanner ); - -void jq_yyset_in (FILE * in_str ,yyscan_t yyscanner ); - -FILE *jq_yyget_out (yyscan_t yyscanner ); - -void jq_yyset_out (FILE * out_str ,yyscan_t yyscanner ); - -int jq_yyget_leng (yyscan_t yyscanner ); - -char *jq_yyget_text (yyscan_t yyscanner ); - -int jq_yyget_lineno (yyscan_t yyscanner ); - -void jq_yyset_lineno (int line_number ,yyscan_t yyscanner ); - -YYSTYPE * jq_yyget_lval (yyscan_t yyscanner ); - -void jq_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); - - YYLTYPE *jq_yyget_lloc (yyscan_t yyscanner ); - - void jq_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int jq_yywrap (yyscan_t yyscanner ); -#else -extern int jq_yywrap (yyscan_t yyscanner ); -#endif -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#ifdef __cplusplus -static int yyinput (yyscan_t yyscanner ); -#else -static int input (yyscan_t yyscanner ); -#endif - -#endif - - static void yy_push_state (int new_state ,yyscan_t yyscanner); - - static void yy_pop_state (yyscan_t yyscanner ); - - static int yy_top_state (yyscan_t yyscanner ); - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k */ -#define YY_READ_BUF_SIZE 16384 -#else -#define YY_READ_BUF_SIZE 8192 -#endif /* __ia64__ */ -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ - { \ - int c = '*'; \ - size_t n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else \ - { \ - errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(yyin); \ - } \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int jq_yylex \ - (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); - -#define YY_DECL int jq_yylex \ - (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -/** The main scanner function which does all the work. - */ -YY_DECL -{ - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - -#line 38 "lexer.l" - - -#line 857 "lexer.c" - - yylval = yylval_param; - - yylloc = yylloc_param; - - if ( !yyg->yy_init ) - { - yyg->yy_init = 1; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yyg->yy_start ) - yyg->yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - jq_yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - jq_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); - } - - jq_yy_load_buffer_state(yyscanner ); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yyg->yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yyg->yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yyg->yy_start; -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - 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 >= 154 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 319 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yyg->yy_hold_char; - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 40 "lexer.l" -{ /* comments */ } - YY_BREAK -case 2: -YY_RULE_SETUP -#line 42 "lexer.l" -{ return NEQ; } - YY_BREAK -case 3: -YY_RULE_SETUP -#line 43 "lexer.l" -{ return EQ; } - YY_BREAK -case 4: -YY_RULE_SETUP -#line 44 "lexer.l" -{ return AS; } - YY_BREAK -case 5: -YY_RULE_SETUP -#line 45 "lexer.l" -{ return IMPORT; } - YY_BREAK -case 6: -YY_RULE_SETUP -#line 46 "lexer.l" -{ return INCLUDE; } - YY_BREAK -case 7: -YY_RULE_SETUP -#line 47 "lexer.l" -{ return MODULE; } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 48 "lexer.l" -{ return DEF; } - YY_BREAK -case 9: -YY_RULE_SETUP -#line 49 "lexer.l" -{ return IF; } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 50 "lexer.l" -{ return THEN; } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 51 "lexer.l" -{ return ELSE; } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 52 "lexer.l" -{ return ELSE_IF; } - YY_BREAK -case 13: -YY_RULE_SETUP -#line 53 "lexer.l" -{ return AND; } - YY_BREAK -case 14: -YY_RULE_SETUP -#line 54 "lexer.l" -{ return OR; } - YY_BREAK -case 15: -YY_RULE_SETUP -#line 55 "lexer.l" -{ return END; } - YY_BREAK -case 16: -YY_RULE_SETUP -#line 56 "lexer.l" -{ return REDUCE; } - YY_BREAK -case 17: -YY_RULE_SETUP -#line 57 "lexer.l" -{ return FOREACH; } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 58 "lexer.l" -{ return DEFINEDOR; } - YY_BREAK -case 19: -YY_RULE_SETUP -#line 59 "lexer.l" -{ return TRY; } - YY_BREAK -case 20: -YY_RULE_SETUP -#line 60 "lexer.l" -{ return CATCH; } - YY_BREAK -case 21: -YY_RULE_SETUP -#line 61 "lexer.l" -{ return LABEL; } - YY_BREAK -case 22: -YY_RULE_SETUP -#line 62 "lexer.l" -{ return BREAK; } - YY_BREAK -case 23: -YY_RULE_SETUP -#line 63 "lexer.l" -{ return LOC; } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 64 "lexer.l" -{ return SETPIPE; } - YY_BREAK -case 25: -YY_RULE_SETUP -#line 65 "lexer.l" -{ return SETPLUS; } - YY_BREAK -case 26: -YY_RULE_SETUP -#line 66 "lexer.l" -{ return SETMINUS; } - YY_BREAK -case 27: -YY_RULE_SETUP -#line 67 "lexer.l" -{ return SETMULT; } - YY_BREAK -case 28: -YY_RULE_SETUP -#line 68 "lexer.l" -{ return SETDIV; } - YY_BREAK -case 29: -YY_RULE_SETUP -#line 69 "lexer.l" -{ return SETMOD; } - YY_BREAK -case 30: -YY_RULE_SETUP -#line 70 "lexer.l" -{ return SETDEFINEDOR; } - YY_BREAK -case 31: -YY_RULE_SETUP -#line 71 "lexer.l" -{ return LESSEQ; } - YY_BREAK -case 32: -YY_RULE_SETUP -#line 72 "lexer.l" -{ return GREATEREQ; } - YY_BREAK -case 33: -YY_RULE_SETUP -#line 73 "lexer.l" -{ return REC; } - YY_BREAK -case 34: -YY_RULE_SETUP -#line 74 "lexer.l" -{ return yytext[0];} - YY_BREAK -case 35: -YY_RULE_SETUP -#line 76 "lexer.l" -{ - return enter(yytext[0], YY_START, yyscanner); -} - YY_BREAK -case 36: -YY_RULE_SETUP -#line 80 "lexer.l" -{ - return try_exit(yytext[0], YY_START, yyscanner); -} - YY_BREAK -case 37: -YY_RULE_SETUP -#line 84 "lexer.l" -{ - yylval->literal = jv_string_sized(yytext + 1, yyleng - 1); return FORMAT; -} - YY_BREAK -case 38: -YY_RULE_SETUP -#line 88 "lexer.l" -{ - yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; -} - YY_BREAK -case 39: -YY_RULE_SETUP -#line 92 "lexer.l" -{ - yy_push_state(IN_QQSTRING, yyscanner); - return QQSTRING_START; -} - YY_BREAK - -case 40: -YY_RULE_SETUP -#line 98 "lexer.l" -{ - return enter(QQSTRING_INTERP_START, YY_START, yyscanner); - } - YY_BREAK -case 41: -YY_RULE_SETUP -#line 101 "lexer.l" -{ - yy_pop_state(yyscanner); - return QQSTRING_END; - } - YY_BREAK -case 42: -/* rule 42 can match eol */ -YY_RULE_SETUP -#line 105 "lexer.l" -{ - /* pass escapes to the json parser */ - jv escapes = jv_string_fmt("\"%.*s\"", (int)yyleng, yytext); - yylval->literal = jv_parse_sized(jv_string_value(escapes), jv_string_length_bytes(jv_copy(escapes))); - jv_free(escapes); - return QQSTRING_TEXT; - } - YY_BREAK -case 43: -/* rule 43 can match eol */ -YY_RULE_SETUP -#line 112 "lexer.l" -{ - yylval->literal = jv_string_sized(yytext, yyleng); - return QQSTRING_TEXT; - } - YY_BREAK -case 44: -YY_RULE_SETUP -#line 116 "lexer.l" -{ - return INVALID_CHARACTER; - } - YY_BREAK - -case 45: -YY_RULE_SETUP -#line 122 "lexer.l" -{ yylval->literal = jv_string(yytext); return IDENT;} - YY_BREAK -case 46: -YY_RULE_SETUP -#line 123 "lexer.l" -{ yylval->literal = jv_string(yytext+1); return FIELD;} - YY_BREAK -case 47: -/* rule 47 can match eol */ -YY_RULE_SETUP -#line 125 "lexer.l" -{} - YY_BREAK -case 48: -YY_RULE_SETUP -#line 127 "lexer.l" -{ return INVALID_CHARACTER; } - YY_BREAK -case 49: -YY_RULE_SETUP -#line 129 "lexer.l" -YY_FATAL_ERROR( "flex scanner jammed" ); - YY_BREAK -#line 1221 "lexer.c" -case YY_STATE_EOF(INITIAL): -case YY_STATE_EOF(IN_PAREN): -case YY_STATE_EOF(IN_BRACKET): -case YY_STATE_EOF(IN_BRACE): -case YY_STATE_EOF(IN_QQINTERP): -case YY_STATE_EOF(IN_QQSTRING): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yyg->yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * jq_yylex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); - - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yyg->yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yyg->yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_END_OF_FILE: - { - yyg->yy_did_buffer_switch_on_eof = 0; - - if ( jq_yywrap(yyscanner ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = - yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yyg->yy_c_buf_p = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ -} /* end of jq_yylex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; - - else - { - int num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; - - int yy_c_buf_p_offset = - (int) (yyg->yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - jq_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - - number_to_move - 1; - - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, (size_t) num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - if ( yyg->yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - jq_yyrestart(yyin ,yyscanner); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { - /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) jq_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); - if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); - } - - yyg->yy_n_chars += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (yyscan_t yyscanner) -{ - register yy_state_type yy_current_state; - register char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_current_state = yyg->yy_start; - - for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - 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 >= 154 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) -{ - register int yy_is_jam; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - register char *yy_cp = yyg->yy_c_buf_p; - - register YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - 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 >= 154 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 153); - - return yy_is_jam ? 0 : yy_current_state; -} - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (yyscan_t yyscanner) -#else - static int input (yyscan_t yyscanner) -#endif - -{ - int c; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - *yyg->yy_c_buf_p = yyg->yy_hold_char; - - if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - /* This was really a NUL. */ - *yyg->yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; - ++yyg->yy_c_buf_p; - - switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - jq_yyrestart(yyin ,yyscanner); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( jq_yywrap(yyscanner ) ) - return EOF; - - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(yyscanner); -#else - return input(yyscanner); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = yyg->yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ - *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ - yyg->yy_hold_char = *++yyg->yy_c_buf_p; - - return c; -} -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * @param yyscanner The scanner object. - * @note This function does not reset the start condition to @c INITIAL . - */ - void jq_yyrestart (FILE * input_file , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! YY_CURRENT_BUFFER ){ - jq_yyensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - jq_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); - } - - jq_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); - jq_yy_load_buffer_state(yyscanner ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * @param yyscanner The scanner object. - */ - void jq_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* TODO. We should be able to replace this entire function body - * with - * jq_yypop_buffer_state(); - * jq_yypush_buffer_state(new_buffer); - */ - jq_yyensure_buffer_stack (yyscanner); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - jq_yy_load_buffer_state(yyscanner ); - - /* We don't actually know whether we did this switch during - * EOF (jq_yywrap()) processing, but the only time this flag - * is looked at is after jq_yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yyg->yy_did_buffer_switch_on_eof = 1; -} - -static void jq_yy_load_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - yyg->yy_hold_char = *yyg->yy_c_buf_p; -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * @param yyscanner The scanner object. - * @return the allocated buffer state. - */ - YY_BUFFER_STATE jq_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) jq_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in jq_yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) jq_yyalloc(b->yy_buf_size + 2 ,yyscanner ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in jq_yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - jq_yy_init_buffer(b,file ,yyscanner); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with jq_yy_create_buffer() - * @param yyscanner The scanner object. - */ - void jq_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - jq_yyfree((void *) b->yy_ch_buf ,yyscanner ); - - jq_yyfree((void *) b ,yyscanner ); -} - -#ifndef __cplusplus -extern int isatty (int ); -#endif /* __cplusplus */ - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a jq_yyrestart() or at EOF. - */ - static void jq_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) - -{ - int oerrno = errno; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - jq_yy_flush_buffer(b ,yyscanner); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then jq_yy_init_buffer was _probably_ - * called from jq_yyrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * @param yyscanner The scanner object. - */ - void jq_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - jq_yy_load_buffer_state(yyscanner ); -} - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * @param yyscanner The scanner object. - */ -void jq_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (new_buffer == NULL) - return; - - jq_yyensure_buffer_stack(yyscanner); - - /* This block is copied from jq_yy_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - yyg->yy_buffer_stack_top++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from jq_yy_switch_to_buffer. */ - jq_yy_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * @param yyscanner The scanner object. - */ -void jq_yypop_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (!YY_CURRENT_BUFFER) - return; - - jq_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); - YY_CURRENT_BUFFER_LVALUE = NULL; - if (yyg->yy_buffer_stack_top > 0) - --yyg->yy_buffer_stack_top; - - if (YY_CURRENT_BUFFER) { - jq_yy_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void jq_yyensure_buffer_stack (yyscan_t yyscanner) -{ - int num_to_alloc; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (!yyg->yy_buffer_stack) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; - yyg->yy_buffer_stack = (struct yy_buffer_state**)jq_yyalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in jq_yyensure_buffer_stack()" ); - - memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - yyg->yy_buffer_stack_max = num_to_alloc; - yyg->yy_buffer_stack_top = 0; - return; - } - - if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = yyg->yy_buffer_stack_max + grow_size; - yyg->yy_buffer_stack = (struct yy_buffer_state**)jq_yyrealloc - (yyg->yy_buffer_stack, - num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in jq_yyensure_buffer_stack()" ); - - /* zero only the new slots.*/ - memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); - yyg->yy_buffer_stack_max = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE jq_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) jq_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in jq_yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - jq_yy_switch_to_buffer(b ,yyscanner ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to jq_yylex() will - * scan from a @e copy of @a str. - * @param yystr a NUL-terminated string to scan - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * jq_yy_scan_bytes() instead. - */ -YY_BUFFER_STATE jq_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) -{ - - return jq_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); -} - -/** Setup the input buffer state to scan the given bytes. The next call to jq_yylex() will - * scan from a @e copy of @a bytes. - * @param yybytes the byte buffer to scan - * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE jq_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; - buf = (char *) jq_yyalloc(n ,yyscanner ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in jq_yy_scan_bytes()" ); - - for ( i = 0; i < _yybytes_len; ++i ) - buf[i] = yybytes[i]; - - buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - - b = jq_yy_scan_buffer(buf,n ,yyscanner); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in jq_yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - - static void yy_push_state (int new_state , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth ) - { - yy_size_t new_size; - - yyg->yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yyg->yy_start_stack_depth * sizeof( int ); - - if ( ! yyg->yy_start_stack ) - yyg->yy_start_stack = (int *) jq_yyalloc(new_size ,yyscanner ); - - else - yyg->yy_start_stack = (int *) jq_yyrealloc((void *) yyg->yy_start_stack,new_size ,yyscanner ); - - if ( ! yyg->yy_start_stack ) - YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); - } - - yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START; - - BEGIN(new_state); -} - - static void yy_pop_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( --yyg->yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); - - BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]); -} - - static int yy_top_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1]; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) -{ - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = yyg->yy_hold_char; \ - yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ - yyg->yy_hold_char = *yyg->yy_c_buf_p; \ - *yyg->yy_c_buf_p = '\0'; \ - yyleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the user-defined data for this scanner. - * @param yyscanner The scanner object. - */ -YY_EXTRA_TYPE jq_yyget_extra (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyextra; -} - -/** Get the current line number. - * @param yyscanner The scanner object. - */ -int jq_yyget_lineno (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yylineno; -} - -/** Get the current column number. - * @param yyscanner The scanner object. - */ -int jq_yyget_column (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yycolumn; -} - -/** Get the input stream. - * @param yyscanner The scanner object. - */ -FILE *jq_yyget_in (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyin; -} - -/** Get the output stream. - * @param yyscanner The scanner object. - */ -FILE *jq_yyget_out (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyout; -} - -/** Get the length of the current token. - * @param yyscanner The scanner object. - */ -int jq_yyget_leng (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyleng; -} - -/** Get the current token. - * @param yyscanner The scanner object. - */ - -char *jq_yyget_text (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yytext; -} - -/** Set the user-defined data. This data is never touched by the scanner. - * @param user_defined The data to be associated with this scanner. - * @param yyscanner The scanner object. - */ -void jq_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyextra = user_defined ; -} - -/** Set the current line number. - * @param line_number - * @param yyscanner The scanner object. - */ -void jq_yyset_lineno (int line_number , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* lineno is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "jq_yyset_lineno called with no buffer" , yyscanner); - - yylineno = line_number; -} - -/** Set the current column. - * @param line_number - * @param yyscanner The scanner object. - */ -void jq_yyset_column (int column_no , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* column is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "jq_yyset_column called with no buffer" , yyscanner); - - yycolumn = column_no; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param in_str A readable stream. - * @param yyscanner The scanner object. - * @see jq_yy_switch_to_buffer - */ -void jq_yyset_in (FILE * in_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyin = in_str ; -} - -void jq_yyset_out (FILE * out_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyout = out_str ; -} - -int jq_yyget_debug (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yy_flex_debug; -} - -void jq_yyset_debug (int bdebug , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yy_flex_debug = bdebug ; -} - -/* Accessor methods for yylval and yylloc */ - -YYSTYPE * jq_yyget_lval (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yylval; -} - -void jq_yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yylval = yylval_param; -} - -YYLTYPE *jq_yyget_lloc (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yylloc; -} - -void jq_yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yylloc = yylloc_param; -} - -/* User-visible API */ - -/* jq_yylex_init is special because it creates the scanner itself, so it is - * the ONLY reentrant function that doesn't take the scanner as the last argument. - * That's why we explicitly handle the declaration, instead of using our macros. - */ - -int jq_yylex_init(yyscan_t* ptr_yy_globals) - -{ - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) jq_yyalloc ( sizeof( struct yyguts_t ), NULL ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - return yy_init_globals ( *ptr_yy_globals ); -} - -/* jq_yylex_init_extra has the same functionality as jq_yylex_init, but follows the - * convention of taking the scanner as the last argument. Note however, that - * this is a *pointer* to a scanner, as it will be allocated by this call (and - * is the reason, too, why this function also must handle its own declaration). - * The user defined value in the first argument will be available to jq_yyalloc in - * the yyextra field. - */ - -int jq_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) - -{ - struct yyguts_t dummy_yyguts; - - jq_yyset_extra (yy_user_defined, &dummy_yyguts); - - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) jq_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in - yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - jq_yyset_extra (yy_user_defined, *ptr_yy_globals); - - return yy_init_globals ( *ptr_yy_globals ); -} - -static int yy_init_globals (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - /* Initialization is the same as for the non-reentrant scanner. - * This function is called from jq_yylex_destroy(), so don't allocate here. - */ - - yyg->yy_buffer_stack = 0; - yyg->yy_buffer_stack_top = 0; - yyg->yy_buffer_stack_max = 0; - yyg->yy_c_buf_p = (char *) 0; - yyg->yy_init = 0; - yyg->yy_start = 0; - - yyg->yy_start_stack_ptr = 0; - yyg->yy_start_stack_depth = 0; - yyg->yy_start_stack = NULL; - -/* Defined in main.c */ -#ifdef YY_STDINIT - yyin = stdin; - yyout = stdout; -#else - yyin = (FILE *) 0; - yyout = (FILE *) 0; -#endif - - /* For future reference: Set errno on error, since we are called by - * jq_yylex_init() - */ - return 0; -} - -/* jq_yylex_destroy is for both reentrant and non-reentrant scanners. */ -int jq_yylex_destroy (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - jq_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); - YY_CURRENT_BUFFER_LVALUE = NULL; - jq_yypop_buffer_state(yyscanner); - } - - /* Destroy the stack itself. */ - jq_yyfree(yyg->yy_buffer_stack ,yyscanner); - yyg->yy_buffer_stack = NULL; - - /* Destroy the start condition stack. */ - jq_yyfree(yyg->yy_start_stack ,yyscanner ); - yyg->yy_start_stack = NULL; - - /* Reset the globals. This is important in a non-reentrant scanner so the next time - * jq_yylex() is called, initialization will occur. */ - yy_init_globals( yyscanner); - - /* Destroy the main struct (reentrant only). */ - jq_yyfree ( yyscanner , yyscanner ); - yyscanner = NULL; - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) -{ - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; -} -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) -{ - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; -} -#endif - -#define YYTABLES_NAME "yytables" - -#line 129 "lexer.l" - - -/* perhaps these should be calls... */ -/* -"true" { return TRUE; } -"false" { return FALSE; } -"null" { return NULL; } -*/ -static int try_exit(int c, int state, yyscan_t yyscanner) { - char match = 0; - int ret; - switch (state) { - case IN_PAREN: match = ret = ')'; break; - case IN_BRACKET: match = ret = ']'; break; - case IN_BRACE: match = ret = '}'; break; - - case IN_QQINTERP: - match = ')'; - ret = QQSTRING_INTERP_END; - break; - - default: - // may not be the best error to give - return INVALID_CHARACTER; - } - assert(match); - if (match == c) { - yy_pop_state(yyscanner); - return ret; - } else { - // FIXME: should we pop? Give a better error at least - return INVALID_CHARACTER; - } -} - -static int enter(int c, int currstate, yyscan_t yyscanner) { - int state = 0; - switch (c) { - case '(': state = IN_PAREN; break; - case '[': state = IN_BRACKET; break; - case '{': state = IN_BRACE; break; - case QQSTRING_INTERP_START: state = IN_QQINTERP; break; - } - assert(state); - yy_push_state(state, yyscanner); - return c; -} - -void* jq_yyalloc(size_t sz,void* extra) { - return jv_mem_alloc(sz); -} -void* jq_yyrealloc(void* p,size_t sz,void* extra) { - return jv_mem_realloc(p, sz); -} -void jq_yyfree(void* p,void* extra) { - jv_mem_free(p); -} - diff --git a/src/jq/lexer.h b/src/jq/lexer.h deleted file mode 100644 index 0eb8506..0000000 --- a/src/jq/lexer.h +++ /dev/null @@ -1,362 +0,0 @@ -#ifndef jq_yyHEADER_H -#define jq_yyHEADER_H 1 -#define jq_yyIN_HEADER 1 - -#line 6 "lexer.h" - -#line 8 "lexer.h" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k. - * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. - * Ditto for the __ia64__ case accordingly. - */ -#define YY_BUF_SIZE 32768 -#else -#define YY_BUF_SIZE 16384 -#endif /* __ia64__ */ -#endif - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -void jq_yyrestart (FILE *input_file ,yyscan_t yyscanner ); -void jq_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE jq_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void jq_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void jq_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void jq_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void jq_yypop_buffer_state (yyscan_t yyscanner ); - -YY_BUFFER_STATE jq_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE jq_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE jq_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); - -void *jq_yyalloc (yy_size_t ,yyscan_t yyscanner ); -void *jq_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void jq_yyfree (void * ,yyscan_t yyscanner ); - -/* Begin user sect3 */ - -#define jq_yywrap(n) 1 -#define YY_SKIP_YYWRAP - -#define yytext_ptr yytext_r - -#ifdef YY_HEADER_EXPORT_START_CONDITIONS -#define INITIAL 0 -#define IN_PAREN 1 -#define IN_BRACKET 2 -#define IN_BRACE 3 -#define IN_QQINTERP 4 -#define IN_QQSTRING 5 - -#endif - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#define YY_EXTRA_TYPE int - -int jq_yylex_init (yyscan_t* scanner); - -int jq_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int jq_yylex_destroy (yyscan_t yyscanner ); - -int jq_yyget_debug (yyscan_t yyscanner ); - -void jq_yyset_debug (int debug_flag ,yyscan_t yyscanner ); - -YY_EXTRA_TYPE jq_yyget_extra (yyscan_t yyscanner ); - -void jq_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); - -FILE *jq_yyget_in (yyscan_t yyscanner ); - -void jq_yyset_in (FILE * in_str ,yyscan_t yyscanner ); - -FILE *jq_yyget_out (yyscan_t yyscanner ); - -void jq_yyset_out (FILE * out_str ,yyscan_t yyscanner ); - -int jq_yyget_leng (yyscan_t yyscanner ); - -char *jq_yyget_text (yyscan_t yyscanner ); - -int jq_yyget_lineno (yyscan_t yyscanner ); - -void jq_yyset_lineno (int line_number ,yyscan_t yyscanner ); - -YYSTYPE * jq_yyget_lval (yyscan_t yyscanner ); - -void jq_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); - - YYLTYPE *jq_yyget_lloc (yyscan_t yyscanner ); - - void jq_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int jq_yywrap (yyscan_t yyscanner ); -#else -extern int jq_yywrap (yyscan_t yyscanner ); -#endif -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k */ -#define YY_READ_BUF_SIZE 16384 -#else -#define YY_READ_BUF_SIZE 8192 -#endif /* __ia64__ */ -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int jq_yylex \ - (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); - -#define YY_DECL int jq_yylex \ - (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -#undef YY_NEW_FILE -#undef YY_FLUSH_BUFFER -#undef yy_set_bol -#undef yy_new_buffer -#undef yy_set_interactive -#undef YY_DO_BEFORE_ACTION - -#ifdef YY_DECL_IS_OURS -#undef YY_DECL_IS_OURS -#undef YY_DECL -#endif - -#line 129 "lexer.l" - - -#line 361 "lexer.h" -#undef jq_yyIN_HEADER -#endif /* jq_yyHEADER_H */ diff --git a/src/jq/libm.h b/src/jq/libm.h deleted file mode 100644 index 4b99e1d..0000000 --- a/src/jq/libm.h +++ /dev/null @@ -1,301 +0,0 @@ -#ifdef HAVE_ACOS -LIBM_DD(acos) -#else -LIBM_DD_NO(acos) -#endif -#ifdef HAVE_ACOSH -LIBM_DD(acosh) -#else -LIBM_DD_NO(acosh) -#endif -#ifdef HAVE_ASIN -LIBM_DD(asin) -#else -LIBM_DD_NO(asin) -#endif -#ifdef HAVE_ASINH -LIBM_DD(asinh) -#else -LIBM_DD_NO(asinh) -#endif -#ifdef HAVE_ATAN -LIBM_DD(atan) -#else -LIBM_DD_NO(atan) -#endif -#ifdef HAVE_ATAN2 -LIBM_DDD(atan2) -#else -LIBM_DDD_NO(atan2) -#endif -#ifdef HAVE_ATANH -LIBM_DD(atanh) -#else -LIBM_DD_NO(atanh) -#endif -#ifdef HAVE_CBRT -LIBM_DD(cbrt) -#else -LIBM_DD_NO(cbrt) -#endif -#ifdef HAVE_COS -LIBM_DD(cos) -#else -LIBM_DD_NO(cos) -#endif -#ifdef HAVE_COSH -LIBM_DD(cosh) -#else -LIBM_DD_NO(cosh) -#endif -#ifdef HAVE_EXP -LIBM_DD(exp) -#else -LIBM_DD_NO(exp) -#endif -#ifdef HAVE_EXP2 -LIBM_DD(exp2) -#else -LIBM_DD_NO(exp2) -#endif -#ifdef HAVE_FLOOR -LIBM_DD(floor) -#else -LIBM_DD_NO(floor) -#endif -#ifdef HAVE_HYPOT -LIBM_DDD(hypot) -#else -LIBM_DDD_NO(hypot) -#endif -#ifdef HAVE_J0 -LIBM_DD(j0) -#else -LIBM_DD_NO(j0) -#endif -#ifdef HAVE_J1 -LIBM_DD(j1) -#else -LIBM_DD_NO(j1) -#endif -#ifdef HAVE_LOG -LIBM_DD(log) -#else -LIBM_DD_NO(log) -#endif -#ifdef HAVE_LOG10 -LIBM_DD(log10) -#else -LIBM_DD_NO(log10) -#endif -#ifdef HAVE_LOG2 -LIBM_DD(log2) -#else -LIBM_DD_NO(log2) -#endif -#ifdef HAVE_POW -LIBM_DDD(pow) -#else -LIBM_DDD_NO(pow) -#endif -#ifdef HAVE_REMAINDER -LIBM_DDD(remainder) -#else -LIBM_DDD_NO(remainder) -#endif -#ifdef HAVE_SIN -LIBM_DD(sin) -#else -LIBM_DD_NO(sin) -#endif -#ifdef HAVE_SINH -LIBM_DD(sinh) -#else -LIBM_DD_NO(sinh) -#endif -#ifdef HAVE_SQRT -LIBM_DD(sqrt) -#else -LIBM_DD_NO(sqrt) -#endif -#ifdef HAVE_TAN -LIBM_DD(tan) -#else -LIBM_DD_NO(tan) -#endif -#ifdef HAVE_TANH -LIBM_DD(tanh) -#else -LIBM_DD_NO(tanh) -#endif -#ifdef HAVE_TGAMMA -LIBM_DD(tgamma) -#else -LIBM_DD_NO(tgamma) -#endif -#ifdef HAVE_Y0 -LIBM_DD(y0) -#else -LIBM_DD_NO(y0) -#endif -#ifdef HAVE_Y1 -LIBM_DD(y1) -#else -LIBM_DD_NO(y1) -#endif -#ifdef HAVE_JN -LIBM_DID(jn) -#endif -#ifdef HAVE_YN -LIBM_DID(yn) -#endif -#ifdef HAVE_CEIL -LIBM_DD(ceil) -#else -LIBM_DD_NO(ceil) -#endif -#ifdef HAVE_COPYSIGN -LIBM_DDD(copysign) -#else -LIBM_DDD_NO(copysign) -#endif -#ifdef HAVE_DREM -LIBM_DDD(drem) -#else -LIBM_DDD_NO(drem) -#endif -#ifdef HAVE_ERF -LIBM_DD(erf) -#else -LIBM_DD_NO(erf) -#endif -#ifdef HAVE_ERFC -LIBM_DD(erfc) -#else -LIBM_DD_NO(erfc) -#endif -#ifdef HAVE_EXP10 -LIBM_DD(exp10) -#else -LIBM_DD_NO(exp10) -#endif -#ifdef HAVE_EXPM1 -LIBM_DD(expm1) -#else -LIBM_DD_NO(expm1) -#endif -#ifdef HAVE_FABS -LIBM_DD(fabs) -#else -LIBM_DD_NO(fabs) -#endif -#ifdef HAVE_FDIM -LIBM_DDD(fdim) -#else -LIBM_DDD_NO(fdim) -#endif -#ifdef HAVE_FMA -LIBM_DDDD(fma) -#else -LIBM_DDDD_NO(fma) -#endif -#ifdef HAVE_FMAX -LIBM_DDD(fmax) -#else -LIBM_DDD_NO(fmax) -#endif -#ifdef HAVE_FMIN -LIBM_DDD(fmin) -#else -LIBM_DDD_NO(fmin) -#endif -#ifdef HAVE_FMOD -LIBM_DDD(fmod) -#else -LIBM_DDD_NO(fmod) -#endif -#ifdef HAVE_FREXP -LIBM_DDD(frexp) -#else -LIBM_DDD_NO(frexp) -#endif -#ifdef HAVE_GAMMA -LIBM_DD(gamma) -#else -LIBM_DD_NO(gamma) -#endif -#ifdef HAVE_LGAMMA -LIBM_DD(lgamma) -#else -LIBM_DD_NO(lgamma) -#endif -#ifdef HAVE_LOG1P -LIBM_DD(log1p) -#else -LIBM_DD_NO(log1p) -#endif -#ifdef HAVE_LOGB -LIBM_DD(logb) -#else -LIBM_DD_NO(logb) -#endif -#ifdef HAVE_MODF -LIBM_DDD(modf) -#else -LIBM_DDD_NO(modf) -#endif -#ifdef HAVE_NEARBYINT -LIBM_DD(nearbyint) -#else -LIBM_DD_NO(nearbyint) -#endif -#ifdef HAVE_NEXTAFTER -LIBM_DDD(nextafter) -#else -LIBM_DDD_NO(nextafter) -#endif -#ifdef HAVE_NEXTTOWARD -LIBM_DDD(nexttoward) -#else -LIBM_DDD_NO(nexttoward) -#endif -#ifdef HAVE_POW10 -LIBM_DD(pow10) -#else -LIBM_DD_NO(pow10) -#endif -#ifdef HAVE_RINT -LIBM_DD(rint) -#else -LIBM_DD_NO(rint) -#endif -#ifdef HAVE_ROUND -LIBM_DD(round) -#else -LIBM_DD_NO(round) -#endif -#ifdef HAVE_SCALB -LIBM_DDD(scalb) -#else -LIBM_DDD_NO(scalb) -#endif -#ifdef HAVE_SCALBLN -LIBM_DDD(scalbln) -#else -LIBM_DDD_NO(scalbln) -#endif -#ifdef HAVE_SIGNIFICAND -LIBM_DD(significand) -#else -LIBM_DD_NO(significand) -#endif -#ifdef HAVE_TRUNC -LIBM_DD(trunc) -#else -LIBM_DD_NO(trunc) -#endif -#ifdef HAVE_LDEXP -LIBM_DDD(ldexp) -#else -LIBM_DDD_NO(ldexp) -#endif diff --git a/src/jq/linker.c b/src/jq/linker.c deleted file mode 100644 index ad869da..0000000 --- a/src/jq/linker.c +++ /dev/null @@ -1,392 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include -#endif - -#include "jq_parser.h" -#include "locfile.h" -#include "jv.h" -#include "jq.h" -#include "parser.h" -#include "util.h" -#include "compile.h" - -struct lib_loading_state { - char **names; - block *defs; - uint64_t ct; -}; -static int load_library(jq_state *jq, jv lib_path, int is_data, int raw, - const char *as, block *out_block, - struct lib_loading_state *lib_state); - -static int path_is_relative(jv p) { - const char *s = jv_string_value(p); - -#ifdef WIN32 - int res = PathIsRelativeA(s); -#else - int res = *s != '/'; -#endif - jv_free(p); - return res; -} - - -// Given a lib_path to search first, creates a chain of search paths -// in the following order: -// 1. lib_path -// 2. -L paths passed in on the command line (from jq_state*) or builtin list -static jv build_lib_search_chain(jq_state *jq, jv search_path, jv jq_origin, jv lib_origin) { - assert(jv_get_kind(search_path) == JV_KIND_ARRAY); - jv expanded = jv_array(); - jv expanded_elt; - jv err = jv_null(); - jv_array_foreach(search_path, i, path) { - if (jv_get_kind(path) != JV_KIND_STRING) { - jv_free(path); - continue; - } - path = expand_path(path); - if (!jv_is_valid(path)) { - err = path; - path = jv_null(); - continue; - } - if (strcmp(".",jv_string_value(path)) == 0) { - expanded_elt = jv_copy(path); - } else if (strncmp("$ORIGIN/",jv_string_value(path),sizeof("$ORIGIN/") - 1) == 0) { - expanded_elt = jv_string_fmt("%s/%s", - jv_string_value(jq_origin), - jv_string_value(path) + sizeof ("$ORIGIN/") - 1); - } else if (jv_get_kind(lib_origin) == JV_KIND_STRING && - path_is_relative(jv_copy(path))) { - expanded_elt = jv_string_fmt("%s/%s", - jv_string_value(lib_origin), - jv_string_value(path)); - } else { - expanded_elt = path; - path = jv_invalid(); - } - expanded = jv_array_append(expanded, expanded_elt); - jv_free(path); - } - jv_free(jq_origin); - jv_free(lib_origin); - jv_free(search_path); - return JV_ARRAY(expanded, err); -} - -// Doesn't actually check that name not be an absolute path, and we -// don't have to: we always append relative paths to others (with a '/' -// in between). -static jv validate_relpath(jv name) { - const char *s = jv_string_value(name); - if (strchr(s, '\\')) { - jv res = jv_invalid_with_msg(jv_string_fmt("Modules must be named by relative paths using '/', not '\\' (%s)", s)); - jv_free(name); - return res; - } - jv components = jv_string_split(jv_copy(name), jv_string("/")); - jv rp = jv_array_get(jv_copy(components), 0); - components = jv_array_slice(components, 1, jv_array_length(jv_copy(components))); - jv_array_foreach(components, i, x) { - if (!strcmp(jv_string_value(x), "..")) { - jv_free(x); - jv_free(rp); - jv_free(components); - jv res = jv_invalid_with_msg(jv_string_fmt("Relative paths to modules may not traverse to parent directories (%s)", s)); - jv_free(name); - return res; - } - if (i > 0 && jv_equal(jv_copy(x), jv_array_get(jv_copy(components), i - 1))) { - jv_free(x); - jv_free(rp); - jv_free(components); - jv res = jv_invalid_with_msg(jv_string_fmt("module names must not have equal consecutive components: %s", - jv_string_value(name))); - jv_free(name); - return res; - } - rp = jv_string_concat(rp, jv_string_concat(jv_string("/"), x)); - } - jv_free(components); - jv_free(name); - return rp; -} - -// Assumes name has been validated -static jv jv_basename(jv name) { - const char *s = jv_string_value(name); - const char *p = strrchr(s, '/'); - if (!p) - return name; - jv res = jv_string_fmt("%s", p); - jv_free(name); - return res; -} - -// 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_get_kind(search) != JV_KIND_ARRAY) - return jv_invalid_with_msg(jv_string_fmt("Module search path must be an array")); - if (jv_get_kind(rel_path) != JV_KIND_STRING) - return jv_invalid_with_msg(jv_string_fmt("Module path must be a string")); - - struct stat st; - int ret; - - // Ideally we should cache this somewhere - search = build_lib_search_chain(jq, search, jq_origin, lib_origin); - jv err = jv_array_get(jv_copy(search), 1); - search = jv_array_get(search, 0); - - jv bname = jv_basename(jv_copy(rel_path)); - - jv_array_foreach(search, i, spath) { - if (jv_get_kind(spath) == JV_KIND_NULL) { - jv_free(spath); - break; - } - if (jv_get_kind(spath) != JV_KIND_STRING || - strcmp(jv_string_value(spath), "") == 0) { - jv_free(spath); - continue; /* XXX report non-strings in search path?? */ - } - // Try ${search_dir}/${rel_path}.jq - jv testpath = jq_realpath(jv_string_fmt("%s/%s%s", - jv_string_value(spath), - jv_string_value(rel_path), - suffix)); - ret = stat(jv_string_value(testpath),&st); - if (ret == -1 && errno == ENOENT) { - jv_free(testpath); - // Try ${search_dir}/$(dirname ${rel_path})/jq/main.jq - testpath = jq_realpath(jv_string_fmt("%s/%s/%s%s", - jv_string_value(spath), - jv_string_value(rel_path), - "jq/main", - suffix)); - ret = stat(jv_string_value(testpath),&st); - } - if (ret == -1 && errno == ENOENT) { - jv_free(testpath); - // Try ${search_dir}/${rel_path}/$(basename ${rel_path}).jq - testpath = jq_realpath(jv_string_fmt("%s/%s/%s%s", - jv_string_value(spath), - jv_string_value(rel_path), - jv_string_value(bname), - suffix)); - ret = stat(jv_string_value(testpath),&st); - } - if (ret == 0) { - jv_free(err); - jv_free(rel_path); - jv_free(search); - jv_free(bname); - jv_free(spath); - return testpath; - } - jv_free(testpath); - jv_free(spath); - } - jv output; - if (!jv_is_valid(err)) { - err = jv_invalid_get_msg(err); - output = jv_invalid_with_msg(jv_string_fmt("module not found: %s (%s)", - jv_string_value(rel_path), - jv_string_value(err))); - } else { - output = jv_invalid_with_msg(jv_string_fmt("module not found: %s", - jv_string_value(rel_path))); - } - jv_free(err); - jv_free(rel_path); - jv_free(search); - jv_free(bname); - return output; -} - -static jv default_search(jq_state *jq, jv value) { - if (!jv_is_valid(value)) { - // dependent didn't say; prepend . to system search path listj - jv_free(value); - return jv_array_concat(JV_ARRAY(jv_string(".")), jq_get_lib_dirs(jq)); - } - if (jv_get_kind(value) != JV_KIND_ARRAY) - return JV_ARRAY(value); - return value; -} - -// XXX Split this into a util that takes a callback, and then... -static int process_dependencies(jq_state *jq, jv jq_origin, jv lib_origin, block *src_block, struct lib_loading_state *lib_state) { - jv deps = block_take_imports(src_block); - block bk = *src_block; - int nerrors = 0; - const char *as_str = NULL; - - jv_array_foreach(deps, i, dep) { - int is_data = jv_get_kind(jv_object_get(jv_copy(dep), jv_string("is_data"))) == JV_KIND_TRUE; - int raw = 0; - jv v = jv_object_get(jv_copy(dep), jv_string("raw")); - if (jv_get_kind(v) == JV_KIND_TRUE) - raw = 1; - jv_free(v); - jv relpath = validate_relpath(jv_object_get(jv_copy(dep), jv_string("relpath"))); - jv as = jv_object_get(jv_copy(dep), jv_string("as")); - assert(!jv_is_valid(as) || jv_get_kind(as) == JV_KIND_STRING); - if (jv_get_kind(as) == JV_KIND_STRING) - as_str = jv_string_value(as); - jv search = default_search(jq, jv_object_get(dep, jv_string("search"))); - // dep is now freed; do not reuse - - // find_lib does a lot of work that could be cached... - jv resolved = find_lib(jq, relpath, search, is_data ? ".json" : ".jq", jv_copy(jq_origin), jv_copy(lib_origin)); - // XXX ...move the rest of this into a callback. - if (!jv_is_valid(resolved)) { - jv emsg = jv_invalid_get_msg(resolved); - jq_report_error(jq, jv_string_fmt("jq: error: %s\n",jv_string_value(emsg))); - jv_free(emsg); - jv_free(as); - jv_free(deps); - jv_free(jq_origin); - jv_free(lib_origin); - return 1; - } - 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) - break; - } - if (state_idx < lib_state->ct) { // 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); - } else { // Not found. Add it to the table before binding. - block dep_def_block = gen_noop(); - nerrors += load_library(jq, resolved, is_data, raw, as_str, &dep_def_block, lib_state); - // resolved has been freed - if (nerrors == 0) { - // Bind the library to the program - bk = block_bind_library(dep_def_block, bk, OP_IS_CALL_PSEUDO, as_str); - } - } - jv_free(as); - } - jv_free(lib_origin); - jv_free(jq_origin); - jv_free(deps); - return nerrors; -} - -// 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, const char *as, block *out_block, struct lib_loading_state *lib_state) { - int nerrors = 0; - struct locfile* src = NULL; - block program; - jv data; - if (is_data && !raw) - data = jv_load_file(jv_string_value(lib_path), 0); - else - data = jv_load_file(jv_string_value(lib_path), 1); - int state_idx; - if (!jv_is_valid(data)) { - if (jv_invalid_has_msg(jv_copy(data))) - data = jv_invalid_get_msg(data); - 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))); - nerrors++; - goto out; - } else if (is_data) { - // import "foo" as $bar; - program = gen_const_global(jv_copy(data), 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); - 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); - } - } - state_idx = lib_state->ct++; - lib_state->names = realloc(lib_state->names, lib_state->ct * sizeof(const char *)); - lib_state->defs = 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 = program; - if (src) - locfile_free(src); -out: - jv_free(lib_path); - jv_free(data); - return nerrors; -} - -// FIXME It'd be nice to have an option to search the same search path -// as we do in process_dependencies. -jv load_module_meta(jq_state *jq, jv mod_relpath) { - // We can't know the caller's origin; we could though, if it was passed in - jv lib_path = find_lib(jq, validate_relpath(mod_relpath), jq_get_lib_dirs(jq), ".jq", jq_get_jq_origin(jq), jv_null()); - if (!jv_is_valid(lib_path)) - return lib_path; - jv meta = jv_null(); - jv data = jv_load_file(jv_string_value(lib_path), 1); - if (jv_is_valid(data)) { - block program; - struct locfile* src = locfile_init(jq, jv_string_value(lib_path), jv_string_value(data), jv_string_length_bytes(jv_copy(data))); - int nerrors = jq_parse_library(src, &program); - if (nerrors == 0) { - meta = block_module_meta(program); - if (jv_get_kind(meta) == JV_KIND_NULL) - meta = jv_object(); - meta = jv_object_set(meta, jv_string("deps"), block_take_imports(&program)); - } - locfile_free(src); - block_free(program); - } - jv_free(lib_path); - jv_free(data); - return meta; -} - -int load_program(jq_state *jq, struct locfile* src, block *out_block) { - int nerrors = 0; - block program; - struct lib_loading_state lib_state = {0,0,0}; - nerrors = jq_parse(src, &program); - if (nerrors) - return nerrors; - - 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]); - } - free(lib_state.names); - free(lib_state.defs); - if (nerrors) - block_free(program); - else - *out_block = block_drop_unreferenced(block_join(libs, program)); - - return nerrors; -} diff --git a/src/jq/linker.h b/src/jq/linker.h deleted file mode 100644 index 3f682ca..0000000 --- a/src/jq/linker.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef LINKER_H -#define LINKER_H - -int load_program(jq_state *jq, struct locfile* src, block *out_block); -jv load_module_meta(jq_state *jq, jv modname); - -#endif diff --git a/src/jq/locfile.c b/src/jq/locfile.c deleted file mode 100644 index 97bb348..0000000 --- a/src/jq/locfile.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "jq.h" -#include "jv_alloc.h" -#include "locfile.h" - - -struct locfile* locfile_init(jq_state *jq, const char *fname, const char* data, int length) { - struct locfile* l = jv_mem_alloc(sizeof(struct locfile)); - l->jq = jq; - l->fname = jv_string(fname); - l->data = jv_mem_alloc(length); - memcpy((char*)l->data,data,length); - l->length = length; - l->nlines = 1; - l->refct = 1; - for (int i=0; inlines++; - } - l->linemap = jv_mem_alloc(sizeof(int) * (l->nlines + 1)); - l->linemap[0] = 0; - int line = 1; - for (int i=0; ilinemap[line] = i+1; // at start of line, not of \n - line++; - } - } - l->linemap[l->nlines] = length+1; // virtual last \n - return l; -} - -struct locfile* locfile_retain(struct locfile* l) { - l->refct++; - return l; -} -void locfile_free(struct locfile* l) { - if (--(l->refct) == 0) { - jv_free(l->fname); - jv_mem_free(l->linemap); - jv_mem_free((char*)l->data); - jv_mem_free(l); - } -} - -int locfile_get_line(struct locfile* l, int pos) { - assert(pos < l->length); - int line = 1; - while (l->linemap[line] <= pos) line++; // == if pos at start (before, never ==, because pos never on \n) - assert(line-1 < l->nlines); - return line-1; -} - -static int locfile_line_length(struct locfile* l, int line) { - assert(line < l->nlines); - return l->linemap[line+1] - l->linemap[line] -1; // -1 to omit \n -} - -void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) { - va_list fmtargs; - va_start(fmtargs, fmt); - int startline; - int offset; - - if (loc.start != -1) { - startline = locfile_get_line(l, loc.start); - offset = l->linemap[startline]; - } - - jv m1 = jv_string_vfmt(fmt, fmtargs); - if (!jv_is_valid(m1)) { - jq_report_error(l->jq, m1); - return; - } - if (loc.start == -1) { - jq_report_error(l->jq, jv_string_fmt("jq: error: %s\n", jv_string_value(m1))); - jv_free(m1); - return; - } - jv m2 = jv_string_fmt("%s at %s, line %d:\n%.*s%*s", jv_string_value(m1), - jv_string_value(l->fname), startline + 1, - locfile_line_length(l, startline), l->data + offset, - loc.start - offset, ""); - jv_free(m1); - jq_report_error(l->jq, m2); - return; -} diff --git a/src/jq/locfile.h b/src/jq/locfile.h deleted file mode 100644 index 9931b00..0000000 --- a/src/jq/locfile.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef LOCFILE_H -#define LOCFILE_H - -#include "jq.h" - -typedef struct { - int start, end; -} location; - -static const location UNKNOWN_LOCATION = {-1, -1}; - -struct locfile { - jv fname; - const char* data; - int length; - int* linemap; - int nlines; - char *error; - jq_state *jq; - int refct; -}; - -struct locfile* locfile_init(jq_state *, const char *, const char *, int); -struct locfile* locfile_retain(struct locfile *); -int locfile_get_line(struct locfile *, int); -void locfile_free(struct locfile *); -void locfile_locate(struct locfile *, location, const char *, ...); - -#endif diff --git a/src/jq/main.c b/src/jq/main.c deleted file mode 100644 index eb542fa..0000000 --- a/src/jq/main.c +++ /dev/null @@ -1,587 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include -#include -#include -#include -#include -#include -#endif - -#if !defined(HAVE_ISATTY) && defined(HAVE__ISATTY) -#undef isatty -#define isatty _isatty -#endif - -#if defined(HAVE_ISATTY) || defined(HAVE__ISATTY) -#define USE_ISATTY -#endif - -#include "compile.h" -#include "jv.h" -#include "jq.h" -#include "jv_alloc.h" -#include "util.h" -#include "src/version.h" - -int jq_testsuite(jv lib_dirs, int verbose, int argc, char* argv[]); - -static const char* progname; - -/* - * For a longer help message we could use a better option parsing - * strategy, one that lets stack options. - */ -static void usage(int code) { - FILE *f = stderr; - - if (code == 0) - f = stdout; - - int ret = fprintf(f, - "jq - commandline JSON processor [version %s]\n" - "\nUsage:\n\n\t%s [options] [file...]\n\n" - "jq is a tool for processing JSON inputs, applying the given filter to\n" - "its JSON text inputs and producing the filter's results as JSON on\n" - "standard output.\n\n" - "The simplest filter is ., which copies jq's input to its output\n" - "unmodified (except for formatting, but note that IEEE754 is used\n" - "for number representation internally, with all that that implies).\n\n" - "For more advanced filters see the jq(1) manpage (\"man jq\")\n" - "and/or https://stedolan.github.io/jq\n\n" - "Example:\n\n\t$ echo '{\"foo\": 0}' | jq .\n" - "\t{\n\t\t\"foo\": 0\n\t}\n\n" - "Some of the options include:\n" - " -c compact instead of pretty-printed output;\n" - " -n use `null` as the single input value;\n" - " -e set the exit status code based on the output;\n" - " -s read (slurp) all inputs into an array; apply filter to it;\n" - " -r output raw strings, not JSON texts;\n" - " -R read raw strings, not JSON texts;\n" - " -C colorize JSON;\n" - " -M monochrome (don't colorize JSON);\n" - " -S sort keys of objects on output;\n" - " --tab use tabs for indentation;\n" - " --arg a v set variable $a to value ;\n" - " --argjson a v set variable $a to JSON value ;\n" - " --slurpfile a f set variable $a to an array of JSON texts read from ;\n" - "\nSee the manpage for more options.\n", JQ_VERSION, progname); - exit((ret < 0 && code == 0) ? 2 : code); -} - -static void die() { - fprintf(stderr, "Use %s --help for help with command-line options,\n", progname); - fprintf(stderr, "or see the jq manpage, or online docs at https://stedolan.github.io/jq\n"); - exit(2); -} - - - - -static int isoptish(const char* text) { - return text[0] == '-' && (text[1] == '-' || isalpha(text[1])); -} - -static int isoption(const char* text, char shortopt, const char* longopt, size_t *short_opts) { - if (text[0] != '-' || text[1] == '-') - *short_opts = 0; - if (text[0] != '-') return 0; - - // check long option - if (text[1] == '-' && !strcmp(text+2, longopt)) return 1; - else if (text[1] == '-') return 0; - - // must be short option; check it and... - if (!shortopt) return 0; - if (strchr(text, shortopt) != NULL) { - (*short_opts)++; // ...count it (for option stacking) - return 1; - } - return 0; -} - -enum { - SLURP = 1, - RAW_INPUT = 2, - PROVIDE_NULL = 4, - RAW_OUTPUT = 8, - 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, - SEQ = 8192, - RUN_TESTS = 16384, - /* debugging only */ - DUMP_DISASM = 32768, -}; -static int options = 0; - -static const char *skip_shebang(const char *p) { - if (strncmp(p, "#!", sizeof("#!") - 1) != 0) - return p; - const char *n = strchr(p, '\n'); - if (n == NULL || n[1] != '#') - return p; - n = strchr(n + 1, '\n'); - if (n == NULL || n[1] == '#' || n[1] == '\0' || n[-1] != '\\' || n[-2] == '\\') - return p; - n = strchr(n + 1, '\n'); - if (n == NULL) - return p; - return n+1; -} - -static int process(jq_state *jq, jv value, int flags, int dumpopts) { - int ret = 14; // No valid results && -e -> exit(4) - jq_start(jq, value, flags); - jv result; - while (jv_is_valid(result = jq_next(jq))) { - if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) { - fwrite(jv_string_value(result), 1, jv_string_length_bytes(jv_copy(result)), stdout); - ret = 0; - jv_free(result); - } else { - if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND_NULL) - ret = 11; - else - ret = 0; - if (options & SEQ) - priv_fwrite("\036", 1, stdout, dumpopts & JV_PRINT_ISATTY); - jv_dump(result, dumpopts); - } - if (!(options & RAW_NO_LF)) - priv_fwrite("\n", 1, stdout, dumpopts & JV_PRINT_ISATTY); - if (options & UNBUFFERED_OUTPUT) - fflush(stdout); - } - if (jv_invalid_has_msg(jv_copy(result))) { - // Uncaught jq exception - jv msg = jv_invalid_get_msg(jv_copy(result)); - jv input_pos = jq_util_input_get_position(jq); - if (jv_get_kind(msg) == JV_KIND_STRING) { - fprintf(stderr, "jq: error (at %s): %s\n", - jv_string_value(input_pos), jv_string_value(msg)); - } else { - msg = jv_dump_string(msg, 0); - fprintf(stderr, "jq: error (at %s) (not a string): %s\n", - jv_string_value(input_pos), jv_string_value(msg)); - } - ret = 5; - jv_free(input_pos); - jv_free(msg); - } - jv_free(result); - return ret; -} - -static void debug_cb(void *data, jv input) { - int dumpopts = *(int *)data; - jv_dumpf(JV_ARRAY(jv_string("DEBUG:"), input), stderr, dumpopts & ~(JV_PRINT_PRETTY)); - fprintf(stderr, "\n"); -} - -int main(int argc, char* argv[]) { - jq_state *jq = NULL; - int ret = 0; - int compiled = 0; - int parser_flags = 0; - int nfiles = 0; - int badwrite; - jv program_arguments = jv_array(); - -#ifdef WIN32 - SetConsoleOutputCP(CP_UTF8); - fflush(stdout); - fflush(stderr); - _setmode(fileno(stdout), _O_TEXT | _O_U8TEXT); - _setmode(fileno(stderr), _O_TEXT | _O_U8TEXT); - int wargc; - wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); - assert(wargc == argc); - size_t arg_sz; - for (int i = 0; i < argc; i++) { - argv[i] = alloca((arg_sz = WideCharToMultiByte(CP_UTF8, - 0, - wargv[i], - -1, 0, 0, 0, 0))); - WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], arg_sz, 0, 0); - } -#endif - - if (argc) progname = argv[0]; - - jq = jq_init(); - if (jq == NULL) { - perror("malloc"); - ret = 2; - goto out; - } - - int dumpopts = JV_PRINT_INDENT_FLAGS(2); - const char* program = 0; - - jq_util_input_state *input_state = jq_util_input_init(NULL, NULL); // XXX add err_cb - - int further_args_are_files = 0; - int jq_flags = 0; - size_t short_opts = 0; - jv lib_search_paths = jv_null(); - for (int i=1; i= argc - 1) { - fprintf(stderr, "-L takes a parameter: (e.g. -L /search/path or -L/search/path)\n"); - die(); - } else { - lib_search_paths = jv_array_append(lib_search_paths, jq_realpath(jv_string(argv[i+1]))); - i++; - } - continue; - } - - if (isoption(argv[i], 's', "slurp", &short_opts)) { - options |= SLURP; - if (!short_opts) continue; - } - if (isoption(argv[i], 'r', "raw-output", &short_opts)) { - options |= RAW_OUTPUT; - if (!short_opts) continue; - } - if (isoption(argv[i], 'c', "compact-output", &short_opts)) { - dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); - if (!short_opts) continue; - } - if (isoption(argv[i], 'C', "color-output", &short_opts)) { - options |= COLOR_OUTPUT; - if (!short_opts) continue; - } - if (isoption(argv[i], 'M', "monochrome-output", &short_opts)) { - options |= NO_COLOR_OUTPUT; - if (!short_opts) continue; - } - if (isoption(argv[i], 'a', "ascii-output", &short_opts)) { - options |= ASCII_OUTPUT; - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "unbuffered", &short_opts)) { - options |= UNBUFFERED_OUTPUT; - if (!short_opts) continue; - } - if (isoption(argv[i], 'S', "sort-keys", &short_opts)) { - options |= SORTED_OUTPUT; - if (!short_opts) continue; - } - if (isoption(argv[i], 'R', "raw-input", &short_opts)) { - options |= RAW_INPUT; - if (!short_opts) continue; - } - if (isoption(argv[i], 'n', "null-input", &short_opts)) { - options |= PROVIDE_NULL; - if (!short_opts) continue; - } - if (isoption(argv[i], 'f', "from-file", &short_opts)) { - options |= FROM_FILE; - if (!short_opts) continue; - } - if (isoption(argv[i], 'j', "join-output", &short_opts)) { - options |= RAW_OUTPUT | RAW_NO_LF; - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "tab", &short_opts)) { - dumpopts &= ~JV_PRINT_INDENT_FLAGS(7); - dumpopts |= JV_PRINT_TAB | JV_PRINT_PRETTY; - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "indent", &short_opts)) { - if (i >= argc - 1) { - fprintf(stderr, "%s: --indent takes one parameter\n", progname); - die(); - } - dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); - int indent = atoi(argv[i+1]); - if (indent < -1 || indent > 7) { - fprintf(stderr, "%s: --indent takes a number between -1 and 7\n", progname); - die(); - } - dumpopts |= JV_PRINT_INDENT_FLAGS(indent); - i++; - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "seq", &short_opts)) { - options |= SEQ; - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "stream", &short_opts)) { - parser_flags |= JV_PARSE_STREAMING; - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "stream-errors", &short_opts)) { - parser_flags |= JV_PARSE_STREAM_ERRORS; - if (!short_opts) continue; - } - if (isoption(argv[i], 'e', "exit-status", &short_opts)) { - options |= EXIT_STATUS; - if (!short_opts) continue; - } - // FIXME: For --arg* we should check that the varname is acceptable - if (isoption(argv[i], 0, "arg", &short_opts)) { - if (i >= argc - 2) { - fprintf(stderr, "%s: --arg takes two parameters (e.g. --arg varname value)\n", progname); - die(); - } - jv arg = jv_object(); - arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1])); - arg = jv_object_set(arg, jv_string("value"), jv_string(argv[i+2])); - program_arguments = jv_array_append(program_arguments, arg); - i += 2; // skip the next two arguments - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "argjson", &short_opts)) { - if (i >= argc - 2) { - fprintf(stderr, "%s: --argjson takes two parameters (e.g. --argjson varname text)\n", progname); - die(); - } - jv v = jv_parse(argv[i+2]); - if (!jv_is_valid(v)) { - fprintf(stderr, "%s: invalid JSON text passed to --argjson\n", progname); - die(); - } - jv arg = jv_object(); - arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1])); - arg = jv_object_set(arg, jv_string("value"), v); - program_arguments = jv_array_append(program_arguments, arg); - i += 2; // skip the next two arguments - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "argfile", &short_opts) || - isoption(argv[i], 0, "slurpfile", &short_opts)) { - const char *which; - if (isoption(argv[i], 0, "argfile", &short_opts)) - which = "argfile"; - else - which = "slurpfile"; - if (i >= argc - 2) { - fprintf(stderr, "%s: --%s takes two parameters (e.g. --%s varname filename)\n", progname, which, which); - die(); - } - jv arg = jv_object(); - arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1])); - jv data = jv_load_file(argv[i+2], 0); - if (!jv_is_valid(data)) { - data = jv_invalid_get_msg(data); - fprintf(stderr, "%s: Bad JSON in --%s %s %s: %s\n", progname, which, - argv[i+1], argv[i+2], jv_string_value(data)); - jv_free(data); - jv_free(arg); - ret = 2; - goto out; - } - if (isoption(argv[i], 0, "argfile", &short_opts) && - jv_get_kind(data) == JV_KIND_ARRAY && jv_array_length(jv_copy(data)) == 1) - data = jv_array_get(data, 0); - arg = jv_object_set(arg, jv_string("value"), data); - program_arguments = jv_array_append(program_arguments, arg); - i += 2; // skip the next two arguments - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "debug-dump-disasm", &short_opts)) { - options |= DUMP_DISASM; - if (!short_opts) continue; - } - if (isoption(argv[i], 0, "debug-trace", &short_opts)) { - jq_flags |= JQ_DEBUG_TRACE; - if (!short_opts) continue; - } - if (isoption(argv[i], 'h', "help", &short_opts)) { - usage(0); - if (!short_opts) continue; - } - if (isoption(argv[i], 'V', "version", &short_opts)) { - printf("jq-%s\n", JQ_VERSION); - ret = 0; - goto out; - } - if (isoption(argv[i], 0, "run-tests", &short_opts)) { - i++; - // XXX Pass program_arguments, even a whole jq_state *, through; - // could be useful for testing - ret = jq_testsuite(lib_search_paths, - (options & DUMP_DISASM) || (jq_flags & JQ_DEBUG_TRACE), - argc - i, argv + i); - goto out; - } - - // check for unknown options... if this argument was a short option - if (strlen(argv[i]) != short_opts + 1) { - fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]); - die(); - } - } - } - -#ifdef USE_ISATTY - if (isatty(STDOUT_FILENO)) { - dumpopts |= JV_PRINT_ISATTY; -#ifndef WIN32 - /* Disable color by default on Windows builds as Windows - terminals tend not to display it correctly */ - dumpopts |= JV_PRINT_COLOR; -#endif - } -#endif - if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED; - if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII; - if (options & COLOR_OUTPUT) dumpopts |= JV_PRINT_COLOR; - if (options & NO_COLOR_OUTPUT) dumpopts &= ~JV_PRINT_COLOR; - - if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) { - // Default search path list - lib_search_paths = JV_ARRAY(jv_string("~/.jq"), - jv_string("$ORIGIN/../lib/jq"), - jv_string("$ORIGIN/lib")); - } - jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_search_paths); - - char *origin = strdup(argv[0]); - if (origin == NULL) { - fprintf(stderr, "Error: out of memory\n"); - exit(1); - } - jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string(dirname(origin))); - free(origin); - - if (strchr(JQ_VERSION, '-') == NULL) - jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string(JQ_VERSION)); - else - jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string_fmt("%.*s-master", (int)(strchr(JQ_VERSION, '-') - JQ_VERSION), JQ_VERSION)); - -#ifdef USE_ISATTY - if (!program && (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO))) - program = "."; -#endif - - if (!program) usage(2); - - if (options & FROM_FILE) { - char *program_origin = strdup(program); - if (program_origin == NULL) { - perror("malloc"); - exit(2); - } - - jv data = jv_load_file(program, 1); - if (!jv_is_valid(data)) { - data = jv_invalid_get_msg(data); - fprintf(stderr, "%s: %s\n", progname, jv_string_value(data)); - jv_free(data); - ret = 2; - goto out; - } - jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(program_origin)))); - compiled = jq_compile_args(jq, skip_shebang(jv_string_value(data)), jv_copy(program_arguments)); - free(program_origin); - jv_free(data); - } else { - jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string("."))); // XXX is this good? - compiled = jq_compile_args(jq, program, jv_copy(program_arguments)); - } - if (!compiled){ - ret = 3; - goto out; - } - - if (options & DUMP_DISASM) { - jq_dump_disassembly(jq, 0); - printf("\n"); - } - - if ((options & SEQ)) - parser_flags |= JV_PARSE_SEQ; - - if ((options & RAW_INPUT)) - jq_util_input_set_parser(input_state, NULL, (options & SLURP) ? 1 : 0); - else - jq_util_input_set_parser(input_state, jv_parser_new(parser_flags), (options & SLURP) ? 1 : 0); - - // Let jq program read from inputs - jq_set_input_cb(jq, jq_util_input_next_input_cb, input_state); - - // Let jq program call `debug` builtin and have that go somewhere - jq_set_debug_cb(jq, debug_cb, &dumpopts); - - if (nfiles == 0) - jq_util_input_add_input(input_state, "-"); - - if (options & PROVIDE_NULL) { - ret = process(jq, jv_null(), jq_flags, dumpopts); - } else { - jv value; - while (jq_util_input_errors(input_state) == 0 && - (jv_is_valid((value = jq_util_input_next_input(input_state))) || jv_invalid_has_msg(jv_copy(value)))) { - if (jv_is_valid(value)) { - ret = process(jq, value, jq_flags, dumpopts); - continue; - } - - // Parse error - jv msg = jv_invalid_get_msg(value); - if (!(options & SEQ)) { - // --seq -> errors are not fatal - ret = 4; - fprintf(stderr, "parse error: %s\n", jv_string_value(msg)); - jv_free(msg); - break; - } - fprintf(stderr, "ignoring parse error: %s\n", jv_string_value(msg)); - jv_free(msg); - } - } - - if (jq_util_input_errors(input_state) != 0) - ret = 2; - -out: - badwrite = ferror(stdout); - if (fclose(stdout)!=0 || badwrite) { - fprintf(stderr,"Error: writing output failed: %s\n", strerror(errno)); - ret = 2; - } - - jv_free(program_arguments); - jq_util_input_free(&input_state); - jq_teardown(&jq); - if (ret >= 10 && (options & EXIT_STATUS)) - return ret - 10; - if (ret >= 10) - return 0; - return ret; -} diff --git a/src/jq/opcode_list.h b/src/jq/opcode_list.h deleted file mode 100644 index e38d684..0000000 --- a/src/jq/opcode_list.h +++ /dev/null @@ -1,44 +0,0 @@ -OP(LOADK, CONSTANT, 1, 1) -OP(DUP, NONE, 1, 2) -OP(DUPN, NONE, 1, 2) -OP(DUP2, NONE, 2, 3) -OP(POP, NONE, 1, 0) -OP(LOADV, VARIABLE, 1, 1) -OP(LOADVN, VARIABLE, 1, 1) -OP(STOREV, VARIABLE, 1, 0) -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(FORK, BRANCH, 0, 0) -OP(FORK_OPT, BRANCH, 0, 0) -OP(JUMP, BRANCH, 0, 0) -OP(JUMP_F,BRANCH, 1, 0) -OP(BACKTRACK, NONE, 0, 0) -OP(APPEND, VARIABLE,1, 0) -OP(INSERT, NONE, 4, 2) -OP(RANGE, VARIABLE, 1, 1) - -OP(SUBEXP_BEGIN, NONE, 1, 2) -OP(SUBEXP_END, NONE, 2, 2) - -OP(PATH_BEGIN, NONE, 1, 2) -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(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) -OP(CLOSURE_PARAM_REGULAR, DEFINITION, 0, 0) -OP(DEPS, CONSTANT, 0, 0) -OP(MODULEMETA, CONSTANT, 0, 0) -OP(GENLABEL, NONE, 0, 1) diff --git a/src/jq/parser.c b/src/jq/parser.c deleted file mode 100644 index 80de873..0000000 --- a/src/jq/parser.c +++ /dev/null @@ -1,3915 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "3.0.2" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 1 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - - - -/* Copy the first part of user declarations. */ -#line 1 "src/parser.y" /* yacc.c:339 */ - -#include -#include -#include -#include -#include "compile.h" -#include "jv_alloc.h" -#define YYMALLOC jv_mem_alloc -#define YYFREE jv_mem_free - -#line 77 "src/parser.c" /* yacc.c:339 */ - -# ifndef YY_NULLPTR -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULLPTR nullptr -# else -# define YY_NULLPTR 0 -# endif -# endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 1 -#endif - -/* In a future release of Bison, this section will be replaced - by #include "y.tab.h". */ -#ifndef YY_YY_SRC_PARSER_H_INCLUDED -# define YY_YY_SRC_PARSER_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif -/* "%code requires" blocks. */ -#line 11 "src/parser.y" /* yacc.c:355 */ - -#include "locfile.h" -struct lexer_param; - -#define YYLTYPE location -#define YYLLOC_DEFAULT(Loc, Rhs, N) \ - do { \ - if (N) { \ - (Loc).start = YYRHSLOC(Rhs, 1).start; \ - (Loc).end = YYRHSLOC(Rhs, N).end; \ - } else { \ - (Loc).start = YYRHSLOC(Rhs, 0).end; \ - (Loc).end = YYRHSLOC(Rhs, 0).end; \ - } \ - } while (0) - -#line 124 "src/parser.c" /* yacc.c:355 */ - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - INVALID_CHARACTER = 258, - IDENT = 259, - FIELD = 260, - LITERAL = 261, - FORMAT = 262, - REC = 263, - SETMOD = 264, - EQ = 265, - NEQ = 266, - 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, - QQSTRING_START = 295, - QQSTRING_TEXT = 296, - QQSTRING_INTERP_START = 297, - QQSTRING_INTERP_END = 298, - QQSTRING_END = 299, - FUNCDEF = 300, - NONOPT = 301 - }; -#endif -/* Tokens. */ -#define INVALID_CHARACTER 258 -#define IDENT 259 -#define FIELD 260 -#define LITERAL 261 -#define FORMAT 262 -#define REC 263 -#define SETMOD 264 -#define EQ 265 -#define NEQ 266 -#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 QQSTRING_START 295 -#define QQSTRING_TEXT 296 -#define QQSTRING_INTERP_START 297 -#define QQSTRING_INTERP_END 298 -#define QQSTRING_END 299 -#define FUNCDEF 300 -#define NONOPT 301 - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; -union YYSTYPE -{ -#line 31 "src/parser.y" /* yacc.c:355 */ - - jv literal; - block blk; - -#line 233 "src/parser.c" /* yacc.c:355 */ -}; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - -/* Location type. */ -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE YYLTYPE; -struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -}; -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif - - - -int yyparse (block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr); - -#endif /* !YY_YY_SRC_PARSER_H_INCLUDED */ - -/* Copy the second part of user declarations. */ -#line 123 "src/parser.y" /* yacc.c:358 */ - -#include "lexer.h" -struct lexer_param { - yyscan_t lexer; -}; -#define FAIL(loc, msg) \ - do { \ - location l = loc; \ - yyerror(&l, answer, errors, locations, lexer_param_ptr, msg); \ - /*YYERROR*/; \ - } while (0) - -void yyerror(YYLTYPE* loc, block* answer, int* errors, - struct locfile* locations, struct lexer_param* lexer_param_ptr, const char *s){ - (*errors)++; - if (strstr(s, "unexpected")) { -#ifdef WIN32 - locfile_locate(locations, *loc, "jq: error: %s (Windows cmd shell quoting issues?)", s); -#else - locfile_locate(locations, *loc, "jq: error: %s (Unix shell quoting issues?)", s); -#endif - } else { - locfile_locate(locations, *loc, "jq: error: %s", s); - } -} - -int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors, - struct locfile* locations, struct lexer_param* lexer_param_ptr) { - yyscan_t lexer = lexer_param_ptr->lexer; - int tok = jq_yylex(yylval, yylloc, lexer); - if ((tok == LITERAL || tok == QQSTRING_TEXT) && !jv_is_valid(yylval->literal)) { - jv msg = jv_invalid_get_msg(jv_copy(yylval->literal)); - if (jv_get_kind(msg) == JV_KIND_STRING) { - FAIL(*yylloc, jv_string_value(msg)); - } else { - FAIL(*yylloc, "Invalid literal"); - } - jv_free(msg); - jv_free(yylval->literal); - yylval->literal = jv_null(); - } - return tok; -} - -/* Returns string message if the block is a constant that is not valid as an - * object key. */ -static jv check_object_key(block k) { - if (block_is_const(k) && block_const_kind(k) != JV_KIND_STRING) { - char errbuf[15]; - return jv_string_fmt("Cannot use %s (%s) as object key", - jv_kind_name(block_const_kind(k)), - jv_dump_string_trunc(jv_copy(block_const(k)), errbuf, sizeof(errbuf))); - } - return jv_invalid(); -} - -static block gen_dictpair(block k, block v) { - return BLOCK(gen_subexp(k), gen_subexp(v), gen_op_simple(INSERT)); -} - -static block gen_index(block obj, block key) { - return BLOCK(gen_subexp(key), obj, gen_op_simple(INDEX)); -} - -static block gen_index_opt(block obj, block key) { - return BLOCK(gen_subexp(key), obj, gen_op_simple(INDEX_OPT)); -} - -static block gen_slice_index(block obj, block start, block end, opcode idx_op) { - block key = BLOCK(gen_subexp(gen_const(jv_object())), - gen_subexp(gen_const(jv_string("start"))), - gen_subexp(start), - gen_op_simple(INSERT), - gen_subexp(gen_const(jv_string("end"))), - gen_subexp(end), - gen_op_simple(INSERT)); - return BLOCK(key, obj, gen_op_simple(idx_op)); -} - -static block constant_fold(block a, block b, int op) { - if (!block_is_single(a) || !block_is_const(a) || - !block_is_single(b) || !block_is_const(b)) - return gen_noop(); - if (op == '+') { - if (block_const_kind(a) == JV_KIND_NULL) { - block_free(a); - return b; - } - if (block_const_kind(b) == JV_KIND_NULL) { - block_free(b); - return a; - } - } - if (block_const_kind(a) != block_const_kind(b)) - return gen_noop(); - - jv res = jv_invalid(); - - if (block_const_kind(a) == JV_KIND_NUMBER) { - double na = jv_number_value(block_const(a)); - double nb = jv_number_value(block_const(b)); - switch (op) { - case '+': res = jv_number(na + nb); break; - case '-': res = jv_number(na - nb); break; - case '*': res = jv_number(na * nb); break; - case '/': res = jv_number(na / nb); break; - case EQ: res = (na == nb ? jv_true() : jv_false()); break; - case NEQ: res = (na != nb ? jv_true() : jv_false()); break; - case '<': res = (na < nb ? jv_true() : jv_false()); break; - case '>': res = (na > nb ? jv_true() : jv_false()); break; - case LESSEQ: res = (na <= nb ? jv_true() : jv_false()); break; - case GREATEREQ: res = (na >= nb ? jv_true() : jv_false()); break; - default: break; - } - } else if (op == '+' && block_const_kind(a) == JV_KIND_STRING) { - res = jv_string_concat(block_const(a), block_const(b)); - } else { - return gen_noop(); - } - - if (jv_get_kind(res) == JV_KIND_INVALID) - return gen_noop(); - - block_free(a); - block_free(b); - return gen_const(res); -} - -static block gen_binop(block a, block b, int op) { - block folded = constant_fold(a, b, op); - if (!block_is_noop(folded)) - return folded; - - const char* funcname = 0; - switch (op) { - case '+': funcname = "_plus"; break; - case '-': funcname = "_minus"; break; - case '*': funcname = "_multiply"; break; - case '/': funcname = "_divide"; break; - case '%': funcname = "_mod"; break; - case EQ: funcname = "_equal"; break; - case NEQ: funcname = "_notequal"; break; - case '<': funcname = "_less"; break; - case '>': funcname = "_greater"; break; - case LESSEQ: funcname = "_lesseq"; break; - case GREATEREQ: funcname = "_greatereq"; break; - } - assert(funcname); - - return gen_call(funcname, BLOCK(gen_lambda(a), gen_lambda(b))); -} - -static block gen_format(block a, jv fmt) { - return BLOCK(a, gen_call("format", gen_lambda(gen_const(fmt)))); -} - -static block gen_definedor_assign(block object, block val) { - block tmp = gen_op_var_fresh(STOREV, "tmp"); - return BLOCK(gen_op_simple(DUP), - val, tmp, - gen_call("_modify", BLOCK(gen_lambda(object), - gen_lambda(gen_definedor(gen_noop(), - gen_op_bound(LOADV, tmp)))))); -} - -static block gen_update(block object, block val, int optype) { - block tmp = gen_op_var_fresh(STOREV, "tmp"); - return BLOCK(gen_op_simple(DUP), - val, - tmp, - gen_call("_modify", BLOCK(gen_lambda(object), - gen_lambda(gen_binop(gen_noop(), - gen_op_bound(LOADV, tmp), - optype))))); -} - - -#line 438 "src/parser.c" /* yacc.c:358 */ - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#else -typedef signed char yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) -# endif -# endif -# ifndef YY_ -# define YY_(Msgid) Msgid -# 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) -# else -# define YY_ATTRIBUTE(Spec) /* empty */ -# 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__)) -#endif - -#if !defined _Noreturn \ - && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) -# if defined _MSC_VER && 1200 <= _MSC_VER -# define _Noreturn __declspec (noreturn) -# else -# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) -#else -# define YYUSE(E) /* empty */ -#endif - -#if defined __GNUC__ && 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\"")\ - _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ - _Pragma ("GCC diagnostic pop") -#else -# define YY_INITIAL_VALUE(Value) Value -#endif -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's 'empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ - && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 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) - -/* 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)) \ - + 2 * YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (0) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 27 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 1871 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 68 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 28 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 157 -/* YYNSTATES -- Number of states. */ -#define YYNSTATES 307 - -/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned - by yylex, with out-of-bounds checking. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 301 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, without out-of-bounds checking. */ -static const yytype_uint8 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, 61, 55, 2, 2, - 59, 60, 53, 51, 47, 52, 63, 54, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 62, 58, - 49, 48, 50, 57, 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, 64, 2, 65, 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, 66, 46, 67, 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, 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, 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, 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, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 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, 56 -}; - -#if YYDEBUG - /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 303, 303, 306, 311, 314, 325, 328, 333, 336, - 341, 345, 349, 353, 357, 361, 364, 369, 373, 377, - 382, 389, 393, 397, 401, 405, 409, 413, 417, 421, - 425, 429, 433, 437, 441, 445, 449, 453, 459, 465, - 469, 473, 477, 481, 485, 489, 493, 497, 502, 505, - 522, 531, 538, 546, 557, 562, 568, 571, 576, 581, - 588, 588, 592, 592, 599, 602, 605, 611, 614, 619, - 622, 625, 631, 634, 637, 645, 649, 652, 655, 658, - 661, 664, 667, 670, 673, 677, 683, 686, 689, 692, - 695, 698, 701, 704, 707, 710, 713, 716, 719, 722, - 725, 728, 731, 738, 742, 746, 758, 763, 764, 765, - 766, 769, 772, 777, 782, 786, 789, 794, 797, 802, - 805, 810, 813, 816, 819, 822, 830, 836, 839, 842, - 845, 848, 851, 854, 857, 860, 863, 866, 869, 872, - 875, 878, 881, 884, 887, 890, 895, 898, 899, 900, - 903, 906, 909, 912, 916, 920, 924, 932 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || 1 -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -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", "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[] = -{ - 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, 124, 44, 61, 60, - 62, 43, 45, 42, 47, 37, 301, 63, 59, 40, - 41, 36, 58, 46, 91, 93, 123, 125 -}; -# endif - -#define YYPACT_NINF -155 - -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-155))) - -#define YYTABLE_NINF -147 - -#define yytable_value_is_error(Yytable_value) \ - (!!((Yytable_value) == (-147))) - - /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -static const yytype_int16 yypact[] = -{ - 20, 709, 42, 50, 14, -3, -155, 7, -155, 58, - 709, 191, 191, 709, 18, 2, -155, 709, 465, 19, - 275, 438, 340, 1215, 709, -155, 6, -155, -2, -2, - 709, 50, 619, 709, -155, -155, 9, 1564, 17, 46, - 54, 111, -155, 116, -155, 3, 62, 1050, -155, -155, - -155, 122, 7, 68, 66, -155, 851, -26, 72, -155, - -155, -155, -155, -155, -155, -155, -155, -155, -155, -155, - -155, -155, -155, -155, -155, -155, -155, -155, 709, 131, - 74, 75, 71, 92, 709, 709, 709, 709, 709, 709, - 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, - 709, 709, 709, 709, 709, 709, 709, 709, -155, -155, - 1728, 84, -21, -2, 148, 130, -155, -155, -155, 1728, - 709, -155, -155, 1265, 1728, -5, -155, -155, 0, 709, - 529, -21, -21, 556, 98, -155, 34, -155, -155, -155, - -155, -155, -155, 396, 689, -155, 689, 1083, -155, 689, - 689, -155, 396, 1794, 335, 335, 1761, 768, 1814, 1794, - 1794, 1794, 1794, 1794, 1794, 335, 335, 1728, 1761, 1794, - 335, 335, 3, 3, 90, 90, 90, -155, 146, -21, - 770, 105, 101, 94, 709, 103, 802, 11, -155, -155, - 709, -155, 70, -155, 157, 61, -155, 1315, -155, 1515, - 104, 106, -155, -155, 709, -155, 709, -155, -10, -155, - 689, 121, 1, 121, 107, 121, 121, -155, -155, -155, - -19, 110, 112, 709, 164, 114, -23, -155, 117, 709, - -155, -155, 900, -155, 646, 123, -155, 169, -155, -155, - -155, 0, 119, -155, 709, 709, -155, 709, 709, 1728, - 1597, -155, 689, 689, -21, -155, -21, -21, 1116, -155, - -21, 770, -155, -21, 1728, 125, 127, 949, -155, -155, - -155, 709, 1646, 1695, 1365, 1415, -155, 121, 121, -155, - -155, -155, 124, -155, -155, -155, -155, -155, 133, 1465, - -155, 709, 709, 709, -21, -155, -155, 1515, 1149, 998, - -155, -155, -155, 709, -155, 1182, -155 -}; - - /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 4, 0, 0, 6, 105, 81, 96, 98, 73, 0, - 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, - 0, 0, 0, 0, 0, 97, 47, 1, 0, 0, - 8, 6, 0, 0, 77, 62, 0, 0, 0, 0, - 18, 0, 75, 0, 64, 32, 0, 0, 104, 103, - 84, 0, 0, 83, 0, 101, 0, 0, 155, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 0, 0, - 153, 0, 0, 147, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 21, 5, - 10, 80, 0, 0, 0, 0, 53, 52, 3, 2, - 8, 7, 48, 0, 113, 0, 111, 64, 0, 0, - 0, 0, 0, 0, 0, 74, 0, 107, 99, 85, - 79, 108, 100, 0, 0, 110, 0, 0, 154, 0, - 0, 102, 0, 40, 41, 42, 25, 24, 23, 27, - 31, 34, 36, 39, 26, 45, 46, 28, 29, 22, - 43, 44, 30, 33, 35, 37, 38, 76, 0, 0, - 0, 0, 82, 0, 0, 89, 0, 0, 9, 49, - 0, 106, 0, 59, 0, 0, 56, 0, 16, 0, - 0, 0, 19, 17, 0, 65, 0, 61, 0, 149, - 0, 157, 71, 150, 0, 152, 151, 148, 114, 117, - 0, 0, 0, 0, 0, 0, 0, 119, 0, 0, - 78, 109, 0, 88, 0, 87, 51, 0, 112, 63, - 58, 0, 0, 54, 0, 0, 15, 0, 0, 20, - 0, 70, 0, 0, 0, 115, 0, 0, 0, 121, - 0, 0, 116, 0, 11, 95, 94, 0, 86, 50, - 57, 0, 0, 0, 0, 0, 66, 69, 156, 118, - 126, 122, 0, 124, 120, 123, 92, 91, 93, 0, - 68, 0, 0, 0, 0, 90, 55, 0, 0, 0, - 125, 67, 12, 0, 14, 0, 13 -}; - - /* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -155, -155, -155, 156, 73, -1, -155, -155, 162, -12, - -155, -49, 5, -155, -155, 67, -96, -136, -4, -155, - 12, -130, -155, -155, -57, -154, -104, -155 -}; - - /* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 2, 3, 30, 118, 110, 31, 32, 115, 24, - 195, 196, 25, 44, 127, 136, 246, 211, 26, 125, - 126, 181, 220, 226, 227, 81, 82, 83 -}; - - /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_int16 yytable[] = -{ - 23, 200, 201, 42, 193, 52, 111, 38, 39, 37, - 213, 111, 40, 215, 216, 236, 45, 47, 120, 112, - 56, 143, 111, 48, 261, 53, 228, 80, 254, 119, - 131, 123, 124, 116, 116, 1, 144, 143, 16, 209, - 178, 145, 27, 179, 262, 180, 255, 35, 217, 219, - 49, 111, 144, 190, 34, 191, 105, 106, 107, 132, - 108, 194, 36, 43, 113, 114, 28, 29, 128, 113, - 114, 129, 237, 33, 251, 205, 206, 147, 207, 41, - 113, 114, 133, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 228, 120, 113, - 114, 205, 206, 186, 239, 134, 277, 278, 182, 241, - 135, 242, 137, 139, 279, 140, 280, 281, 197, 199, - 283, 141, 203, 285, 146, 148, 149, 150, 151, 152, - 212, 177, 212, 187, 204, 212, 212, 108, 80, 183, - 218, 229, 4, 5, 6, 7, 8, 80, 230, 231, - 233, 240, 9, 247, 300, 248, 10, 252, 259, 253, - 11, 12, 256, 269, 257, 13, 260, 14, 15, 263, - 268, 271, 286, 232, 287, 225, 294, 121, 16, 124, - 295, 117, 270, 188, 192, 4, 5, 6, 7, 8, - 17, 301, 238, 249, 284, 250, 212, 18, 0, 19, - 184, 20, 21, 185, 22, 0, 0, 0, 0, 0, - 0, 15, 258, 0, 0, 0, 0, 0, 264, 0, - 0, 16, 0, 267, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 272, 273, 0, 274, 275, 212, 212, - 18, 0, 19, 0, 20, 21, 0, 22, 0, 0, - 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, - 289, 0, 0, 0, 0, -72, 50, 0, 0, 51, - -72, 0, 52, 0, -72, -72, -72, -72, -72, 0, - 297, 298, 299, 0, -72, -72, -72, 0, 0, -72, - -72, -72, 305, -72, 0, 0, 0, -72, -72, -72, - -72, -72, -72, -72, -72, 16, 0, 0, -72, 0, - 0, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, 0, -72, -72, 0, -72, 0, -72, -72, -72, - -72, 57, -72, 0, 58, -147, -147, 52, 0, 0, - 0, 0, 0, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 0, -147, -147, 0, 0, 0, 0, 0, - 16, 0, 0, 0, -147, -147, 103, 104, 105, 106, - 107, 0, 108, 0, 0, 0, 0, 208, 0, 78, - 58, 79, 0, 52, 0, 0, 0, -146, 0, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 0, 0, - 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, - 0, 0, 4, 5, 6, 7, 8, 0, 0, 0, - 0, 0, 9, 0, 0, 78, 10, 79, 0, 0, - 11, 12, 0, -146, 0, 13, 46, 14, 15, 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, 55, 22, 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, - 198, 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, 202, 14, 15, - 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, 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, 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, - 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, 122, 18, 0, - 19, 0, 20, 21, 0, 22, 16, 0, 0, 0, - 0, 0, 0, 4, 5, 6, 7, 8, 17, 0, - 0, 0, 0, 0, 0, 18, 0, 19, 0, 20, - 21, 266, 22, 4, 5, 6, 7, 8, 0, 15, - 0, 0, 0, 9, 0, 0, 0, 10, 0, 16, - 0, 11, 12, 0, 0, 0, 13, 0, 14, 15, - 0, 210, 0, 0, 0, 0, 0, 0, 18, 16, - 19, 0, 20, 21, 0, 22, 0, 0, 0, 0, - 0, 17, 0, 0, 0, 0, 0, 0, 18, 0, - 19, 221, 20, 21, 222, 22, 0, 52, 85, 86, - 0, 0, 0, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 0, 0, 0, 0, 96, 97, 0, 0, - 16, 84, 85, 86, 87, 0, 0, 101, 102, 103, - 104, 105, 106, 107, 0, 108, 0, 88, 89, 223, - 0, 224, 0, 0, 90, 91, 92, 93, 94, 95, - 96, 97, 0, 0, 0, 0, 0, 0, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 0, 108, - 84, 85, 86, 87, 234, 0, 0, 235, 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, 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, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 0, 108, 84, 85, - 86, 87, 0, 0, 0, 265, 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, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 0, 108, 84, 85, 86, - 87, 0, 0, 0, 288, 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, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 0, 108, 303, 0, 304, 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, 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, 84, 85, 86, 87, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 0, - 108, 88, 89, 214, 0, 0, 0, 0, 90, 91, - 92, 93, 94, 95, 96, 97, 0, 0, 84, 85, - 86, 87, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 0, 108, 88, 89, 282, 0, 0, 0, - 0, 90, 91, 92, 93, 94, 95, 96, 97, 0, - 0, 84, 85, 86, 87, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 0, 108, 88, 89, 302, - 0, 0, 0, 0, 90, 91, 92, 93, 94, 95, - 96, 97, 0, 0, 84, 85, 86, 87, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 0, 108, - 88, 89, 306, 0, 0, 0, 0, 90, 91, 92, - 93, 94, 95, 96, 97, 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, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 189, 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, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 243, 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, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 292, 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, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 293, 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, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 0, 108, 296, 84, 85, 86, 87, 0, 0, - 0, 0, 0, 0, 0, 244, 245, 0, 0, 0, - 88, 89, 0, 0, 0, 0, 0, 90, 91, 92, - 93, 94, 95, 96, 97, 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, 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, - 276, 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, 0, 0, 0, 0, - 290, 88, 89, 0, 0, 0, 0, 0, 90, 91, - 92, 93, 94, 95, 96, 97, 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, 291, 0, 0, 0, 0, 0, - 88, 89, 0, 0, 0, 0, 0, 90, 91, 92, - 93, 94, 95, 96, 97, 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, - 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, -147, 85, 86, 0, 0, 0, 100, - 101, 102, 103, 104, 105, 106, 107, 0, 108, 88, - 89, 0, 0, 0, 85, 86, -147, -147, -147, -147, - -147, -147, 96, 97, 0, 0, 0, 0, 0, 88, - 0, 0, -147, 101, 102, 103, 104, 105, 106, 107, - 0, 108, 96, 97, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 101, 102, 103, 104, 105, 106, 107, - 0, 108 -}; - -static const yytype_int16 yycheck[] = -{ - 1, 131, 132, 1, 4, 7, 5, 11, 12, 10, - 146, 5, 13, 149, 150, 4, 17, 18, 30, 13, - 21, 47, 5, 4, 47, 20, 180, 22, 47, 30, - 13, 32, 33, 28, 29, 15, 62, 47, 40, 143, - 61, 67, 0, 64, 67, 66, 65, 40, 152, 179, - 31, 5, 62, 58, 57, 60, 53, 54, 55, 13, - 57, 61, 4, 61, 63, 64, 16, 17, 59, 63, - 64, 62, 61, 59, 210, 41, 42, 78, 44, 61, - 63, 64, 28, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 261, 120, 63, - 64, 41, 42, 114, 44, 4, 252, 253, 113, 58, - 4, 60, 60, 1, 254, 57, 256, 257, 129, 130, - 260, 65, 133, 263, 62, 4, 62, 62, 67, 47, - 144, 57, 146, 13, 46, 149, 150, 57, 143, 1, - 4, 46, 4, 5, 6, 7, 8, 152, 57, 65, - 57, 4, 14, 59, 294, 59, 18, 46, 4, 62, - 22, 23, 62, 4, 62, 27, 62, 29, 30, 62, - 57, 62, 57, 184, 57, 180, 62, 31, 40, 190, - 57, 29, 241, 120, 127, 4, 5, 6, 7, 8, - 52, 297, 190, 204, 261, 206, 210, 59, -1, 61, - 62, 63, 64, 65, 66, -1, -1, -1, -1, -1, - -1, 30, 223, -1, -1, -1, -1, -1, 229, -1, - -1, 40, -1, 234, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 244, 245, -1, 247, 248, 252, 253, - 59, -1, 61, -1, 63, 64, -1, 66, -1, -1, - -1, -1, -1, -1, -1, -1, 261, -1, -1, -1, - 271, -1, -1, -1, -1, 0, 1, -1, -1, 4, - 5, -1, 7, -1, 9, 10, 11, 12, 13, -1, - 291, 292, 293, -1, 19, 20, 21, -1, -1, 24, - 25, 26, 303, 28, -1, -1, -1, 32, 33, 34, - 35, 36, 37, 38, 39, 40, -1, -1, 43, -1, - -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 58, -1, 60, -1, 62, 63, 64, - 65, 1, 67, -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, - 40, -1, -1, -1, 49, 50, 51, 52, 53, 54, - 55, -1, 57, -1, -1, -1, -1, 1, -1, 59, - 4, 61, -1, 7, -1, -1, -1, 67, -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, 40, -1, -1, 1, - -1, -1, 4, 5, 6, 7, 8, -1, -1, -1, - -1, -1, 14, -1, -1, 59, 18, 61, -1, -1, - 22, 23, -1, 67, -1, 27, 1, 29, 30, 4, - 5, 6, 7, 8, -1, -1, -1, -1, 40, 14, - -1, -1, -1, 18, -1, -1, -1, 22, 23, -1, - 52, -1, 27, -1, 29, 30, -1, 59, -1, 61, - -1, 63, 64, 65, 66, 40, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 52, -1, -1, - -1, -1, -1, -1, 59, -1, 61, -1, 63, 64, - 1, 66, -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, - 4, 5, 6, 7, 8, -1, -1, -1, -1, 40, - 14, -1, -1, -1, 18, -1, -1, -1, 22, 23, - -1, 52, -1, 27, -1, 29, 30, -1, 59, -1, - 61, -1, 63, 64, -1, 66, 40, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 52, -1, - -1, -1, -1, -1, -1, 59, -1, 61, -1, 63, - 64, -1, 66, 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, - 4, 5, 6, 7, 8, -1, -1, -1, -1, 40, - 14, -1, -1, -1, 18, -1, -1, -1, 22, 23, - -1, 52, -1, 27, -1, 29, 30, 58, 59, -1, - 61, -1, 63, 64, -1, 66, 40, -1, -1, -1, - -1, -1, -1, 4, 5, 6, 7, 8, 52, -1, - -1, -1, -1, -1, -1, 59, -1, 61, -1, 63, - 64, 65, 66, 4, 5, 6, 7, 8, -1, 30, - -1, -1, -1, 14, -1, -1, -1, 18, -1, 40, - -1, 22, 23, -1, -1, -1, 27, -1, 29, 30, - -1, 52, -1, -1, -1, -1, -1, -1, 59, 40, - 61, -1, 63, 64, -1, 66, -1, -1, -1, -1, - -1, 52, -1, -1, -1, -1, -1, -1, 59, -1, - 61, 1, 63, 64, 4, 66, -1, 7, 10, 11, - -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, 38, 39, -1, -1, - 40, 9, 10, 11, 12, -1, -1, 49, 50, 51, - 52, 53, 54, 55, -1, 57, -1, 25, 26, 59, - -1, 61, -1, -1, 32, 33, 34, 35, 36, 37, - 38, 39, -1, -1, -1, -1, -1, -1, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, - 9, 10, 11, 12, 62, -1, -1, 65, -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, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, -1, 57, 9, - 10, 11, 12, -1, -1, -1, 65, -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, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, -1, 57, 9, 10, - 11, 12, -1, -1, -1, 65, -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, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, -1, 57, 9, 10, 11, - 12, -1, -1, -1, 65, -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, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, -1, 57, 58, -1, 60, 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, 9, 10, 11, 12, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, -1, 57, 25, 26, - 60, -1, -1, -1, -1, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, 9, 10, 11, 12, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, - 57, 25, 26, 60, -1, -1, -1, -1, 32, 33, - 34, 35, 36, 37, 38, 39, -1, -1, 9, 10, - 11, 12, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, -1, 57, 25, 26, 60, -1, -1, -1, - -1, 32, 33, 34, 35, 36, 37, 38, 39, -1, - -1, 9, 10, 11, 12, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, -1, 57, 25, 26, 60, - -1, -1, -1, -1, 32, 33, 34, 35, 36, 37, - 38, 39, -1, -1, 9, 10, 11, 12, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, - 25, 26, 60, -1, -1, -1, -1, 32, 33, 34, - 35, 36, 37, 38, 39, -1, -1, -1, -1, -1, - -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 58, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 58, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 58, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 58, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 58, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 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, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 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, 9, 10, 11, 12, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - -1, 57, 25, 26, -1, -1, -1, -1, -1, 32, - 33, 34, 35, 36, 37, 38, 39, -1, -1, -1, - 43, -1, -1, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, -1, 57, 9, 10, 11, 12, -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, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, -1, 57, 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, 9, 10, 11, - 12, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, -1, 57, 25, 26, -1, -1, -1, -1, -1, - 32, 33, 34, 35, 36, 37, 38, 39, -1, -1, - 9, 10, 11, 12, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, -1, 57, 25, 26, -1, -1, - -1, -1, -1, 32, 33, 34, 35, 36, 37, 38, - 39, -1, -1, 9, 10, 11, -1, -1, -1, 48, - 49, 50, 51, 52, 53, 54, 55, -1, 57, 25, - 26, -1, -1, -1, 10, 11, 32, 33, 34, 35, - 36, 37, 38, 39, -1, -1, -1, -1, -1, 25, - -1, -1, 48, 49, 50, 51, 52, 53, 54, 55, - -1, 57, 38, 39, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 49, 50, 51, 52, 53, 54, 55, - -1, 57 -}; - - /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 15, 69, 70, 4, 5, 6, 7, 8, 14, - 18, 22, 23, 27, 29, 30, 40, 52, 59, 61, - 63, 64, 66, 73, 77, 80, 86, 0, 16, 17, - 71, 74, 75, 59, 57, 40, 4, 73, 86, 86, - 73, 61, 1, 61, 81, 73, 1, 73, 4, 31, - 1, 4, 7, 80, 1, 65, 73, 1, 4, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 59, 61, - 80, 93, 94, 95, 9, 10, 11, 12, 25, 26, - 32, 33, 34, 35, 36, 37, 38, 39, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 57, 58, - 73, 5, 13, 63, 64, 76, 80, 76, 72, 73, - 77, 71, 58, 73, 73, 87, 88, 82, 59, 62, - 19, 13, 13, 28, 4, 4, 83, 60, 60, 1, - 57, 65, 65, 47, 62, 67, 62, 73, 4, 62, - 62, 67, 47, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 57, 61, 64, - 66, 89, 80, 1, 62, 65, 73, 13, 72, 58, - 58, 60, 83, 4, 61, 78, 79, 73, 1, 73, - 89, 89, 1, 73, 46, 41, 42, 44, 1, 94, - 52, 85, 86, 85, 60, 85, 85, 94, 4, 89, - 90, 1, 4, 59, 61, 80, 91, 92, 93, 46, - 57, 65, 73, 57, 62, 65, 4, 61, 88, 44, - 4, 58, 60, 58, 20, 21, 84, 59, 59, 73, - 73, 85, 46, 62, 47, 65, 62, 62, 73, 4, - 62, 47, 67, 62, 73, 65, 65, 73, 57, 4, - 79, 62, 73, 73, 73, 73, 43, 85, 85, 89, - 89, 89, 60, 89, 92, 89, 57, 57, 65, 73, - 24, 19, 58, 58, 62, 57, 58, 73, 73, 73, - 89, 84, 60, 58, 60, 73, 60 -}; - - /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 68, 69, 69, 70, 70, 71, 71, 72, 72, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, - 75, 75, 75, 76, 77, 77, 78, 78, 79, 79, - 81, 80, 82, 80, 83, 83, 83, 84, 84, 85, - 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 87, 87, 88, 89, 89, 89, 90, 90, 91, - 91, 92, 92, 92, 92, 92, 92, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 94, 94, 94, 94, - 95, 95, 95, 95, 95, 95, 95, 95 -}; - - /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 3, 3, 0, 3, 0, 2, 0, 2, - 2, 5, 9, 11, 9, 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, 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, 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, 2, 3, 3, 1, 3, 1, - 3, 2, 3, 3, 3, 5, 3, 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, 2, 1, 5, 3 -}; - - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (&yylloc, answer, errors, locations, lexer_param_ptr, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (0) - -/* Error token number */ -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (N) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (0) -#endif - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL - -/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ - -YY_ATTRIBUTE_UNUSED -static unsigned -yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) -{ - unsigned res = 0; - int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; - if (0 <= yylocp->first_line) - { - res += YYFPRINTF (yyo, "%d", yylocp->first_line); - if (0 <= yylocp->first_column) - res += YYFPRINTF (yyo, ".%d", yylocp->first_column); - } - if (0 <= yylocp->last_line) - { - if (yylocp->first_line < yylocp->last_line) - { - res += YYFPRINTF (yyo, "-%d", yylocp->last_line); - if (0 <= end_col) - res += YYFPRINTF (yyo, ".%d", end_col); - } - else if (0 <= end_col && yylocp->first_column < end_col) - res += YYFPRINTF (yyo, "-%d", end_col); - } - return res; - } - -# define YY_LOCATION_PRINT(File, Loc) \ - yy_location_print_ (File, &(Loc)) - -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, Location, answer, errors, locations, lexer_param_ptr); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - - -/*----------------------------------------. -| Print this symbol's value on YYOUTPUT. | -`----------------------------------------*/ - -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) -{ - FILE *yyo = yyoutput; - YYUSE (yyo); - YYUSE (yylocationp); - YYUSE (answer); - YYUSE (errors); - YYUSE (locations); - YYUSE (lexer_param_ptr); - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - YYUSE (yytype); -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) -{ - YYFPRINTF (yyoutput, "%s %s (", - yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); - - YY_LOCATION_PRINT (yyoutput, *yylocationp); - YYFPRINTF (yyoutput, ": "); - yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, answer, errors, locations, lexer_param_ptr); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -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) -{ - unsigned long int yylno = yyrline[yyrule]; - int yynrhs = yyr2[yyrule]; - int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, - yystos[yyssp[yyi + 1 - yynrhs]], - &(yyvsp[(yyi + 1) - (yynrhs)]) - , &(yylsp[(yyi + 1) - (yynrhs)]) , answer, errors, locations, lexer_param_ptr); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyssp, yyvsp, yylsp, Rule, answer, errors, locations, lexer_param_ptr); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -yystrlen (const char *yystr) -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -yystpcpy (char *yydest, const char *yysrc) -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - 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 -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *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) -{ - 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. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } - } - - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } - - { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } - - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; -} -#endif /* YYERROR_VERBOSE */ - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) -{ - YYUSE (yyvaluep); - YYUSE (yylocationp); - YYUSE (answer); - YYUSE (errors); - YYUSE (locations); - YYUSE (lexer_param_ptr); - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - switch (yytype) - { - case 4: /* IDENT */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1866 "src/parser.c" /* yacc.c:1257 */ - break; - - case 5: /* FIELD */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1872 "src/parser.c" /* yacc.c:1257 */ - break; - - case 6: /* LITERAL */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1878 "src/parser.c" /* yacc.c:1257 */ - break; - - case 7: /* FORMAT */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1884 "src/parser.c" /* yacc.c:1257 */ - break; - - case 41: /* QQSTRING_TEXT */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 1890 "src/parser.c" /* yacc.c:1257 */ - break; - - case 70: /* Module */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1896 "src/parser.c" /* yacc.c:1257 */ - break; - - case 71: /* Imports */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1902 "src/parser.c" /* yacc.c:1257 */ - break; - - case 72: /* FuncDefs */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1908 "src/parser.c" /* yacc.c:1257 */ - break; - - case 73: /* Exp */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1914 "src/parser.c" /* yacc.c:1257 */ - break; - - case 74: /* Import */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1920 "src/parser.c" /* yacc.c:1257 */ - break; - - case 75: /* ImportWhat */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1926 "src/parser.c" /* yacc.c:1257 */ - break; - - case 76: /* ImportFrom */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1932 "src/parser.c" /* yacc.c:1257 */ - break; - - case 77: /* FuncDef */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1938 "src/parser.c" /* yacc.c:1257 */ - break; - - case 78: /* Params */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1944 "src/parser.c" /* yacc.c:1257 */ - break; - - case 79: /* Param */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1950 "src/parser.c" /* yacc.c:1257 */ - break; - - case 80: /* String */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1956 "src/parser.c" /* yacc.c:1257 */ - break; - - case 83: /* QQString */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1962 "src/parser.c" /* yacc.c:1257 */ - break; - - case 84: /* ElseBody */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1968 "src/parser.c" /* yacc.c:1257 */ - break; - - case 85: /* ExpD */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1974 "src/parser.c" /* yacc.c:1257 */ - break; - - case 86: /* Term */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1980 "src/parser.c" /* yacc.c:1257 */ - break; - - case 87: /* Args */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1986 "src/parser.c" /* yacc.c:1257 */ - break; - - case 88: /* Arg */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1992 "src/parser.c" /* yacc.c:1257 */ - break; - - case 89: /* Pattern */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 1998 "src/parser.c" /* yacc.c:1257 */ - break; - - case 90: /* ArrayPats */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2004 "src/parser.c" /* yacc.c:1257 */ - break; - - case 91: /* ObjPats */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2010 "src/parser.c" /* yacc.c:1257 */ - break; - - case 92: /* ObjPat */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2016 "src/parser.c" /* yacc.c:1257 */ - break; - - case 93: /* Keyword */ -#line 36 "src/parser.y" /* yacc.c:1257 */ - { jv_free(((*yyvaluep).literal)); } -#line 2022 "src/parser.c" /* yacc.c:1257 */ - break; - - case 94: /* MkDict */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2028 "src/parser.c" /* yacc.c:1257 */ - break; - - case 95: /* MkDictPair */ -#line 37 "src/parser.y" /* yacc.c:1257 */ - { block_free(((*yyvaluep).blk)); } -#line 2034 "src/parser.c" /* yacc.c:1257 */ - break; - - - default: - break; - } - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - - - -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr) -{ -/* The lookahead symbol. */ -int yychar; - - -/* The semantic value of the lookahead symbol. */ -/* Default value used for initialization, for pacifying older GCCs - or non-GCC compilers. */ -YY_INITIAL_VALUE (static YYSTYPE yyval_default;) -YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); - -/* Location data for the lookahead symbol. */ -static YYLTYPE yyloc_default -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL - = { 1, 1, 1, 1 } -# endif -; -YYLTYPE yylloc = yyloc_default; - - /* Number of syntax errors so far. */ - int yynerrs; - - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - 'yyss': related to states. - 'yyvs': related to semantic values. - 'yyls': related to locations. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls; - YYLTYPE *yylsp; - - /* The locations where the error started and ended. */ - YYLTYPE yyerror_range[3]; - - YYSIZE_T yystacksize; - - int yyn; - int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - YYLTYPE yyloc; - -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - yylsp = yyls = yylsa; - yystacksize = YYINITDEPTH; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - yylsp[0] = yylloc; - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef 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. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - YYLTYPE *yyls1 = yyls; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - 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), - &yystacksize); - - yyls = yyls1; - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); - YYSTACK_RELOCATE (yyls_alloc, yyls); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - yylsp = yyls + yysize - 1; - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = yylex (&yylval, &yylloc, answer, errors, locations, lexer_param_ptr); - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* 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; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - '$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - /* Default location. */ - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 303 "src/parser.y" /* yacc.c:1646 */ - { - *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), gen_op_simple(TOP), (yyvsp[0].blk)); -} -#line 2330 "src/parser.c" /* yacc.c:1646 */ - break; - - case 3: -#line 306 "src/parser.y" /* yacc.c:1646 */ - { - *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); -} -#line 2338 "src/parser.c" /* yacc.c:1646 */ - break; - - case 4: -#line 311 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_noop(); -} -#line 2346 "src/parser.c" /* yacc.c:1646 */ - break; - - case 5: -#line 314 "src/parser.y" /* yacc.c:1646 */ - { - if (!block_is_const((yyvsp[-1].blk))) { - FAIL((yyloc), "Module metadata must be constant"); - (yyval.blk) = gen_noop(); - block_free((yyvsp[-1].blk)); - } else { - (yyval.blk) = gen_module((yyvsp[-1].blk)); - } -} -#line 2360 "src/parser.c" /* yacc.c:1646 */ - break; - - case 6: -#line 325 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_noop(); -} -#line 2368 "src/parser.c" /* yacc.c:1646 */ - break; - - case 7: -#line 328 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[-1].blk), (yyvsp[0].blk)); -} -#line 2376 "src/parser.c" /* yacc.c:1646 */ - break; - - case 8: -#line 333 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_noop(); -} -#line 2384 "src/parser.c" /* yacc.c:1646 */ - break; - - case 9: -#line 336 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = block_bind((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO); -} -#line 2392 "src/parser.c" /* yacc.c:1646 */ - break; - - case 10: -#line 341 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = block_bind_referenced((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO); -} -#line 2400 "src/parser.c" /* yacc.c:1646 */ - break; - - case 11: -#line 345 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_destructure((yyvsp[-4].blk), (yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2408 "src/parser.c" /* yacc.c:1646 */ - break; - - case 12: -#line 349 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_reduce((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); -} -#line 2416 "src/parser.c" /* yacc.c:1646 */ - break; - - case 13: -#line 353 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_foreach((yyvsp[-9].blk), (yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); -} -#line 2424 "src/parser.c" /* yacc.c:1646 */ - break; - - case 14: -#line 357 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_foreach((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); -} -#line 2432 "src/parser.c" /* yacc.c:1646 */ - break; - - case 15: -#line 361 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); -} -#line 2440 "src/parser.c" /* yacc.c:1646 */ - break; - - case 16: -#line 364 "src/parser.y" /* yacc.c:1646 */ - { - FAIL((yyloc), "Possibly unterminated 'if' statement"); - (yyval.blk) = (yyvsp[-2].blk); -} -#line 2449 "src/parser.c" /* yacc.c:1646 */ - break; - - case 17: -#line 369 "src/parser.y" /* yacc.c:1646 */ - { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, $4); - (yyval.blk) = gen_try((yyvsp[-2].blk), gen_try_handler((yyvsp[0].blk))); -} -#line 2458 "src/parser.c" /* yacc.c:1646 */ - break; - - case 18: -#line 373 "src/parser.y" /* yacc.c:1646 */ - { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, gen_op_simple(BACKTRACK)); - (yyval.blk) = gen_try((yyvsp[0].blk), gen_op_simple(BACKTRACK)); -} -#line 2467 "src/parser.c" /* yacc.c:1646 */ - break; - - case 19: -#line 377 "src/parser.y" /* yacc.c:1646 */ - { - FAIL((yyloc), "Possibly unterminated 'try' statement"); - (yyval.blk) = (yyvsp[-2].blk); -} -#line 2476 "src/parser.c" /* yacc.c:1646 */ - break; - - case 20: -#line 382 "src/parser.y" /* yacc.c:1646 */ - { - 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 2487 "src/parser.c" /* yacc.c:1646 */ - break; - - case 21: -#line 389 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_try((yyvsp[-1].blk), gen_op_simple(BACKTRACK)); -} -#line 2495 "src/parser.c" /* yacc.c:1646 */ - break; - - case 22: -#line 393 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_call("_assign", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); -} -#line 2503 "src/parser.c" /* yacc.c:1646 */ - break; - - case 23: -#line 397 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_or((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2511 "src/parser.c" /* yacc.c:1646 */ - break; - - case 24: -#line 401 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_and((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2519 "src/parser.c" /* yacc.c:1646 */ - break; - - case 25: -#line 405 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_definedor((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2527 "src/parser.c" /* yacc.c:1646 */ - break; - - case 26: -#line 409 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_definedor_assign((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2535 "src/parser.c" /* yacc.c:1646 */ - break; - - case 27: -#line 413 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_call("_modify", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); -} -#line 2543 "src/parser.c" /* yacc.c:1646 */ - break; - - case 28: -#line 417 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2551 "src/parser.c" /* yacc.c:1646 */ - break; - - case 29: -#line 421 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_both((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2559 "src/parser.c" /* yacc.c:1646 */ - break; - - case 30: -#line 425 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '+'); -} -#line 2567 "src/parser.c" /* yacc.c:1646 */ - break; - - case 31: -#line 429 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '+'); -} -#line 2575 "src/parser.c" /* yacc.c:1646 */ - break; - - case 32: -#line 433 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); -} -#line 2583 "src/parser.c" /* yacc.c:1646 */ - break; - - case 33: -#line 437 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '-'); -} -#line 2591 "src/parser.c" /* yacc.c:1646 */ - break; - - case 34: -#line 441 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '-'); -} -#line 2599 "src/parser.c" /* yacc.c:1646 */ - break; - - case 35: -#line 445 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '*'); -} -#line 2607 "src/parser.c" /* yacc.c:1646 */ - break; - - case 36: -#line 449 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '*'); -} -#line 2615 "src/parser.c" /* yacc.c:1646 */ - break; - - case 37: -#line 453 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '/'); - if (block_is_const_inf((yyval.blk))) - FAIL((yyloc), "Division by zero?"); -} -#line 2625 "src/parser.c" /* yacc.c:1646 */ - break; - - case 38: -#line 459 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '%'); - if (block_is_const_inf((yyval.blk))) - FAIL((yyloc), "Remainder by zero?"); -} -#line 2635 "src/parser.c" /* yacc.c:1646 */ - break; - - case 39: -#line 465 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '/'); -} -#line 2643 "src/parser.c" /* yacc.c:1646 */ - break; - - case 40: -#line 469 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '%'); -} -#line 2651 "src/parser.c" /* yacc.c:1646 */ - break; - - case 41: -#line 473 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), EQ); -} -#line 2659 "src/parser.c" /* yacc.c:1646 */ - break; - - case 42: -#line 477 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), NEQ); -} -#line 2667 "src/parser.c" /* yacc.c:1646 */ - break; - - case 43: -#line 481 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '<'); -} -#line 2675 "src/parser.c" /* yacc.c:1646 */ - break; - - case 44: -#line 485 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '>'); -} -#line 2683 "src/parser.c" /* yacc.c:1646 */ - break; - - case 45: -#line 489 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), LESSEQ); -} -#line 2691 "src/parser.c" /* yacc.c:1646 */ - break; - - case 46: -#line 493 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), GREATEREQ); -} -#line 2699 "src/parser.c" /* yacc.c:1646 */ - break; - - case 47: -#line 497 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 2707 "src/parser.c" /* yacc.c:1646 */ - break; - - case 48: -#line 502 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[-1].blk); -} -#line 2715 "src/parser.c" /* yacc.c:1646 */ - break; - - case 49: -#line 505 "src/parser.y" /* yacc.c:1646 */ - { - if (!block_is_const((yyvsp[-1].blk))) { - FAIL((yyloc), "Module metadata must be constant"); - (yyval.blk) = gen_noop(); - block_free((yyvsp[-2].blk)); - block_free((yyvsp[-1].blk)); - } else if (block_const_kind((yyvsp[-1].blk)) != JV_KIND_OBJECT) { - FAIL((yyloc), "Module metadata must be an object"); - (yyval.blk) = gen_noop(); - block_free((yyvsp[-2].blk)); - block_free((yyvsp[-1].blk)); - } else { - (yyval.blk) = gen_import_meta((yyvsp[-2].blk), (yyvsp[-1].blk)); - } -} -#line 2735 "src/parser.c" /* yacc.c:1646 */ - break; - - case 50: -#line 522 "src/parser.y" /* yacc.c:1646 */ - { - 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 - (yyval.blk) = gen_import(jv_string_value(v), jv_string_value((yyvsp[0].literal)), 1); - block_free((yyvsp[-3].blk)); - jv_free((yyvsp[0].literal)); - jv_free(v); -} -#line 2749 "src/parser.c" /* yacc.c:1646 */ - break; - - case 51: -#line 531 "src/parser.y" /* yacc.c:1646 */ - { - 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 2761 "src/parser.c" /* yacc.c:1646 */ - break; - - case 52: -#line 538 "src/parser.y" /* yacc.c:1646 */ - { - 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 2772 "src/parser.c" /* yacc.c:1646 */ - break; - - case 53: -#line 546 "src/parser.y" /* yacc.c:1646 */ - { - if (!block_is_const((yyvsp[0].blk))) { - FAIL((yyloc), "Import path must be constant"); - (yyval.blk) = gen_const(jv_string("")); - block_free((yyvsp[0].blk)); - } else { - (yyval.blk) = (yyvsp[0].blk); - } -} -#line 2786 "src/parser.c" /* yacc.c:1646 */ - break; - - case 54: -#line 557 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_function(jv_string_value((yyvsp[-3].literal)), gen_noop(), (yyvsp[-1].blk)); - jv_free((yyvsp[-3].literal)); -} -#line 2795 "src/parser.c" /* yacc.c:1646 */ - break; - - case 55: -#line 562 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_function(jv_string_value((yyvsp[-6].literal)), (yyvsp[-4].blk), (yyvsp[-1].blk)); - jv_free((yyvsp[-6].literal)); -} -#line 2804 "src/parser.c" /* yacc.c:1646 */ - break; - - case 56: -#line 568 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 2812 "src/parser.c" /* yacc.c:1646 */ - break; - - case 57: -#line 571 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2820 "src/parser.c" /* yacc.c:1646 */ - break; - - case 58: -#line 576 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_param_regular(jv_string_value((yyvsp[0].literal))); - jv_free((yyvsp[0].literal)); -} -#line 2829 "src/parser.c" /* yacc.c:1646 */ - break; - - case 59: -#line 581 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_param(jv_string_value((yyvsp[0].literal))); - jv_free((yyvsp[0].literal)); -} -#line 2838 "src/parser.c" /* yacc.c:1646 */ - break; - - case 60: -#line 588 "src/parser.y" /* yacc.c:1646 */ - { (yyval.literal) = jv_string("text"); } -#line 2844 "src/parser.c" /* yacc.c:1646 */ - break; - - case 61: -#line 588 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[-1].blk); - jv_free((yyvsp[-2].literal)); -} -#line 2853 "src/parser.c" /* yacc.c:1646 */ - break; - - case 62: -#line 592 "src/parser.y" /* yacc.c:1646 */ - { (yyval.literal) = (yyvsp[-1].literal); } -#line 2859 "src/parser.c" /* yacc.c:1646 */ - break; - - case 63: -#line 592 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[-1].blk); - jv_free((yyvsp[-2].literal)); -} -#line 2868 "src/parser.c" /* yacc.c:1646 */ - break; - - case 64: -#line 599 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_const(jv_string("")); -} -#line 2876 "src/parser.c" /* yacc.c:1646 */ - break; - - case 65: -#line 602 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-1].blk), gen_const((yyvsp[0].literal)), '+'); -} -#line 2884 "src/parser.c" /* yacc.c:1646 */ - break; - - case 66: -#line 605 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_binop((yyvsp[-3].blk), gen_format((yyvsp[-1].blk), jv_copy((yyvsp[-4].literal))), '+'); -} -#line 2892 "src/parser.c" /* yacc.c:1646 */ - break; - - case 67: -#line 611 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); -} -#line 2900 "src/parser.c" /* yacc.c:1646 */ - break; - - case 68: -#line 614 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[-1].blk); -} -#line 2908 "src/parser.c" /* yacc.c:1646 */ - break; - - case 69: -#line 619 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2916 "src/parser.c" /* yacc.c:1646 */ - break; - - case 70: -#line 622 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); -} -#line 2924 "src/parser.c" /* yacc.c:1646 */ - break; - - case 71: -#line 625 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 2932 "src/parser.c" /* yacc.c:1646 */ - break; - - case 72: -#line 631 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_noop(); -} -#line 2940 "src/parser.c" /* yacc.c:1646 */ - break; - - case 73: -#line 634 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_call("recurse", gen_noop()); -} -#line 2948 "src/parser.c" /* yacc.c:1646 */ - break; - - case 74: -#line 637 "src/parser.y" /* yacc.c:1646 */ - { - 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)), - gen_call("error", gen_noop()))); - jv_free(v); - jv_free((yyvsp[0].literal)); -} -#line 2961 "src/parser.c" /* yacc.c:1646 */ - break; - - case 75: -#line 645 "src/parser.y" /* yacc.c:1646 */ - { - FAIL((yyloc), "break requires a label to break to"); - (yyval.blk) = gen_noop(); -} -#line 2970 "src/parser.c" /* yacc.c:1646 */ - break; - - case 76: -#line 649 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index_opt((yyvsp[-2].blk), gen_const((yyvsp[-1].literal))); -} -#line 2978 "src/parser.c" /* yacc.c:1646 */ - break; - - case 77: -#line 652 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index_opt(gen_noop(), gen_const((yyvsp[-1].literal))); -} -#line 2986 "src/parser.c" /* yacc.c:1646 */ - break; - - case 78: -#line 655 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index_opt((yyvsp[-3].blk), (yyvsp[-1].blk)); -} -#line 2994 "src/parser.c" /* yacc.c:1646 */ - break; - - case 79: -#line 658 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index_opt(gen_noop(), (yyvsp[-1].blk)); -} -#line 3002 "src/parser.c" /* yacc.c:1646 */ - break; - - case 80: -#line 661 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index((yyvsp[-1].blk), gen_const((yyvsp[0].literal))); -} -#line 3010 "src/parser.c" /* yacc.c:1646 */ - break; - - case 81: -#line 664 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index(gen_noop(), gen_const((yyvsp[0].literal))); -} -#line 3018 "src/parser.c" /* yacc.c:1646 */ - break; - - case 82: -#line 667 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 3026 "src/parser.c" /* yacc.c:1646 */ - break; - - case 83: -#line 670 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index(gen_noop(), (yyvsp[0].blk)); -} -#line 3034 "src/parser.c" /* yacc.c:1646 */ - break; - - case 84: -#line 673 "src/parser.y" /* yacc.c:1646 */ - { - FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); - (yyval.blk) = gen_noop(); -} -#line 3043 "src/parser.c" /* yacc.c:1646 */ - break; - - case 85: -#line 677 "src/parser.y" /* yacc.c:1646 */ - { - jv_free((yyvsp[-1].literal)); - FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); - (yyval.blk) = gen_noop(); -} -#line 3053 "src/parser.c" /* yacc.c:1646 */ - break; - - case 86: -#line 683 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index_opt((yyvsp[-4].blk), (yyvsp[-2].blk)); -} -#line 3061 "src/parser.c" /* yacc.c:1646 */ - break; - - case 87: -#line 686 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_index((yyvsp[-3].blk), (yyvsp[-1].blk)); -} -#line 3069 "src/parser.c" /* yacc.c:1646 */ - break; - - case 88: -#line 689 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH_OPT)); -} -#line 3077 "src/parser.c" /* yacc.c:1646 */ - break; - - case 89: -#line 692 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = block_join((yyvsp[-2].blk), gen_op_simple(EACH)); -} -#line 3085 "src/parser.c" /* yacc.c:1646 */ - break; - - case 90: -#line 695 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_slice_index((yyvsp[-6].blk), (yyvsp[-4].blk), (yyvsp[-2].blk), INDEX_OPT); -} -#line 3093 "src/parser.c" /* yacc.c:1646 */ - break; - - case 91: -#line 698 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), gen_const(jv_null()), INDEX_OPT); -} -#line 3101 "src/parser.c" /* yacc.c:1646 */ - break; - - case 92: -#line 701 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_slice_index((yyvsp[-5].blk), gen_const(jv_null()), (yyvsp[-2].blk), INDEX_OPT); -} -#line 3109 "src/parser.c" /* yacc.c:1646 */ - break; - - case 93: -#line 704 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), INDEX); -} -#line 3117 "src/parser.c" /* yacc.c:1646 */ - break; - - case 94: -#line 707 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_slice_index((yyvsp[-4].blk), (yyvsp[-2].blk), gen_const(jv_null()), INDEX); -} -#line 3125 "src/parser.c" /* yacc.c:1646 */ - break; - - case 95: -#line 710 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_slice_index((yyvsp[-4].blk), gen_const(jv_null()), (yyvsp[-1].blk), INDEX); -} -#line 3133 "src/parser.c" /* yacc.c:1646 */ - break; - - case 96: -#line 713 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_const((yyvsp[0].literal)); -} -#line 3141 "src/parser.c" /* yacc.c:1646 */ - break; - - case 97: -#line 716 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 3149 "src/parser.c" /* yacc.c:1646 */ - break; - - case 98: -#line 719 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_format(gen_noop(), (yyvsp[0].literal)); -} -#line 3157 "src/parser.c" /* yacc.c:1646 */ - break; - - case 99: -#line 722 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[-1].blk); -} -#line 3165 "src/parser.c" /* yacc.c:1646 */ - break; - - case 100: -#line 725 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_collect((yyvsp[-1].blk)); -} -#line 3173 "src/parser.c" /* yacc.c:1646 */ - break; - - case 101: -#line 728 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_const(jv_array()); -} -#line 3181 "src/parser.c" /* yacc.c:1646 */ - break; - - case 102: -#line 731 "src/parser.y" /* yacc.c:1646 */ - { - 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 3193 "src/parser.c" /* yacc.c:1646 */ - break; - - case 103: -#line 738 "src/parser.y" /* yacc.c:1646 */ - { - (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))); -} -#line 3202 "src/parser.c" /* yacc.c:1646 */ - break; - - case 104: -#line 742 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal)))); - jv_free((yyvsp[0].literal)); -} -#line 3211 "src/parser.c" /* yacc.c:1646 */ - break; - - case 105: -#line 746 "src/parser.y" /* yacc.c:1646 */ - { - const char *s = jv_string_value((yyvsp[0].literal)); - if (strcmp(s, "false") == 0) - (yyval.blk) = gen_const(jv_false()); - else if (strcmp(s, "true") == 0) - (yyval.blk) = gen_const(jv_true()); - else if (strcmp(s, "null") == 0) - (yyval.blk) = gen_const(jv_null()); - else - (yyval.blk) = gen_location((yyloc), locations, gen_call(s, gen_noop())); - jv_free((yyvsp[0].literal)); -} -#line 3228 "src/parser.c" /* yacc.c:1646 */ - break; - - case 106: -#line 758 "src/parser.y" /* yacc.c:1646 */ - { - (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 3238 "src/parser.c" /* yacc.c:1646 */ - break; - - case 107: -#line 763 "src/parser.y" /* yacc.c:1646 */ - { (yyval.blk) = gen_noop(); } -#line 3244 "src/parser.c" /* yacc.c:1646 */ - break; - - case 108: -#line 764 "src/parser.y" /* yacc.c:1646 */ - { (yyval.blk) = gen_noop(); } -#line 3250 "src/parser.c" /* yacc.c:1646 */ - break; - - case 109: -#line 765 "src/parser.y" /* yacc.c:1646 */ - { (yyval.blk) = (yyvsp[-3].blk); } -#line 3256 "src/parser.c" /* yacc.c:1646 */ - break; - - case 110: -#line 766 "src/parser.y" /* yacc.c:1646 */ - { (yyval.blk) = gen_noop(); } -#line 3262 "src/parser.c" /* yacc.c:1646 */ - break; - - case 111: -#line 769 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 3270 "src/parser.c" /* yacc.c:1646 */ - break; - - case 112: -#line 772 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 3278 "src/parser.c" /* yacc.c:1646 */ - break; - - case 113: -#line 777 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_lambda((yyvsp[0].blk)); -} -#line 3286 "src/parser.c" /* yacc.c:1646 */ - break; - - case 114: -#line 782 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal))); - jv_free((yyvsp[0].literal)); -} -#line 3295 "src/parser.c" /* yacc.c:1646 */ - break; - - case 115: -#line 786 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); -} -#line 3303 "src/parser.c" /* yacc.c:1646 */ - break; - - case 116: -#line 789 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); -} -#line 3311 "src/parser.c" /* yacc.c:1646 */ - break; - - case 117: -#line 794 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_array_matcher(gen_noop(), (yyvsp[0].blk)); -} -#line 3319 "src/parser.c" /* yacc.c:1646 */ - break; - - case 118: -#line 797 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_array_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 3327 "src/parser.c" /* yacc.c:1646 */ - break; - - case 119: -#line 802 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 3335 "src/parser.c" /* yacc.c:1646 */ - break; - - case 120: -#line 805 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 3343 "src/parser.c" /* yacc.c:1646 */ - break; - - case 121: -#line 810 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_object_matcher(gen_const((yyvsp[0].literal)), gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal)))); -} -#line 3351 "src/parser.c" /* yacc.c:1646 */ - break; - - case 122: -#line 813 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); -} -#line 3359 "src/parser.c" /* yacc.c:1646 */ - break; - - case 123: -#line 816 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); -} -#line 3367 "src/parser.c" /* yacc.c:1646 */ - break; - - case 124: -#line 819 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_object_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 3375 "src/parser.c" /* yacc.c:1646 */ - break; - - case 125: -#line 822 "src/parser.y" /* yacc.c:1646 */ - { - jv msg = check_object_key((yyvsp[-3].blk)); - if (jv_is_valid(msg)) { - FAIL((yyloc), jv_string_value(msg)); - } - jv_free(msg); - (yyval.blk) = gen_object_matcher((yyvsp[-3].blk), (yyvsp[0].blk)); -} -#line 3388 "src/parser.c" /* yacc.c:1646 */ - break; - - case 126: -#line 830 "src/parser.y" /* yacc.c:1646 */ - { - FAIL((yyloc), "May need parentheses around object key expression"); - (yyval.blk) = (yyvsp[0].blk); -} -#line 3397 "src/parser.c" /* yacc.c:1646 */ - break; - - case 127: -#line 836 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("as"); -} -#line 3405 "src/parser.c" /* yacc.c:1646 */ - break; - - case 128: -#line 839 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("def"); -} -#line 3413 "src/parser.c" /* yacc.c:1646 */ - break; - - case 129: -#line 842 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("module"); -} -#line 3421 "src/parser.c" /* yacc.c:1646 */ - break; - - case 130: -#line 845 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("import"); -} -#line 3429 "src/parser.c" /* yacc.c:1646 */ - break; - - case 131: -#line 848 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("include"); -} -#line 3437 "src/parser.c" /* yacc.c:1646 */ - break; - - case 132: -#line 851 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("if"); -} -#line 3445 "src/parser.c" /* yacc.c:1646 */ - break; - - case 133: -#line 854 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("then"); -} -#line 3453 "src/parser.c" /* yacc.c:1646 */ - break; - - case 134: -#line 857 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("else"); -} -#line 3461 "src/parser.c" /* yacc.c:1646 */ - break; - - case 135: -#line 860 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("elif"); -} -#line 3469 "src/parser.c" /* yacc.c:1646 */ - break; - - case 136: -#line 863 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("reduce"); -} -#line 3477 "src/parser.c" /* yacc.c:1646 */ - break; - - case 137: -#line 866 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("foreach"); -} -#line 3485 "src/parser.c" /* yacc.c:1646 */ - break; - - case 138: -#line 869 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("end"); -} -#line 3493 "src/parser.c" /* yacc.c:1646 */ - break; - - case 139: -#line 872 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("and"); -} -#line 3501 "src/parser.c" /* yacc.c:1646 */ - break; - - case 140: -#line 875 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("or"); -} -#line 3509 "src/parser.c" /* yacc.c:1646 */ - break; - - case 141: -#line 878 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("try"); -} -#line 3517 "src/parser.c" /* yacc.c:1646 */ - break; - - case 142: -#line 881 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("catch"); -} -#line 3525 "src/parser.c" /* yacc.c:1646 */ - break; - - case 143: -#line 884 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("label"); -} -#line 3533 "src/parser.c" /* yacc.c:1646 */ - break; - - case 144: -#line 887 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("break"); -} -#line 3541 "src/parser.c" /* yacc.c:1646 */ - break; - - case 145: -#line 890 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.literal) = jv_string("__loc__"); -} -#line 3549 "src/parser.c" /* yacc.c:1646 */ - break; - - case 146: -#line 895 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk)=gen_noop(); -} -#line 3557 "src/parser.c" /* yacc.c:1646 */ - break; - - case 147: -#line 898 "src/parser.y" /* yacc.c:1646 */ - { (yyval.blk) = (yyvsp[0].blk); } -#line 3563 "src/parser.c" /* yacc.c:1646 */ - break; - - case 148: -#line 899 "src/parser.y" /* yacc.c:1646 */ - { (yyval.blk)=block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3569 "src/parser.c" /* yacc.c:1646 */ - break; - - case 149: -#line 900 "src/parser.y" /* yacc.c:1646 */ - { (yyval.blk) = (yyvsp[0].blk); } -#line 3575 "src/parser.c" /* yacc.c:1646 */ - break; - - case 150: -#line 903 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); - } -#line 3583 "src/parser.c" /* yacc.c:1646 */ - break; - - case 151: -#line 906 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); - } -#line 3591 "src/parser.c" /* yacc.c:1646 */ - break; - - case 152: -#line 909 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_dictpair((yyvsp[-2].blk), (yyvsp[0].blk)); - } -#line 3599 "src/parser.c" /* yacc.c:1646 */ - break; - - case 153: -#line 912 "src/parser.y" /* yacc.c:1646 */ - { - (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 3608 "src/parser.c" /* yacc.c:1646 */ - break; - - case 154: -#line 916 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_dictpair(gen_const((yyvsp[0].literal)), - gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal))))); - } -#line 3617 "src/parser.c" /* yacc.c:1646 */ - break; - - case 155: -#line 920 "src/parser.y" /* yacc.c:1646 */ - { - (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), - gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); - } -#line 3626 "src/parser.c" /* yacc.c:1646 */ - break; - - case 156: -#line 924 "src/parser.y" /* yacc.c:1646 */ - { - jv msg = check_object_key((yyvsp[-3].blk)); - if (jv_is_valid(msg)) { - FAIL((yyloc), jv_string_value(msg)); - } - jv_free(msg); - (yyval.blk) = gen_dictpair((yyvsp[-3].blk), (yyvsp[0].blk)); - } -#line 3639 "src/parser.c" /* yacc.c:1646 */ - break; - - case 157: -#line 932 "src/parser.y" /* yacc.c:1646 */ - { - FAIL((yyloc), "May need parentheses around object key expression"); - (yyval.blk) = (yyvsp[0].blk); - } -#line 3648 "src/parser.c" /* yacc.c:1646 */ - break; - - -#line 3652 "src/parser.c" /* yacc.c:1646 */ - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - *++yylsp = yyloc; - - /* Now 'shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*--------------------------------------. -| yyerrlab -- here on detecting error. | -`--------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (&yylloc, answer, errors, locations, lexer_param_ptr, YY_("syntax error")); -#else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) - { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (&yylloc, answer, errors, locations, lexer_param_ptr, yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; - } -# undef YYSYNTAX_ERROR -#endif - } - - yyerror_range[1] = yylloc; - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval, &yylloc, answer, errors, locations, lexer_param_ptr); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - yyerror_range[1] = yylsp[1-yylen]; - /* Do not reclaim the symbols of the rule whose action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - yyerror_range[1] = *yylsp; - yydestruct ("Error: popping", - yystos[yystate], yyvsp, yylsp, answer, errors, locations, lexer_param_ptr); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - yyerror_range[2] = yylloc; - /* Using YYLLOC is tempting, but would change the location of - the lookahead. YYLOC is available though. */ - YYLLOC_DEFAULT (yyloc, yyerror_range, 2); - *++yylsp = yyloc; - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#if !defined yyoverflow || YYERROR_VERBOSE -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (&yylloc, answer, errors, locations, lexer_param_ptr, YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, &yylloc, answer, errors, locations, lexer_param_ptr); - } - /* Do not reclaim the symbols of the rule whose action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, yylsp, answer, errors, locations, lexer_param_ptr); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - return yyresult; -} -#line 936 "src/parser.y" /* yacc.c:1906 */ - - -int jq_parse(struct locfile* locations, block* answer) { - struct lexer_param scanner; - YY_BUFFER_STATE buf; - jq_yylex_init_extra(0, &scanner.lexer); - buf = jq_yy_scan_bytes(locations->data, locations->length, scanner.lexer); - int errors = 0; - *answer = gen_noop(); - yyparse(answer, &errors, locations, &scanner); - jq_yy_delete_buffer(buf, scanner.lexer); - jq_yylex_destroy(scanner.lexer); - if (errors > 0) { - block_free(*answer); - *answer = gen_noop(); - } - return errors; -} - -int jq_parse_library(struct locfile* locations, block* answer) { - int errs = jq_parse(locations, answer); - if (errs) return errs; - if (block_has_main(*answer)) { - locfile_locate(locations, UNKNOWN_LOCATION, "jq: error: library should only have function definitions, not a main expression"); - return 1; - } - assert(block_has_only_binders_and_imports(*answer, OP_IS_CALL_PSEUDO)); - return 0; -} diff --git a/src/jq/parser.h b/src/jq/parser.h deleted file mode 100644 index 6facfcc..0000000 --- a/src/jq/parser.h +++ /dev/null @@ -1,193 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -#ifndef YY_YY_SRC_PARSER_H_INCLUDED -# define YY_YY_SRC_PARSER_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif -/* "%code requires" blocks. */ -#line 11 "src/parser.y" /* yacc.c:1909 */ - -#include "locfile.h" -struct lexer_param; - -#define YYLTYPE location -#define YYLLOC_DEFAULT(Loc, Rhs, N) \ - do { \ - if (N) { \ - (Loc).start = YYRHSLOC(Rhs, 1).start; \ - (Loc).end = YYRHSLOC(Rhs, N).end; \ - } else { \ - (Loc).start = YYRHSLOC(Rhs, 0).end; \ - (Loc).end = YYRHSLOC(Rhs, 0).end; \ - } \ - } while (0) - -#line 61 "src/parser.h" /* yacc.c:1909 */ - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - INVALID_CHARACTER = 258, - IDENT = 259, - FIELD = 260, - LITERAL = 261, - FORMAT = 262, - REC = 263, - SETMOD = 264, - EQ = 265, - NEQ = 266, - 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, - QQSTRING_START = 295, - QQSTRING_TEXT = 296, - QQSTRING_INTERP_START = 297, - QQSTRING_INTERP_END = 298, - QQSTRING_END = 299, - FUNCDEF = 300, - NONOPT = 301 - }; -#endif -/* Tokens. */ -#define INVALID_CHARACTER 258 -#define IDENT 259 -#define FIELD 260 -#define LITERAL 261 -#define FORMAT 262 -#define REC 263 -#define SETMOD 264 -#define EQ 265 -#define NEQ 266 -#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 QQSTRING_START 295 -#define QQSTRING_TEXT 296 -#define QQSTRING_INTERP_START 297 -#define QQSTRING_INTERP_END 298 -#define QQSTRING_END 299 -#define FUNCDEF 300 -#define NONOPT 301 - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; -union YYSTYPE -{ -#line 31 "src/parser.y" /* yacc.c:1909 */ - - jv literal; - block blk; - -#line 170 "src/parser.h" /* yacc.c:1909 */ -}; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - -/* Location type. */ -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE YYLTYPE; -struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -}; -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif - - - -int yyparse (block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr); - -#endif /* !YY_YY_SRC_PARSER_H_INCLUDED */ diff --git a/src/jq/util.c b/src/jq/util.c deleted file mode 100644 index 51c42e4..0000000 --- a/src/jq/util.c +++ /dev/null @@ -1,459 +0,0 @@ - -#ifdef HAVE_MEMMEM -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_ALLOCA_H -# include -#elif !defined alloca -# ifdef __GNUC__ -# define alloca __builtin_alloca -# elif defined _MSC_VER -# include -# define alloca _alloca -# elif !defined HAVE_ALLOCA -# ifdef __cplusplus -extern "C" -# endif -void *alloca (size_t); -# endif -#endif -#ifndef WIN32 -#include -#endif - -#ifdef WIN32 -#include -#include -#include -#include -#endif - - -#include "util.h" -#include "jq.h" -#include "jv_alloc.h" - -#ifdef WIN32 -FILE *fopen(const char *fname, const char *mode) { - size_t sz = sizeof(wchar_t) * MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0); - wchar_t *wfname = alloca(sz + 2); // +2 is not needed, but just in case - MultiByteToWideChar(CP_UTF8, 0, fname, -1, wfname, sz); - - sz = sizeof(wchar_t) * MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); - wchar_t *wmode = alloca(sz); // +2 is not needed, but just in case - MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, sz); - return _wfopen(wfname, wmode); -} -#endif - -#ifndef HAVE_MKSTEMP -int mkstemp(char *template) { - size_t len = strlen(template); - int tries=5; - int fd; - - // mktemp() truncates template when it fails - char *s = alloca(len + 1); - assert(s != NULL); - strcpy(s, template); - - do { - // Restore template - strcpy(template, s); - (void) mktemp(template); - fd = open(template, O_CREAT | O_EXCL | O_RDWR, 0600); - } while (fd == -1 && tries-- > 0); - return fd; -} -#endif - -jv expand_path(jv path) { - assert(jv_get_kind(path) == JV_KIND_STRING); - const char *pstr = jv_string_value(path); - jv ret = path; - if (jv_string_length_bytes(jv_copy(path)) > 1 && pstr[0] == '~' && pstr[1] == '/') { - jv home = get_home(); - if (jv_is_valid(home)) { - ret = jv_string_fmt("%s/%s",jv_string_value(home),pstr+2); - jv_free(home); - } else { - jv emsg = jv_invalid_get_msg(home); - ret = jv_invalid_with_msg(jv_string_fmt("Could not expand %s. (%s)", pstr, jv_string_value(emsg))); - jv_free(emsg); - } - jv_free(path); - } - return ret; -} - -jv get_home() { - jv ret; - char *home = getenv("HOME"); - if (!home) { -#ifndef WIN32 - struct passwd* pwd = getpwuid(getuid()); - if (pwd) - ret = jv_string(pwd->pw_dir); - else - ret = jv_invalid_with_msg(jv_string("Could not find home directory.")); -#else - home = getenv("USERPROFILE"); - if (!home) { - char *hd = getenv("HOMEDRIVE"); - if (!hd) hd = ""; - home = getenv("HOMEPATH"); - if (!home) { - ret = jv_invalid_with_msg(jv_string("Could not find home directory.")); - } else { - ret = jv_string_fmt("%s%s",hd,home); - } - } else { - ret = jv_string(home); - } -#endif - } else { - ret = jv_string(home); - } - return ret; -} - - -jv jq_realpath(jv path) { - int path_max; - char *buf = NULL; -#ifdef _PC_PATH_MAX - path_max = pathconf(jv_string_value(path),_PC_PATH_MAX); -#else - path_max = PATH_MAX; -#endif - if (path_max > 0) { - buf = malloc(sizeof(char) * path_max); - } -#ifdef WIN32 - char *tmp = _fullpath(buf, jv_string_value(path), path_max); -#else - char *tmp = realpath(jv_string_value(path), buf); -#endif - if (tmp == NULL) { - free(buf); - return path; - } - jv_free(path); - path = jv_string(tmp); - free(tmp); - return path; -} - -const void *_jq_memmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen) { -#ifdef HAVE_MEMMEM - return (const void*)memmem(haystack, haystacklen, needle, needlelen); -#else - const char *h = haystack; - const char *n = needle; - size_t hi, hi2, ni; - - if (haystacklen < needlelen || haystacklen == 0) - return NULL; - for (hi = 0; hi < (haystacklen - needlelen + 1); hi++) { - for (ni = 0, hi2 = hi; ni < needlelen; ni++, hi2++) { - if (h[hi2] != n[ni]) - goto not_this; - } - - return &h[hi]; - -not_this: - continue; - } - return NULL; -#endif /* !HAVE_MEMMEM */ -} - -struct jq_util_input_state { - jq_util_msg_cb err_cb; - void *err_cb_data; - jv_parser *parser; - FILE* current_input; - char **files; - int nfiles; - int curr_file; - int failures; - jv slurped; - char buf[4096]; - size_t buf_valid_len; - jv current_filename; - size_t current_line; -}; - -static void fprinter(void *data, const char *fname) { - fprintf((FILE *)data, "jq: error: Could not open file %s: %s\n", fname, strerror(errno)); -} - -// If parser == NULL -> RAW -jq_util_input_state *jq_util_input_init(jq_util_msg_cb err_cb, void *err_cb_data) { - if (err_cb == NULL) { - err_cb = fprinter; - err_cb_data = stderr; - } - jq_util_input_state *new_state = jv_mem_alloc(sizeof(*new_state)); - memset(new_state, 0, sizeof(*new_state)); - new_state->err_cb = err_cb; - new_state->err_cb_data = err_cb_data; - new_state->parser = NULL; - new_state->current_input = NULL; - new_state->files = NULL; - new_state->nfiles = 0; - new_state->curr_file = 0; - new_state->slurped = jv_invalid(); - new_state->buf[0] = 0; - new_state->buf_valid_len = 0; - new_state->current_filename = jv_invalid(); - new_state->current_line = 0; - - return new_state; -} - -void jq_util_input_set_parser(jq_util_input_state *state, jv_parser *parser, int slurp) { - assert(!jv_is_valid(state->slurped)); - state->parser = parser; - - if (parser == NULL && slurp) - state->slurped = jv_string(""); - else if (slurp) - state->slurped = jv_array(); - else - state->slurped = jv_invalid(); -} - -void jq_util_input_free(jq_util_input_state **state) { - jq_util_input_state *old_state = *state; - *state = NULL; - if (old_state == NULL) - return; - - if (old_state->parser != NULL) - jv_parser_free(old_state->parser); - for (int i = 0; i < old_state->nfiles; i++) - free(old_state->files[i]); - free(old_state->files); - jv_free(old_state->slurped); - jv_free(old_state->current_filename); - jv_mem_free(old_state); -} - -void jq_util_input_add_input(jq_util_input_state *state, const char *fname) { - state->files = jv_mem_realloc(state->files, (state->nfiles + 1) * sizeof(state->files[0])); - state->files[state->nfiles++] = jv_mem_strdup(fname); -} - -int jq_util_input_errors(jq_util_input_state *state) { - return state->failures; -} - -static const char *next_file(jq_util_input_state *state) { - if (state->curr_file < state->nfiles) - return state->files[state->curr_file++]; - return NULL; -} - -static int jq_util_input_read_more(jq_util_input_state *state) { - if (!state->current_input || feof(state->current_input) || ferror(state->current_input)) { - if (state->current_input && ferror(state->current_input)) { - // System-level input error on the stream. It will be closed (below). - // TODO: report it. Can't use 'state->err_cb()' as it is hard-coded for - // 'open' related problems. - fprintf(stderr,"Input error: %s\n", strerror(errno)); - } - if (state->current_input) { - if (state->current_input == stdin) { - clearerr(stdin); // perhaps we can read again; anyways, we don't fclose(stdin) - } else { - fclose(state->current_input); - } - state->current_input = NULL; - jv_free(state->current_filename); - state->current_filename = jv_invalid(); - state->current_line = 0 ; - } - const char *f = next_file(state); - if (f != NULL) { - if (!strcmp(f, "-")) { - state->current_input = stdin; - state->current_filename = jv_string(""); - } else { - state->current_input = fopen(f, "r"); - state->current_filename = jv_string(f); - if (!state->current_input) { - state->err_cb(state->err_cb_data, f); - state->failures++; - } - } - state->current_line = 0; - } - } - - state->buf[0] = 0; - state->buf_valid_len = 0; - if (state->current_input) { - char *res; - memset(state->buf, 0, sizeof(state->buf)); - - while (!(res = fgets(state->buf, sizeof(state->buf), state->current_input)) && - ferror(state->current_input) && errno == EINTR) - clearerr(state->current_input); - if (res == NULL) { - state->buf[0] = 0; - if (ferror(state->current_input)) - state->failures++; - } else { - const char *p = memchr(state->buf, '\n', sizeof(state->buf)); - - if (p != NULL) - state->current_line++; - - if (p == NULL && state->parser != NULL) { - /* - * There should be no NULs in JSON texts (but JSON text - * sequences are another story). - */ - state->buf_valid_len = strlen(state->buf); - } else if (p == NULL && feof(state->current_input)) { - size_t i; - - /* - * XXX We can't know how many bytes we've read! - * - * We can't use getline() because there need not be any newlines - * in the input. The only entirely correct choices are: use - * fgetc() or fread(). Using fread() will complicate buffer - * management here. - * - * For now we guess how much fgets() read. - */ - for (p = state->buf, i = 0; i < sizeof(state->buf); i++) { - if (state->buf[i] != '\0') - p = &state->buf[i]; - } - state->buf_valid_len = p - state->buf + 1; - } else if (p == NULL) { - state->buf_valid_len = sizeof(state->buf) - 1; - } else { - state->buf_valid_len = (p - state->buf) + 1; - } - } - } - return state->curr_file == state->nfiles && - (!state->current_input || feof(state->current_input) || ferror(state->current_input)); -} - -jv jq_util_input_next_input_cb(jq_state *jq, void *data) { - return jq_util_input_next_input((jq_util_input_state *)data); -} - -// Return the current_filename:current_line -jv jq_util_input_get_position(jq_state *jq) { - jq_input_cb cb = NULL; - void *cb_data = NULL; - jq_get_input_cb(jq, &cb, &cb_data); - assert(cb == jq_util_input_next_input_cb); - if (cb != jq_util_input_next_input_cb) - return jv_invalid_with_msg(jv_string("Invalid jq_util_input API usage")); - jq_util_input_state *s = (jq_util_input_state *)cb_data; - - // We can't assert that current_filename is a string because if - // the error was a JSON parser error then we may not have set - // current_filename yet. - if (jv_get_kind(s->current_filename) != JV_KIND_STRING) - return jv_string(""); - - jv v = jv_string_fmt("%s:%lu", jv_string_value(s->current_filename), (unsigned long)s->current_line); - return v; -} - -jv jq_util_input_get_current_filename(jq_state* jq) { - jq_input_cb cb=NULL; - void *cb_data=NULL; - jq_get_input_cb(jq, &cb, &cb_data); - if (cb != jq_util_input_next_input_cb) - return jv_invalid_with_msg(jv_string("Unknown input filename")); - jq_util_input_state *s = (jq_util_input_state *)cb_data; - jv v = jv_copy(s->current_filename); - return v; -} - -jv jq_util_input_get_current_line(jq_state* jq) { - jq_input_cb cb=NULL; - void *cb_data=NULL; - jq_get_input_cb(jq, &cb, &cb_data); - if (cb != jq_util_input_next_input_cb) - return jv_invalid_with_msg(jv_string("Unknown input line number")); - jq_util_input_state *s = (jq_util_input_state *)cb_data; - jv v = jv_number(s->current_line); - return v; -} - - -// Blocks to read one more input from stdin and/or given files -// When slurping, it returns just one value -jv jq_util_input_next_input(jq_util_input_state *state) { - int is_last = 0; - jv value = jv_invalid(); // need more input - do { - if (state->parser == NULL) { - // Raw input - is_last = jq_util_input_read_more(state); - if (state->buf_valid_len == 0) - continue; - if (jv_is_valid(state->slurped)) { - // Slurped raw input - state->slurped = jv_string_concat(state->slurped, jv_string_sized(state->buf, state->buf_valid_len)); - } else { - if (!jv_is_valid(value)) - value = jv_string(""); - if (state->buf[state->buf_valid_len-1] == '\n') { - // whole line - state->buf[state->buf_valid_len-1] = 0; - return jv_string_concat(value, jv_string_sized(state->buf, state->buf_valid_len-1)); - } - value = jv_string_concat(value, jv_string_sized(state->buf, state->buf_valid_len)); - state->buf[0] = '\0'; - state->buf_valid_len = 0; - } - } else { - if (jv_parser_remaining(state->parser) == 0) { - is_last = jq_util_input_read_more(state); - if (is_last && state->buf_valid_len == 0) - value = jv_invalid(); - jv_parser_set_buf(state->parser, state->buf, state->buf_valid_len, !is_last); - } - value = jv_parser_next(state->parser); - if (jv_is_valid(state->slurped)) { - if (jv_is_valid(value)) { - state->slurped = jv_array_append(state->slurped, value); - value = jv_invalid(); - } else if (jv_invalid_has_msg(jv_copy(value))) - return value; // Not slurped parsed input - } else if (jv_is_valid(value) || jv_invalid_has_msg(jv_copy(value))) { - return value; - } - } - } while (!is_last); - - if (jv_is_valid(state->slurped)) { - value = state->slurped; - state->slurped = jv_invalid(); - } - return value; -} diff --git a/src/jq/util.h b/src/jq/util.h deleted file mode 100644 index 3d845a2..0000000 --- a/src/jq/util.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef UTIL_H -#define UTIL_H - -#ifdef WIN32 -/* For WriteFile() below */ -#include -#include -#include -#include -#include -#endif - -#include "jv.h" - -#ifndef HAVE_MKSTEMP -int mkstemp(char *template); -#endif - -jv expand_path(jv); -jv get_home(void); -jv jq_realpath(jv); - -/* - * The Windows CRT and console are something else. In order for the - * console to get UTF-8 written to it correctly we have to bypass stdio - * completely. No amount of fflush()ing helps. If the first byte of a - * buffer being written with fwrite() is non-ASCII UTF-8 then the - * console misinterprets the byte sequence. But one must not - * WriteFile() if stdout is a file!1!! - * - * We carry knowledge of whether the FILE * is a tty everywhere we - * output to it just so we can write with WriteFile() if stdout is a - * console on WIN32. - */ - -static void priv_fwrite(const char *s, size_t len, FILE *fout, int is_tty) { -#ifdef WIN32 - if (is_tty) - WriteFile((HANDLE)_get_osfhandle(fileno(fout)), s, len, NULL, NULL); - else - fwrite(s, 1, len, fout); -#else - fwrite(s, 1, len, fout); -#endif -} - -const void *_jq_memmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen); - -#ifndef MIN -#define MIN(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) -#endif -#ifndef MAX -#define MAX(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) -#endif - -#endif /* UTIL_H */ diff --git a/src/jq/version.h b/src/jq/version.h deleted file mode 100644 index 58c11f5..0000000 --- a/src/jq/version.h +++ /dev/null @@ -1 +0,0 @@ -#define JQ_VERSION "1.5rc2-174-g597c1f6" diff --git a/src/jqr.c b/src/jqr.c index b440c7c..28887ac 100644 --- a/src/jqr.c +++ b/src/jqr.c @@ -5,10 +5,10 @@ #include #include #include -#include attribute_visible SEXP C_jq_version(){ - return Rf_mkString(JQ_VERSION); + //return Rf_mkString(JQ_VERSION); + return R_NilValue; } void error_cb(void * data, jv x) { diff --git a/tools/winlibs.R b/tools/winlibs.R new file mode 100644 index 0000000..d69182e --- /dev/null +++ b/tools/winlibs.R @@ -0,0 +1,8 @@ +# Build against mingw-w64 build of jq 1.5 +if(!file.exists("../windows/jq-1.5/include/jq.h")){ + if(getRversion() < "3.3.0") setInternet2() + download.file("https://github.com/rwinlib/jq/archive/v1.5.zip", "lib.zip", quiet = TRUE) + dir.create("../windows", showWarnings = FALSE) + unzip("lib.zip", exdir = "../windows") + unlink("lib.zip") +} From 9d4455fcb9ff49314fbd9259609fa1fd6415735a Mon Sep 17 00:00:00 2001 From: Jeroen Date: Tue, 19 Sep 2017 11:04:03 +0200 Subject: [PATCH 2/4] reorganize travis --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index beab3e5..0609881 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: r cache: packages dist: trusty latex: false +sudo: required matrix: include: @@ -20,12 +21,12 @@ matrix: disable_homebrew: true addons: - sources: - - sourceline: 'ppa:opencpu/jq' apt: + sources: + - sourceline: 'ppa:opencpu/jq' packages: - - libjq-dev - - valgrind + - libjq-dev + - valgrind after_success: - if [[ "${R_CODECOV}" ]]; then R -e 'covr::codecov()'; fi From 432ec1c9095c1a6d3cef41b04f3a851ba3051a18 Mon Sep 17 00:00:00 2001 From: Jeroen Date: Tue, 19 Sep 2017 11:17:52 +0200 Subject: [PATCH 3/4] Update DESCRIPTION --- DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 6af3105..5bef654 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -4,7 +4,7 @@ Description: Client for 'jq', a 'JSON' processor (= 3.1.2) License: MIT + file LICENSE @@ -16,6 +16,7 @@ Authors@R: c(person("Rich", "FitzJohn", role = "aut", email = "rich.fitzjohn@gma VignetteBuilder: knitr URL: https://github.com/ropensci/jqr BugReports: https://github.com/ropensci/jqr/issues +SystemRequirements: libjq: jq-devel (rpm) or libjq-dev (deb) Imports: magrittr, lazyeval From ec943641658ef648116b0eaf8cd67082c1e1c4ee Mon Sep 17 00:00:00 2001 From: Jeroen Date: Tue, 19 Sep 2017 11:34:43 +0200 Subject: [PATCH 4/4] Update readme --- README.Rmd | 56 +++++++++++++++++++++++++++++++++++++++++++----------- README.md | 54 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 88 insertions(+), 22 deletions(-) diff --git a/README.Rmd b/README.Rmd index be3f052..b525fad 100644 --- a/README.Rmd +++ b/README.Rmd @@ -26,22 +26,56 @@ means that the eventual loading into R can be quicker. [Introduction](vignettes/jqr_vignette.md) -## Install +## Installation -Stable version: +Binary packages for __OS-X__ or __Windows__ can be installed directly from CRAN: -```{r eval=FALSE} +```r install.packages("jqr") ``` -Development version: +Installation from source on Linux or OSX requires [`libjq`](https://stedolan.github.io/jq/). On __Ubuntu 14.04 and 16.04 lower__ use [libjq-dev](https://launchpad.net/~opencpu/+archive/ubuntu/jq) from Launchpad: -```{r eval=FALSE} -devtools::install_github("ropensci/jqr") +``` +sudo add-apt-repository -y ppa:opencpu/jq +sudo apt-get update -q +sudo apt-get install -y libjq-dev +``` + +More __recent Debian or Ubuntu__ install [libjq-dev](https://packages.debian.org/testing/libjq-dev) directly from Universe: + +``` +sudo apt-get install -y libjq-dev +``` + +On __Fedora__ we need [jq-devel](https://apps.fedoraproject.org/packages/jq-devel): + +``` +sudo yum install jq-devel +```` + +On __CentOS / RHEL__ we install [libsodium-devel](https://apps.fedoraproject.org/packages/jq-devel) via EPEL: + +``` +sudo yum install epel-release +sudo yum install jq-devel +``` + +On __OS-X__ use [jq](https://github.com/Homebrew/homebrew-core/blob/master/Formula/jq.rb) from Homebrew: + +``` +brew install jq +``` + +On __Solaris__ we can have [libjq_dev](https://www.opencsw.org/packages/libjq_dev) from [OpenCSW](https://www.opencsw.org/): +``` +pkgadd -d http://get.opencsw.org/now +/opt/csw/bin/pkgutil -U +/opt/csw/bin/pkgutil -y -i libjq_dev ``` ```{r} -library("jqr") +library(jqr) ``` ## Interfaces @@ -216,10 +250,10 @@ Select variables by name, and rename '{"foo": 5, "bar": 7}' %>% select(a = .foo) ``` -More complicated `select()`, using the included dataset `githubcommits` +More complicated `select()`, using the included dataset `commits` ```{r} -githubcommits %>% +commits %>% index() %>% select(sha = .sha, name = .commit.committer.name) ``` @@ -290,7 +324,7 @@ find maximum This outputs a few pieces of JSON ```{r} -(x <- githubcommits %>% +(x <- commits %>% index() %>% select(sha = .sha, name = .commit.committer.name)) ``` @@ -308,4 +342,4 @@ combine(x) * Get citation information for `jqr` in R doing `citation(package = 'jqr')` * Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms. -[![rofooter](http://ropensci.org/public_images/github_footer.png)](http://ropensci.org) +[![rofooter](http://www.ropensci.org/public_images/github_footer.png)](http://ropensci.org) diff --git a/README.md b/README.md index e2ecdc0..235dfd1 100644 --- a/README.md +++ b/README.md @@ -19,25 +19,57 @@ means that the eventual loading into R can be quicker. [Introduction](vignettes/jqr_vignette.md) -## Install - -Stable version: +## Installation +Binary packages for __OS-X__ or __Windows__ can be installed directly from CRAN: ```r install.packages("jqr") ``` -Development version: +Installation from source on Linux or OSX requires [`libjq`](https://stedolan.github.io/jq/). On __Ubuntu 14.04 and 16.04 lower__ use [libjq-dev](https://launchpad.net/~opencpu/+archive/ubuntu/jq) from Launchpad: +``` +sudo add-apt-repository -y ppa:opencpu/jq +sudo apt-get update -q +sudo apt-get install -y libjq-dev +``` -```r -devtools::install_github("ropensci/jqr") +More __recent Debian or Ubuntu__ install [libjq-dev](https://packages.debian.org/testing/libjq-dev) directly from Universe: + +``` +sudo apt-get install -y libjq-dev +``` + +On __Fedora__ we need [jq-devel](https://apps.fedoraproject.org/packages/jq-devel): + +``` +sudo yum install jq-devel +```` + +On __CentOS / RHEL__ we install [libsodium-devel](https://apps.fedoraproject.org/packages/jq-devel) via EPEL: + +``` +sudo yum install epel-release +sudo yum install jq-devel +``` + +On __OS-X__ use [jq](https://github.com/Homebrew/homebrew-core/blob/master/Formula/jq.rb) from Homebrew: + +``` +brew install jq +``` + +On __Solaris__ we can have [libjq_dev](https://www.opencsw.org/packages/libjq_dev) from [OpenCSW](https://www.opencsw.org/): +``` +pkgadd -d http://get.opencsw.org/now +/opt/csw/bin/pkgutil -U +/opt/csw/bin/pkgutil -y -i libjq_dev ``` ```r -library("jqr") +library(jqr) ``` ## Interfaces @@ -381,11 +413,11 @@ Select variables by name, and rename #> } ``` -More complicated `select()`, using the included dataset `githubcommits` +More complicated `select()`, using the included dataset `commits` ```r -githubcommits %>% +commits %>% index() %>% select(sha = .sha, name = .commit.committer.name) #> [ @@ -590,7 +622,7 @@ This outputs a few pieces of JSON ```r -(x <- githubcommits %>% +(x <- commits %>% index() %>% select(sha = .sha, name = .commit.committer.name)) #> [ @@ -693,4 +725,4 @@ combine(x) * Get citation information for `jqr` in R doing `citation(package = 'jqr')` * Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms. -[![rofooter](http://ropensci.org/public_images/github_footer.png)](http://ropensci.org) +[![rofooter](http://www.ropensci.org/public_images/github_footer.png)](http://ropensci.org)