From 91ae0dee0bd4205d750b3d9cc008563f1eb98ed1 Mon Sep 17 00:00:00 2001 From: maxcodehack Date: Sun, 20 Dec 2020 08:45:42 +0000 Subject: [PATCH] kosjs: replace libmujs.a with sources; if argc = 0, see "usage" git-svn-id: svn://kolibrios.org@8456 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/kosjs/Makefile | 4 +- programs/develop/kosjs/kosjs.c | 10 +- programs/develop/kosjs/libmujs/AUTHORS | 1 + programs/develop/kosjs/libmujs/COPYING | 16 + programs/develop/kosjs/libmujs/Makefile | 16 + programs/develop/kosjs/libmujs/README | 52 + .../kosjs/libmujs/{include => }/astnames.h | 0 .../kosjs/libmujs/{include => }/import.h | 0 programs/develop/kosjs/libmujs/jsarray.c | 748 +++++++ programs/develop/kosjs/libmujs/jsboolean.c | 40 + programs/develop/kosjs/libmujs/jsbuiltin.c | 245 +++ .../kosjs/libmujs/{include => }/jsbuiltin.h | 0 programs/develop/kosjs/libmujs/jscompile.c | 1447 +++++++++++++ .../kosjs/libmujs/{include => }/jscompile.h | 0 programs/develop/kosjs/libmujs/jsdate.c | 812 ++++++++ programs/develop/kosjs/libmujs/jsdtoa.c | 747 +++++++ programs/develop/kosjs/libmujs/jsdump.c | 924 +++++++++ programs/develop/kosjs/libmujs/jserror.c | 132 ++ programs/develop/kosjs/libmujs/jsfunction.c | 229 +++ programs/develop/kosjs/libmujs/jsgc.c | 278 +++ .../develop/kosjs/libmujs/{include => }/jsi.h | 16 +- programs/develop/kosjs/libmujs/jsintern.c | 135 ++ programs/develop/kosjs/libmujs/jslex.c | 879 ++++++++ .../kosjs/libmujs/{include => }/jslex.h | 0 programs/develop/kosjs/libmujs/jsmath.c | 192 ++ programs/develop/kosjs/libmujs/jsnumber.c | 198 ++ programs/develop/kosjs/libmujs/jsobject.c | 521 +++++ programs/develop/kosjs/libmujs/json.c | 414 ++++ programs/develop/kosjs/libmujs/jsparse.c | 1067 ++++++++++ .../kosjs/libmujs/{include => }/jsparse.h | 0 programs/develop/kosjs/libmujs/jsproperty.c | 333 +++ programs/develop/kosjs/libmujs/jsregexp.c | 205 ++ programs/develop/kosjs/libmujs/jsrepr.c | 289 +++ programs/develop/kosjs/libmujs/jsrun.c | 1811 +++++++++++++++++ .../kosjs/libmujs/{include => }/jsrun.h | 0 programs/develop/kosjs/libmujs/jsstate.c | 298 +++ programs/develop/kosjs/libmujs/jsstring.c | 711 +++++++ programs/develop/kosjs/libmujs/jsvalue.c | 630 ++++++ .../kosjs/libmujs/{include => }/jsvalue.h | 3 +- programs/develop/kosjs/libmujs/lib/libmujs.a | Bin 326416 -> 0 bytes .../kosjs/libmujs/{include => }/mujs.h | 0 .../kosjs/libmujs/{include => }/opnames.h | 0 programs/develop/kosjs/libmujs/pp.c | 115 ++ programs/develop/kosjs/libmujs/regexp.c | 1204 +++++++++++ .../kosjs/libmujs/{include => }/regexp.h | 0 programs/develop/kosjs/libmujs/utf.c | 212 ++ .../develop/kosjs/libmujs/{include => }/utf.h | 5 +- programs/develop/kosjs/libmujs/utftype.c | 1130 ++++++++++ 48 files changed, 16058 insertions(+), 11 deletions(-) create mode 100755 programs/develop/kosjs/libmujs/AUTHORS create mode 100755 programs/develop/kosjs/libmujs/COPYING create mode 100755 programs/develop/kosjs/libmujs/Makefile create mode 100755 programs/develop/kosjs/libmujs/README rename programs/develop/kosjs/libmujs/{include => }/astnames.h (100%) rename programs/develop/kosjs/libmujs/{include => }/import.h (100%) create mode 100755 programs/develop/kosjs/libmujs/jsarray.c create mode 100755 programs/develop/kosjs/libmujs/jsboolean.c create mode 100755 programs/develop/kosjs/libmujs/jsbuiltin.c rename programs/develop/kosjs/libmujs/{include => }/jsbuiltin.h (100%) create mode 100755 programs/develop/kosjs/libmujs/jscompile.c rename programs/develop/kosjs/libmujs/{include => }/jscompile.h (100%) create mode 100755 programs/develop/kosjs/libmujs/jsdate.c create mode 100755 programs/develop/kosjs/libmujs/jsdtoa.c create mode 100755 programs/develop/kosjs/libmujs/jsdump.c create mode 100755 programs/develop/kosjs/libmujs/jserror.c create mode 100755 programs/develop/kosjs/libmujs/jsfunction.c create mode 100755 programs/develop/kosjs/libmujs/jsgc.c rename programs/develop/kosjs/libmujs/{include => }/jsi.h (90%) create mode 100755 programs/develop/kosjs/libmujs/jsintern.c create mode 100755 programs/develop/kosjs/libmujs/jslex.c rename programs/develop/kosjs/libmujs/{include => }/jslex.h (100%) create mode 100755 programs/develop/kosjs/libmujs/jsmath.c create mode 100755 programs/develop/kosjs/libmujs/jsnumber.c create mode 100755 programs/develop/kosjs/libmujs/jsobject.c create mode 100755 programs/develop/kosjs/libmujs/json.c create mode 100755 programs/develop/kosjs/libmujs/jsparse.c rename programs/develop/kosjs/libmujs/{include => }/jsparse.h (100%) create mode 100755 programs/develop/kosjs/libmujs/jsproperty.c create mode 100755 programs/develop/kosjs/libmujs/jsregexp.c create mode 100755 programs/develop/kosjs/libmujs/jsrepr.c create mode 100755 programs/develop/kosjs/libmujs/jsrun.c rename programs/develop/kosjs/libmujs/{include => }/jsrun.h (100%) create mode 100755 programs/develop/kosjs/libmujs/jsstate.c create mode 100755 programs/develop/kosjs/libmujs/jsstring.c create mode 100755 programs/develop/kosjs/libmujs/jsvalue.c rename programs/develop/kosjs/libmujs/{include => }/jsvalue.h (98%) delete mode 100755 programs/develop/kosjs/libmujs/lib/libmujs.a rename programs/develop/kosjs/libmujs/{include => }/mujs.h (100%) rename programs/develop/kosjs/libmujs/{include => }/opnames.h (100%) create mode 100755 programs/develop/kosjs/libmujs/pp.c create mode 100755 programs/develop/kosjs/libmujs/regexp.c rename programs/develop/kosjs/libmujs/{include => }/regexp.h (100%) create mode 100755 programs/develop/kosjs/libmujs/utf.c rename programs/develop/kosjs/libmujs/{include => }/utf.h (89%) create mode 100755 programs/develop/kosjs/libmujs/utftype.c diff --git a/programs/develop/kosjs/Makefile b/programs/develop/kosjs/Makefile index e024d89922..354584325e 100755 --- a/programs/develop/kosjs/Makefile +++ b/programs/develop/kosjs/Makefile @@ -8,9 +8,9 @@ NAME = kosjs SDK_DIR = ../../../contrib/sdk LDFLAGS = -call_shared -nostdlib -T $(SDK_DIR)/sources/newlib/app-dynamic.lds --image-base 0 -LIBPATH = -L$(SDK_DIR)/lib -L/home/autobuild/tools/win32/mingw32/lib -L libmujs/lib +LIBPATH = -L$(SDK_DIR)/lib -L/home/autobuild/tools/win32/mingw32/lib -L libmujs CFLAGS = -c -fno-ident -O2 -fomit-frame-pointer -fno-ident -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -INCLUDES = -I $(SDK_DIR)/sources/newlib/libc/include -I libmujs/include +INCLUDES = -I $(SDK_DIR)/sources/newlib/libc/include -I libmujs all: $(CC) $(CFLAGS) $(INCLUDES) kosjs.c import.c diff --git a/programs/develop/kosjs/kosjs.c b/programs/develop/kosjs/kosjs.c index 4d395a1323..c27b260e42 100755 --- a/programs/develop/kosjs/kosjs.c +++ b/programs/develop/kosjs/kosjs.c @@ -7,8 +7,12 @@ int main(int argc, char **argv) { - import_functions(); - js_dofile(J, argv[1]); - js_freestate (J); + if (argc == 1) { + printf("usage: %s [program.js]\n", argv[0]); + } else { + import_functions(); + js_dofile(J, argv[1]); + js_freestate (J); + } exit(0); } diff --git a/programs/develop/kosjs/libmujs/AUTHORS b/programs/develop/kosjs/libmujs/AUTHORS new file mode 100755 index 0000000000..593c93ffca --- /dev/null +++ b/programs/develop/kosjs/libmujs/AUTHORS @@ -0,0 +1 @@ +Tor Andersson diff --git a/programs/develop/kosjs/libmujs/COPYING b/programs/develop/kosjs/libmujs/COPYING new file mode 100755 index 0000000000..aa8805f288 --- /dev/null +++ b/programs/develop/kosjs/libmujs/COPYING @@ -0,0 +1,16 @@ +ISC License + +Copyright (c) 2013-2020 Artifex Software, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + diff --git a/programs/develop/kosjs/libmujs/Makefile b/programs/develop/kosjs/libmujs/Makefile new file mode 100755 index 0000000000..538d91575a --- /dev/null +++ b/programs/develop/kosjs/libmujs/Makefile @@ -0,0 +1,16 @@ +CC = kos32-gcc + +SDK_DIR = ../../../../contrib/sdk +CFLAGS = -c -fno-ident -O2 -fomit-frame-pointer -fno-ident -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 + +INCLUDES = -I $(SDK_DIR)/sources/newlib/libc/include -I . + +SRC := $(notdir $(wildcard *.c)) +OBJECTS = $(patsubst %.c, %.o, $(SRC)) + +default: $(patsubst %.c,%.o,$(SRC)) + ar rcs libmujs.a *.o + rm *.o + +%.o : %.c Makefile $(SRC) + $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< diff --git a/programs/develop/kosjs/libmujs/README b/programs/develop/kosjs/libmujs/README new file mode 100755 index 0000000000..7576d46dbf --- /dev/null +++ b/programs/develop/kosjs/libmujs/README @@ -0,0 +1,52 @@ +MuJS: an embeddable Javascript interpreter in C. + +ABOUT + +MuJS is a lightweight Javascript interpreter designed for embedding in +other software to extend them with scripting capabilities. + +LICENSE + +MuJS is Copyright 2013-2017 Artifex Software, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +The software is provided "as is" and the author disclaims all warranties with +regard to this software including all implied warranties of merchantability +and fitness. In no event shall the author be liable for any special, direct, +indirect, or consequential damages or any damages whatsoever resulting from +loss of use, data or profits, whether in an action of contract, negligence +or other tortious action, arising out of or in connection with the use or +performance of this software. + +COMPILING + +If you are building from source you can either use the provided Unix Makefile: + + make release + +Or compile the source with your preferred compiler: + + cc -O2 -c one.c -o libmujs.o + +INSTALLING + +To install the MuJS command line interpreter, static library and header file: + + make prefix=/usr/local install + +DOWNLOAD + +The latest development source is available directly from the git repository: + + git clone http://git.ghostscript.com/mujs.git + +REPORTING BUGS AND PROBLEMS + +Report bugs on the ghostscript bugzilla, with MuJS as the selected component. + + http://bugs.ghostscript.com/ + +The MuJS developers hang out on IRC in the #mupdf channel on irc.freenode.net. diff --git a/programs/develop/kosjs/libmujs/include/astnames.h b/programs/develop/kosjs/libmujs/astnames.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/astnames.h rename to programs/develop/kosjs/libmujs/astnames.h diff --git a/programs/develop/kosjs/libmujs/include/import.h b/programs/develop/kosjs/libmujs/import.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/import.h rename to programs/develop/kosjs/libmujs/import.h diff --git a/programs/develop/kosjs/libmujs/jsarray.c b/programs/develop/kosjs/libmujs/jsarray.c new file mode 100755 index 0000000000..03963cd0ba --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsarray.c @@ -0,0 +1,748 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +int js_getlength(js_State *J, int idx) +{ + int len; + js_getproperty(J, idx, "length"); + len = js_tointeger(J, -1); + js_pop(J, 1); + return len; +} + +void js_setlength(js_State *J, int idx, int len) +{ + js_pushnumber(J, len); + js_setproperty(J, idx < 0 ? idx - 1 : idx, "length"); +} + +int js_hasindex(js_State *J, int idx, int i) +{ + char buf[32]; + return js_hasproperty(J, idx, js_itoa(buf, i)); +} + +void js_getindex(js_State *J, int idx, int i) +{ + char buf[32]; + js_getproperty(J, idx, js_itoa(buf, i)); +} + +void js_setindex(js_State *J, int idx, int i) +{ + char buf[32]; + js_setproperty(J, idx, js_itoa(buf, i)); +} + +void js_delindex(js_State *J, int idx, int i) +{ + char buf[32]; + js_delproperty(J, idx, js_itoa(buf, i)); +} + +static void jsB_new_Array(js_State *J) +{ + int i, top = js_gettop(J); + + js_newarray(J); + + if (top == 2) { + if (js_isnumber(J, 1)) { + js_copy(J, 1); + js_setproperty(J, -2, "length"); + } else { + js_copy(J, 1); + js_setindex(J, -2, 0); + } + } else { + for (i = 1; i < top; ++i) { + js_copy(J, i); + js_setindex(J, -2, i - 1); + } + } +} + +static void Ap_concat(js_State *J) +{ + int i, top = js_gettop(J); + int n, k, len; + + js_newarray(J); + n = 0; + + for (i = 0; i < top; ++i) { + js_copy(J, i); + if (js_isarray(J, -1)) { + len = js_getlength(J, -1); + for (k = 0; k < len; ++k) + if (js_hasindex(J, -1, k)) + js_setindex(J, -3, n++); + js_pop(J, 1); + } else { + js_setindex(J, -2, n++); + } + } +} + +static void Ap_join(js_State *J) +{ + char * volatile out = NULL; + const char *sep; + const char *r; + int seplen; + int k, n, len; + + len = js_getlength(J, 0); + + if (js_isdefined(J, 1)) { + sep = js_tostring(J, 1); + seplen = strlen(sep); + } else { + sep = ","; + seplen = 1; + } + + if (len == 0) { + js_pushliteral(J, ""); + return; + } + + if (js_try(J)) { + js_free(J, out); + js_throw(J); + } + + n = 1; + for (k = 0; k < len; ++k) { + js_getindex(J, 0, k); + if (js_isundefined(J, -1) || js_isnull(J, -1)) + r = ""; + else + r = js_tostring(J, -1); + n += strlen(r); + + if (k == 0) { + out = js_malloc(J, n); + strcpy(out, r); + } else { + n += seplen; + out = js_realloc(J, out, n); + strcat(out, sep); + strcat(out, r); + } + + js_pop(J, 1); + } + + js_pushstring(J, out); + js_endtry(J); + js_free(J, out); +} + +static void Ap_pop(js_State *J) +{ + int n; + + n = js_getlength(J, 0); + + if (n > 0) { + js_getindex(J, 0, n - 1); + js_delindex(J, 0, n - 1); + js_setlength(J, 0, n - 1); + } else { + js_setlength(J, 0, 0); + js_pushundefined(J); + } +} + +static void Ap_push(js_State *J) +{ + int i, top = js_gettop(J); + int n; + + n = js_getlength(J, 0); + + for (i = 1; i < top; ++i, ++n) { + js_copy(J, i); + js_setindex(J, 0, n); + } + + js_setlength(J, 0, n); + + js_pushnumber(J, n); +} + +static void Ap_reverse(js_State *J) +{ + int len, middle, lower; + + len = js_getlength(J, 0); + middle = len / 2; + lower = 0; + + while (lower != middle) { + int upper = len - lower - 1; + int haslower = js_hasindex(J, 0, lower); + int hasupper = js_hasindex(J, 0, upper); + if (haslower && hasupper) { + js_setindex(J, 0, lower); + js_setindex(J, 0, upper); + } else if (hasupper) { + js_setindex(J, 0, lower); + js_delindex(J, 0, upper); + } else if (haslower) { + js_setindex(J, 0, upper); + js_delindex(J, 0, lower); + } + ++lower; + } + + js_copy(J, 0); +} + +static void Ap_shift(js_State *J) +{ + int k, len; + + len = js_getlength(J, 0); + + if (len == 0) { + js_setlength(J, 0, 0); + js_pushundefined(J); + return; + } + + js_getindex(J, 0, 0); + + for (k = 1; k < len; ++k) { + if (js_hasindex(J, 0, k)) + js_setindex(J, 0, k - 1); + else + js_delindex(J, 0, k - 1); + } + + js_delindex(J, 0, len - 1); + js_setlength(J, 0, len - 1); +} + +static void Ap_slice(js_State *J) +{ + int len, s, e, n; + double sv, ev; + + js_newarray(J); + + len = js_getlength(J, 0); + sv = js_tointeger(J, 1); + ev = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; + + if (sv < 0) sv = sv + len; + if (ev < 0) ev = ev + len; + + s = sv < 0 ? 0 : sv > len ? len : sv; + e = ev < 0 ? 0 : ev > len ? len : ev; + + for (n = 0; s < e; ++s, ++n) + if (js_hasindex(J, 0, s)) + js_setindex(J, -2, n); +} + +struct sortslot { + js_Value v; + js_State *J; +}; + +static int sortcmp(const void *avoid, const void *bvoid) +{ + const struct sortslot *aslot = avoid, *bslot = bvoid; + const js_Value *a = &aslot->v, *b = &bslot->v; + js_State *J = aslot->J; + const char *sx, *sy; + double v; + int c; + + int unx = (a->type == JS_TUNDEFINED); + int uny = (b->type == JS_TUNDEFINED); + if (unx) return !uny; + if (uny) return -1; + + if (js_iscallable(J, 1)) { + js_copy(J, 1); /* copy function */ + js_pushundefined(J); + js_pushvalue(J, *a); + js_pushvalue(J, *b); + js_call(J, 2); + v = js_tonumber(J, -1); + c = (v == 0) ? 0 : (v < 0) ? -1 : 1; + js_pop(J, 1); + } else { + js_pushvalue(J, *a); + js_pushvalue(J, *b); + sx = js_tostring(J, -2); + sy = js_tostring(J, -1); + c = strcmp(sx, sy); + js_pop(J, 2); + } + return c; +} + +static void Ap_sort(js_State *J) +{ + struct sortslot *array = NULL; + int i, n, len; + + len = js_getlength(J, 0); + if (len <= 0) { + js_copy(J, 0); + return; + } + + if (len >= INT_MAX / (int)sizeof(*array)) + js_rangeerror(J, "array is too large to sort"); + + array = js_malloc(J, len * sizeof *array); + + /* Holding objects where the GC cannot see them is illegal, but if we + * don't allow the GC to run we can use qsort() on a temporary array of + * js_Values for fast sorting. + */ + ++J->gcpause; + + if (js_try(J)) { + --J->gcpause; + js_free(J, array); + js_throw(J); + } + + n = 0; + for (i = 0; i < len; ++i) { + if (js_hasindex(J, 0, i)) { + array[n].v = *js_tovalue(J, -1); + array[n].J = J; + js_pop(J, 1); + ++n; + } + } + + qsort(array, n, sizeof *array, sortcmp); + + for (i = 0; i < n; ++i) { + js_pushvalue(J, array[i].v); + js_setindex(J, 0, i); + } + for (i = n; i < len; ++i) { + js_delindex(J, 0, i); + } + + --J->gcpause; + + js_endtry(J); + js_free(J, array); + + js_copy(J, 0); +} + +static void Ap_splice(js_State *J) +{ + int top = js_gettop(J); + int len, start, del, add, k; + double f; + + js_newarray(J); + + len = js_getlength(J, 0); + + f = js_tointeger(J, 1); + if (f < 0) f = f + len; + start = f < 0 ? 0 : f > len ? len : f; + + f = js_tointeger(J, 2); + del = f < 0 ? 0 : f > len - start ? len - start : f; + + /* copy deleted items to return array */ + for (k = 0; k < del; ++k) + if (js_hasindex(J, 0, start + k)) + js_setindex(J, -2, k); + js_setlength(J, -1, del); + + /* shift the tail to resize the hole left by deleted items */ + add = top - 3; + if (add < del) { + for (k = start; k < len - del; ++k) { + if (js_hasindex(J, 0, k + del)) + js_setindex(J, 0, k + add); + else + js_delindex(J, 0, k + add); + } + for (k = len; k > len - del + add; --k) + js_delindex(J, 0, k - 1); + } else if (add > del) { + for (k = len - del; k > start; --k) { + if (js_hasindex(J, 0, k + del - 1)) + js_setindex(J, 0, k + add - 1); + else + js_delindex(J, 0, k + add - 1); + } + } + + /* copy new items into the hole */ + for (k = 0; k < add; ++k) { + js_copy(J, 3 + k); + js_setindex(J, 0, start + k); + } + + js_setlength(J, 0, len - del + add); +} + +static void Ap_unshift(js_State *J) +{ + int i, top = js_gettop(J); + int k, len; + + len = js_getlength(J, 0); + + for (k = len; k > 0; --k) { + int from = k - 1; + int to = k + top - 2; + if (js_hasindex(J, 0, from)) + js_setindex(J, 0, to); + else + js_delindex(J, 0, to); + } + + for (i = 1; i < top; ++i) { + js_copy(J, i); + js_setindex(J, 0, i - 1); + } + + js_setlength(J, 0, len + top - 1); + + js_pushnumber(J, len + top - 1); +} + +static void Ap_toString(js_State *J) +{ + int top = js_gettop(J); + js_pop(J, top - 1); + Ap_join(J); +} + +static void Ap_indexOf(js_State *J) +{ + int k, len, from; + + len = js_getlength(J, 0); + from = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0; + if (from < 0) from = len + from; + if (from < 0) from = 0; + + js_copy(J, 1); + for (k = from; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + if (js_strictequal(J)) { + js_pushnumber(J, k); + return; + } + js_pop(J, 1); + } + } + + js_pushnumber(J, -1); +} + +static void Ap_lastIndexOf(js_State *J) +{ + int k, len, from; + + len = js_getlength(J, 0); + from = js_isdefined(J, 2) ? js_tointeger(J, 2) : len - 1; + if (from > len - 1) from = len - 1; + if (from < 0) from = len + from; + + js_copy(J, 1); + for (k = from; k >= 0; --k) { + if (js_hasindex(J, 0, k)) { + if (js_strictequal(J)) { + js_pushnumber(J, k); + return; + } + js_pop(J, 1); + } + } + + js_pushnumber(J, -1); +} + +static void Ap_every(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (!js_toboolean(J, -1)) + return; + js_pop(J, 2); + } + } + + js_pushboolean(J, 1); +} + +static void Ap_some(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (js_toboolean(J, -1)) + return; + js_pop(J, 2); + } + } + + js_pushboolean(J, 0); +} + +static void Ap_forEach(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + js_pop(J, 2); + } + } + + js_pushundefined(J); +} + +static void Ap_map(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + js_newarray(J); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + js_setindex(J, -3, k); + js_pop(J, 1); + } + } +} + +static void Ap_filter(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, to, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + js_newarray(J); + to = 0; + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (js_toboolean(J, -1)) { + js_pop(J, 1); + js_setindex(J, -2, to++); + } else { + js_pop(J, 2); + } + } + } +} + +static void Ap_reduce(js_State *J) +{ + int hasinitial = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + k = 0; + + if (len == 0 && !hasinitial) + js_typeerror(J, "no initial value"); + + /* initial value of accumulator */ + if (hasinitial) + js_copy(J, 2); + else { + while (k < len) + if (js_hasindex(J, 0, k++)) + break; + if (k == len) + js_typeerror(J, "no initial value"); + } + + while (k < len) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + js_pushundefined(J); + js_rot(J, 4); /* accumulator on top */ + js_rot(J, 4); /* property on top */ + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 4); /* calculate new accumulator */ + } + ++k; + } + + /* return accumulator */ +} + +static void Ap_reduceRight(js_State *J) +{ + int hasinitial = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + k = len - 1; + + if (len == 0 && !hasinitial) + js_typeerror(J, "no initial value"); + + /* initial value of accumulator */ + if (hasinitial) + js_copy(J, 2); + else { + while (k >= 0) + if (js_hasindex(J, 0, k--)) + break; + if (k < 0) + js_typeerror(J, "no initial value"); + } + + while (k >= 0) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + js_pushundefined(J); + js_rot(J, 4); /* accumulator on top */ + js_rot(J, 4); /* property on top */ + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 4); /* calculate new accumulator */ + } + --k; + } + + /* return accumulator */ +} + +static void A_isArray(js_State *J) +{ + if (js_isobject(J, 1)) { + js_Object *T = js_toobject(J, 1); + js_pushboolean(J, T->type == JS_CARRAY); + } else { + js_pushboolean(J, 0); + } +} + +void jsB_initarray(js_State *J) +{ + js_pushobject(J, J->Array_prototype); + { + jsB_propf(J, "Array.prototype.toString", Ap_toString, 0); + jsB_propf(J, "Array.prototype.concat", Ap_concat, 0); /* 1 */ + jsB_propf(J, "Array.prototype.join", Ap_join, 1); + jsB_propf(J, "Array.prototype.pop", Ap_pop, 0); + jsB_propf(J, "Array.prototype.push", Ap_push, 0); /* 1 */ + jsB_propf(J, "Array.prototype.reverse", Ap_reverse, 0); + jsB_propf(J, "Array.prototype.shift", Ap_shift, 0); + jsB_propf(J, "Array.prototype.slice", Ap_slice, 2); + jsB_propf(J, "Array.prototype.sort", Ap_sort, 1); + jsB_propf(J, "Array.prototype.splice", Ap_splice, 0); /* 2 */ + jsB_propf(J, "Array.prototype.unshift", Ap_unshift, 0); /* 1 */ + + /* ES5 */ + jsB_propf(J, "Array.prototype.indexOf", Ap_indexOf, 1); + jsB_propf(J, "Array.prototype.lastIndexOf", Ap_lastIndexOf, 1); + jsB_propf(J, "Array.prototype.every", Ap_every, 1); + jsB_propf(J, "Array.prototype.some", Ap_some, 1); + jsB_propf(J, "Array.prototype.forEach", Ap_forEach, 1); + jsB_propf(J, "Array.prototype.map", Ap_map, 1); + jsB_propf(J, "Array.prototype.filter", Ap_filter, 1); + jsB_propf(J, "Array.prototype.reduce", Ap_reduce, 1); + jsB_propf(J, "Array.prototype.reduceRight", Ap_reduceRight, 1); + } + js_newcconstructor(J, jsB_new_Array, jsB_new_Array, "Array", 0); /* 1 */ + { + /* ES5 */ + jsB_propf(J, "Array.isArray", A_isArray, 1); + } + js_defglobal(J, "Array", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsboolean.c b/programs/develop/kosjs/libmujs/jsboolean.c new file mode 100755 index 0000000000..ae37768932 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsboolean.c @@ -0,0 +1,40 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +static void jsB_new_Boolean(js_State *J) +{ + js_newboolean(J, js_toboolean(J, 1)); +} + +static void jsB_Boolean(js_State *J) +{ + js_pushboolean(J, js_toboolean(J, 1)); +} + +static void Bp_toString(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean"); + js_pushliteral(J, self->u.boolean ? "true" : "false"); +} + +static void Bp_valueOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean"); + js_pushboolean(J, self->u.boolean); +} + +void jsB_initboolean(js_State *J) +{ + J->Boolean_prototype->u.boolean = 0; + + js_pushobject(J, J->Boolean_prototype); + { + jsB_propf(J, "Boolean.prototype.toString", Bp_toString, 0); + jsB_propf(J, "Boolean.prototype.valueOf", Bp_valueOf, 0); + } + js_newcconstructor(J, jsB_Boolean, jsB_new_Boolean, "Boolean", 1); + js_defglobal(J, "Boolean", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsbuiltin.c b/programs/develop/kosjs/libmujs/jsbuiltin.c new file mode 100755 index 0000000000..4d083c0b3f --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsbuiltin.c @@ -0,0 +1,245 @@ +#include "jsi.h" +#include "jslex.h" +#include "jscompile.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +static void jsB_globalf(js_State *J, const char *name, js_CFunction cfun, int n) +{ + js_newcfunction(J, cfun, name, n); + js_defglobal(J, name, JS_DONTENUM); +} + +void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n) +{ + const char *pname = strrchr(name, '.'); + pname = pname ? pname + 1 : name; + js_newcfunction(J, cfun, name, n); + js_defproperty(J, -2, pname, JS_DONTENUM); +} + +void jsB_propn(js_State *J, const char *name, double number) +{ + js_pushnumber(J, number); + js_defproperty(J, -2, name, JS_READONLY | JS_DONTENUM | JS_DONTCONF); +} + +void jsB_props(js_State *J, const char *name, const char *string) +{ + js_pushliteral(J, string); + js_defproperty(J, -2, name, JS_DONTENUM); +} + +static void jsB_parseInt(js_State *J) +{ + const char *s = js_tostring(J, 1); + int radix = js_isdefined(J, 2) ? js_tointeger(J, 2) : 10; + double sign = 1; + double n; + char *e; + + while (jsY_iswhite(*s) || jsY_isnewline(*s)) + ++s; + if (*s == '-') { + ++s; + sign = -1; + } else if (*s == '+') { + ++s; + } + if (radix == 0) { + radix = 10; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + s += 2; + radix = 16; + } + } else if (radix < 2 || radix > 36) { + js_pushnumber(J, NAN); + return; + } + n = strtol(s, &e, radix); + if (s == e) + js_pushnumber(J, NAN); + else + js_pushnumber(J, n * sign); +} + +static void jsB_parseFloat(js_State *J) +{ + const char *s = js_tostring(J, 1); + char *e; + double n; + + while (jsY_iswhite(*s) || jsY_isnewline(*s)) ++s; + if (!strncmp(s, "Infinity", 8)) + js_pushnumber(J, INFINITY); + else if (!strncmp(s, "+Infinity", 9)) + js_pushnumber(J, INFINITY); + else if (!strncmp(s, "-Infinity", 9)) + js_pushnumber(J, -INFINITY); + else { + n = js_stringtofloat(s, &e); + if (e == s) + js_pushnumber(J, NAN); + else + js_pushnumber(J, n); + } +} + +static void jsB_isNaN(js_State *J) +{ + double n = js_tonumber(J, 1); + js_pushboolean(J, isnan(n)); +} + +static void jsB_isFinite(js_State *J) +{ + double n = js_tonumber(J, 1); + js_pushboolean(J, isfinite(n)); +} + +static void Encode(js_State *J, const char *str, const char *unescaped) +{ + js_Buffer *sb = NULL; + + static const char *HEX = "0123456789ABCDEF"; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + while (*str) { + int c = (unsigned char) *str++; + if (strchr(unescaped, c)) + js_putc(J, &sb, c); + else { + js_putc(J, &sb, '%'); + js_putc(J, &sb, HEX[(c >> 4) & 0xf]); + js_putc(J, &sb, HEX[c & 0xf]); + } + } + js_putc(J, &sb, 0); + + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +static void Decode(js_State *J, const char *str, const char *reserved) +{ + js_Buffer *sb = NULL; + int a, b; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + while (*str) { + int c = (unsigned char) *str++; + if (c != '%') + js_putc(J, &sb, c); + else { + if (!str[0] || !str[1]) + js_urierror(J, "truncated escape sequence"); + a = *str++; + b = *str++; + if (!jsY_ishex(a) || !jsY_ishex(b)) + js_urierror(J, "invalid escape sequence"); + c = jsY_tohex(a) << 4 | jsY_tohex(b); + if (!strchr(reserved, c)) + js_putc(J, &sb, c); + else { + js_putc(J, &sb, '%'); + js_putc(J, &sb, a); + js_putc(J, &sb, b); + } + } + } + js_putc(J, &sb, 0); + + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +#define URIRESERVED ";/?:@&=+$," +#define URIALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define URIDIGIT "0123456789" +#define URIMARK "-_.!~*`()" +#define URIUNESCAPED URIALPHA URIDIGIT URIMARK + +static void jsB_decodeURI(js_State *J) +{ + Decode(J, js_tostring(J, 1), URIRESERVED "#"); +} + +static void jsB_decodeURIComponent(js_State *J) +{ + Decode(J, js_tostring(J, 1), ""); +} + +static void jsB_encodeURI(js_State *J) +{ + Encode(J, js_tostring(J, 1), URIUNESCAPED URIRESERVED "#"); +} + +static void jsB_encodeURIComponent(js_State *J) +{ + Encode(J, js_tostring(J, 1), URIUNESCAPED); +} + +void jsB_init(js_State *J) +{ + /* Create the prototype objects here, before the constructors */ + J->Object_prototype = jsV_newobject(J, JS_COBJECT, NULL); + J->Array_prototype = jsV_newobject(J, JS_CARRAY, J->Object_prototype); + J->Function_prototype = jsV_newobject(J, JS_CCFUNCTION, J->Object_prototype); + J->Boolean_prototype = jsV_newobject(J, JS_CBOOLEAN, J->Object_prototype); + J->Number_prototype = jsV_newobject(J, JS_CNUMBER, J->Object_prototype); + J->String_prototype = jsV_newobject(J, JS_CSTRING, J->Object_prototype); + J->RegExp_prototype = jsV_newobject(J, JS_COBJECT, J->Object_prototype); + J->Date_prototype = jsV_newobject(J, JS_CDATE, J->Object_prototype); + + /* All the native error types */ + J->Error_prototype = jsV_newobject(J, JS_CERROR, J->Object_prototype); + J->EvalError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->RangeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->ReferenceError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->SyntaxError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->TypeError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + J->URIError_prototype = jsV_newobject(J, JS_CERROR, J->Error_prototype); + + /* Create the constructors and fill out the prototype objects */ + jsB_initobject(J); + jsB_initarray(J); + jsB_initfunction(J); + jsB_initboolean(J); + jsB_initnumber(J); + jsB_initstring(J); + jsB_initregexp(J); + jsB_initdate(J); + jsB_initerror(J); + jsB_initmath(J); + jsB_initjson(J); + + /* Initialize the global object */ + js_pushnumber(J, NAN); + js_defglobal(J, "NaN", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + js_pushnumber(J, INFINITY); + js_defglobal(J, "Infinity", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + js_pushundefined(J); + js_defglobal(J, "undefined", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + jsB_globalf(J, "parseInt", jsB_parseInt, 1); + jsB_globalf(J, "parseFloat", jsB_parseFloat, 1); + jsB_globalf(J, "isNaN", jsB_isNaN, 1); + jsB_globalf(J, "isFinite", jsB_isFinite, 1); + + jsB_globalf(J, "decodeURI", jsB_decodeURI, 1); + jsB_globalf(J, "decodeURIComponent", jsB_decodeURIComponent, 1); + jsB_globalf(J, "encodeURI", jsB_encodeURI, 1); + jsB_globalf(J, "encodeURIComponent", jsB_encodeURIComponent, 1); +} diff --git a/programs/develop/kosjs/libmujs/include/jsbuiltin.h b/programs/develop/kosjs/libmujs/jsbuiltin.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/jsbuiltin.h rename to programs/develop/kosjs/libmujs/jsbuiltin.h diff --git a/programs/develop/kosjs/libmujs/jscompile.c b/programs/develop/kosjs/libmujs/jscompile.c new file mode 100755 index 0000000000..1bb3fbef07 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jscompile.c @@ -0,0 +1,1447 @@ +#include "jsi.h" +#include "jslex.h" +#include "jsparse.h" +#include "jscompile.h" +#include "jsvalue.h" /* for jsV_numbertostring */ + +#define cexp jsC_cexp /* collision with math.h */ + +#define JF js_State *J, js_Function *F + +JS_NORETURN void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) JS_PRINTFLIKE(3,4); + +static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body); +static void cexp(JF, js_Ast *exp); +static void cstmlist(JF, js_Ast *list); +static void cstm(JF, js_Ast *stm); + +void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + snprintf(buf, 256, "%s:%d: ", J->filename, node->line); + strcat(buf, msgbuf); + + js_newsyntaxerror(J, buf); + js_throw(J); +} + +static const char *futurewords[] = { + "class", "const", "enum", "export", "extends", "import", "super", +}; + +static const char *strictfuturewords[] = { + "implements", "interface", "let", "package", "private", "protected", + "public", "static", "yield", +}; + +static void checkfutureword(JF, js_Ast *exp) +{ + if (jsY_findword(exp->string, futurewords, nelem(futurewords)) >= 0) + jsC_error(J, exp, "'%s' is a future reserved word", exp->string); + if (F->strict) { + if (jsY_findword(exp->string, strictfuturewords, nelem(strictfuturewords)) >= 0) + jsC_error(J, exp, "'%s' is a strict mode future reserved word", exp->string); + } +} + +static js_Function *newfun(js_State *J, int line, js_Ast *name, js_Ast *params, js_Ast *body, int script, int default_strict) +{ + js_Function *F = js_malloc(J, sizeof *F); + memset(F, 0, sizeof *F); + F->gcmark = 0; + F->gcnext = J->gcfun; + J->gcfun = F; + ++J->gccounter; + + F->filename = js_intern(J, J->filename); + F->line = line; + F->script = script; + F->strict = default_strict; + F->name = name ? name->string : ""; + + cfunbody(J, F, name, params, body); + + return F; +} + +/* Emit opcodes, constants and jumps */ + +static void emitraw(JF, int value) +{ + if (value != (js_Instruction)value) + js_syntaxerror(J, "integer overflow in instruction coding"); + if (F->codelen >= F->codecap) { + F->codecap = F->codecap ? F->codecap * 2 : 64; + F->code = js_realloc(J, F->code, F->codecap * sizeof *F->code); + } + F->code[F->codelen++] = value; +} + +static void emit(JF, int value) +{ + emitraw(J, F, F->lastline); + emitraw(J, F, value); +} + +static void emitarg(JF, int value) +{ + emitraw(J, F, value); +} + +static void emitline(JF, js_Ast *node) +{ + F->lastline = node->line; +} + +static int addfunction(JF, js_Function *value) +{ + if (F->funlen >= F->funcap) { + F->funcap = F->funcap ? F->funcap * 2 : 16; + F->funtab = js_realloc(J, F->funtab, F->funcap * sizeof *F->funtab); + } + F->funtab[F->funlen] = value; + return F->funlen++; +} + +static int addnumber(JF, double value) +{ + int i; + for (i = 0; i < F->numlen; ++i) + if (F->numtab[i] == value) + return i; + if (F->numlen >= F->numcap) { + F->numcap = F->numcap ? F->numcap * 2 : 16; + F->numtab = js_realloc(J, F->numtab, F->numcap * sizeof *F->numtab); + } + F->numtab[F->numlen] = value; + return F->numlen++; +} + +static int addstring(JF, const char *value) +{ + int i; + for (i = 0; i < F->strlen; ++i) + if (!strcmp(F->strtab[i], value)) + return i; + if (F->strlen >= F->strcap) { + F->strcap = F->strcap ? F->strcap * 2 : 16; + F->strtab = js_realloc(J, F->strtab, F->strcap * sizeof *F->strtab); + } + F->strtab[F->strlen] = value; + return F->strlen++; +} + +static int addlocal(JF, js_Ast *ident, int reuse) +{ + const char *name = ident->string; + if (F->strict) { + if (!strcmp(name, "arguments")) + jsC_error(J, ident, "redefining 'arguments' is not allowed in strict mode"); + if (!strcmp(name, "eval")) + jsC_error(J, ident, "redefining 'eval' is not allowed in strict mode"); + } else { + if (!strcmp(name, "eval")) + js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line); + } + if (reuse || F->strict) { + int i; + for (i = 0; i < F->varlen; ++i) { + if (!strcmp(F->vartab[i], name)) { + if (reuse) + return i+1; + if (F->strict) + jsC_error(J, ident, "duplicate formal parameter '%s'", name); + } + } + } + if (F->varlen >= F->varcap) { + F->varcap = F->varcap ? F->varcap * 2 : 16; + F->vartab = js_realloc(J, F->vartab, F->varcap * sizeof *F->vartab); + } + F->vartab[F->varlen] = name; + return ++F->varlen; +} + +static int findlocal(JF, const char *name) +{ + int i; + for (i = F->varlen; i > 0; --i) + if (!strcmp(F->vartab[i-1], name)) + return i; + return -1; +} + +static void emitfunction(JF, js_Function *fun) +{ + F->lightweight = 0; + emit(J, F, OP_CLOSURE); + emitarg(J, F, addfunction(J, F, fun)); +} + +static void emitnumber(JF, double num) +{ + if (num == 0) { + emit(J, F, OP_INTEGER); + emitarg(J, F, 32768); + if (signbit(num)) + emit(J, F, OP_NEG); + } else if (num >= SHRT_MIN && num <= SHRT_MAX && num == (int)num) { + emit(J, F, OP_INTEGER); + emitarg(J, F, num + 32768); + } else { + emit(J, F, OP_NUMBER); + emitarg(J, F, addnumber(J, F, num)); + } +} + +static void emitstring(JF, int opcode, const char *str) +{ + emit(J, F, opcode); + emitarg(J, F, addstring(J, F, str)); +} + +static void emitlocal(JF, int oploc, int opvar, js_Ast *ident) +{ + int is_arguments = !strcmp(ident->string, "arguments"); + int is_eval = !strcmp(ident->string, "eval"); + int i; + + if (is_arguments) { + F->lightweight = 0; + F->arguments = 1; + } + + checkfutureword(J, F, ident); + if (F->strict && oploc == OP_SETLOCAL) { + if (is_arguments) + jsC_error(J, ident, "'arguments' is read-only in strict mode"); + if (is_eval) + jsC_error(J, ident, "'eval' is read-only in strict mode"); + } + if (is_eval) + js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line); + + i = findlocal(J, F, ident->string); + if (i < 0) { + emitstring(J, F, opvar, ident->string); + } else { + emit(J, F, oploc); + emitarg(J, F, i); + } +} + +static int here(JF) +{ + return F->codelen; +} + +static int emitjump(JF, int opcode) +{ + int inst; + emit(J, F, opcode); + inst = F->codelen; + emitarg(J, F, 0); + return inst; +} + +static void emitjumpto(JF, int opcode, int dest) +{ + emit(J, F, opcode); + if (dest != (js_Instruction)dest) + js_syntaxerror(J, "jump address integer overflow"); + emitarg(J, F, dest); +} + +static void labelto(JF, int inst, int addr) +{ + if (addr != (js_Instruction)addr) + js_syntaxerror(J, "jump address integer overflow"); + F->code[inst] = addr; +} + +static void label(JF, int inst) +{ + labelto(J, F, inst, F->codelen); +} + +/* Expressions */ + +static void ctypeof(JF, js_Ast *exp) +{ + if (exp->a->type == EXP_IDENTIFIER) { + emitline(J, F, exp->a); + emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp->a); + } else { + cexp(J, F, exp->a); + } + emitline(J, F, exp); + emit(J, F, OP_TYPEOF); +} + +static void cunary(JF, js_Ast *exp, int opcode) +{ + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, opcode); +} + +static void cbinary(JF, js_Ast *exp, int opcode) +{ + cexp(J, F, exp->a); + cexp(J, F, exp->b); + emitline(J, F, exp); + emit(J, F, opcode); +} + +static void carray(JF, js_Ast *list) +{ + int i = 0; + while (list) { + if (list->a->type != EXP_UNDEF) { + emitline(J, F, list->a); + emitnumber(J, F, i++); + cexp(J, F, list->a); + emitline(J, F, list->a); + emit(J, F, OP_INITPROP); + } else { + ++i; + } + list = list->b; + } +} + +static void checkdup(JF, js_Ast *list, js_Ast *end) +{ + char nbuf[32], sbuf[32]; + const char *needle, *straw; + + if (end->a->type == EXP_NUMBER) + needle = jsV_numbertostring(J, nbuf, end->a->number); + else + needle = end->a->string; + + while (list->a != end) { + if (list->a->type == end->type) { + js_Ast *prop = list->a->a; + if (prop->type == EXP_NUMBER) + straw = jsV_numbertostring(J, sbuf, prop->number); + else + straw = prop->string; + if (!strcmp(needle, straw)) + jsC_error(J, list, "duplicate property '%s' in object literal", needle); + } + list = list->b; + } +} + +static void cobject(JF, js_Ast *list) +{ + js_Ast *head = list; + + while (list) { + js_Ast *kv = list->a; + js_Ast *prop = kv->a; + + if (prop->type == AST_IDENTIFIER || prop->type == EXP_STRING) { + emitline(J, F, prop); + emitstring(J, F, OP_STRING, prop->string); + } else if (prop->type == EXP_NUMBER) { + emitline(J, F, prop); + emitnumber(J, F, prop->number); + } else { + jsC_error(J, prop, "invalid property name in object initializer"); + } + + if (F->strict) + checkdup(J, F, head, kv); + + switch (kv->type) { + default: /* impossible */ break; + case EXP_PROP_VAL: + cexp(J, F, kv->b); + emitline(J, F, kv); + emit(J, F, OP_INITPROP); + break; + case EXP_PROP_GET: + emitfunction(J, F, newfun(J, prop->line, NULL, NULL, kv->c, 0, F->strict)); + emitline(J, F, kv); + emit(J, F, OP_INITGETTER); + break; + case EXP_PROP_SET: + emitfunction(J, F, newfun(J, prop->line, NULL, kv->b, kv->c, 0, F->strict)); + emitline(J, F, kv); + emit(J, F, OP_INITSETTER); + break; + } + + list = list->b; + } +} + +static int cargs(JF, js_Ast *list) +{ + int n = 0; + while (list) { + cexp(J, F, list->a); + list = list->b; + ++n; + } + return n; +} + +static void cassign(JF, js_Ast *exp) +{ + js_Ast *lhs = exp->a; + js_Ast *rhs = exp->b; + switch (lhs->type) { + case EXP_IDENTIFIER: + cexp(J, F, rhs); + emitline(J, F, exp); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs); + break; + case EXP_INDEX: + cexp(J, F, lhs->a); + cexp(J, F, lhs->b); + cexp(J, F, rhs); + emitline(J, F, exp); + emit(J, F, OP_SETPROP); + break; + case EXP_MEMBER: + cexp(J, F, lhs->a); + cexp(J, F, rhs); + emitline(J, F, exp); + emitstring(J, F, OP_SETPROP_S, lhs->b->string); + break; + default: + jsC_error(J, lhs, "invalid l-value in assignment"); + } +} + +static void cassignforin(JF, js_Ast *stm) +{ + js_Ast *lhs = stm->a; + + if (stm->type == STM_FOR_IN_VAR) { + if (lhs->b) + jsC_error(J, lhs->b, "more than one loop variable in for-in statement"); + emitline(J, F, lhs->a); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs->a->a); /* list(var-init(ident)) */ + emit(J, F, OP_POP); + return; + } + + switch (lhs->type) { + case EXP_IDENTIFIER: + emitline(J, F, lhs); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs); + emit(J, F, OP_POP); + break; + case EXP_INDEX: + cexp(J, F, lhs->a); + cexp(J, F, lhs->b); + emitline(J, F, lhs); + emit(J, F, OP_ROT3); + emit(J, F, OP_SETPROP); + emit(J, F, OP_POP); + break; + case EXP_MEMBER: + cexp(J, F, lhs->a); + emitline(J, F, lhs); + emit(J, F, OP_ROT2); + emitstring(J, F, OP_SETPROP_S, lhs->b->string); + emit(J, F, OP_POP); + break; + default: + jsC_error(J, lhs, "invalid l-value in for-in loop assignment"); + } +} + +static void cassignop1(JF, js_Ast *lhs) +{ + switch (lhs->type) { + case EXP_IDENTIFIER: + emitline(J, F, lhs); + emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, lhs); + break; + case EXP_INDEX: + cexp(J, F, lhs->a); + cexp(J, F, lhs->b); + emitline(J, F, lhs); + emit(J, F, OP_DUP2); + emit(J, F, OP_GETPROP); + break; + case EXP_MEMBER: + cexp(J, F, lhs->a); + emitline(J, F, lhs); + emit(J, F, OP_DUP); + emitstring(J, F, OP_GETPROP_S, lhs->b->string); + break; + default: + jsC_error(J, lhs, "invalid l-value in assignment"); + } +} + +static void cassignop2(JF, js_Ast *lhs, int postfix) +{ + switch (lhs->type) { + case EXP_IDENTIFIER: + emitline(J, F, lhs); + if (postfix) emit(J, F, OP_ROT2); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs); + break; + case EXP_INDEX: + emitline(J, F, lhs); + if (postfix) emit(J, F, OP_ROT4); + emit(J, F, OP_SETPROP); + break; + case EXP_MEMBER: + emitline(J, F, lhs); + if (postfix) emit(J, F, OP_ROT3); + emitstring(J, F, OP_SETPROP_S, lhs->b->string); + break; + default: + jsC_error(J, lhs, "invalid l-value in assignment"); + } +} + +static void cassignop(JF, js_Ast *exp, int opcode) +{ + js_Ast *lhs = exp->a; + js_Ast *rhs = exp->b; + cassignop1(J, F, lhs); + cexp(J, F, rhs); + emitline(J, F, exp); + emit(J, F, opcode); + cassignop2(J, F, lhs, 0); +} + +static void cdelete(JF, js_Ast *exp) +{ + js_Ast *arg = exp->a; + switch (arg->type) { + case EXP_IDENTIFIER: + if (F->strict) + jsC_error(J, exp, "delete on an unqualified name is not allowed in strict mode"); + emitline(J, F, exp); + emitlocal(J, F, OP_DELLOCAL, OP_DELVAR, arg); + break; + case EXP_INDEX: + cexp(J, F, arg->a); + cexp(J, F, arg->b); + emitline(J, F, exp); + emit(J, F, OP_DELPROP); + break; + case EXP_MEMBER: + cexp(J, F, arg->a); + emitline(J, F, exp); + emitstring(J, F, OP_DELPROP_S, arg->b->string); + break; + default: + jsC_error(J, exp, "invalid l-value in delete expression"); + } +} + +static void ceval(JF, js_Ast *fun, js_Ast *args) +{ + int n = cargs(J, F, args); + F->lightweight = 0; + F->arguments = 1; + if (n == 0) + emit(J, F, OP_UNDEF); + else while (n-- > 1) + emit(J, F, OP_POP); + emit(J, F, OP_EVAL); +} + +static void ccall(JF, js_Ast *fun, js_Ast *args) +{ + int n; + switch (fun->type) { + case EXP_INDEX: + cexp(J, F, fun->a); + emit(J, F, OP_DUP); + cexp(J, F, fun->b); + emit(J, F, OP_GETPROP); + emit(J, F, OP_ROT2); + break; + case EXP_MEMBER: + cexp(J, F, fun->a); + emit(J, F, OP_DUP); + emitstring(J, F, OP_GETPROP_S, fun->b->string); + emit(J, F, OP_ROT2); + break; + case EXP_IDENTIFIER: + if (!strcmp(fun->string, "eval")) { + ceval(J, F, fun, args); + return; + } + /* fallthrough */ + default: + cexp(J, F, fun); + emit(J, F, OP_UNDEF); + break; + } + n = cargs(J, F, args); + emit(J, F, OP_CALL); + emitarg(J, F, n); +} + +static void cexp(JF, js_Ast *exp) +{ + int then, end; + int n; + + switch (exp->type) { + case EXP_STRING: + emitline(J, F, exp); + emitstring(J, F, OP_STRING, exp->string); + break; + case EXP_NUMBER: + emitline(J, F, exp); + emitnumber(J, F, exp->number); + break; + case EXP_UNDEF: + emitline(J, F, exp); + emit(J, F, OP_UNDEF); + break; + case EXP_NULL: + emitline(J, F, exp); + emit(J, F, OP_NULL); + break; + case EXP_TRUE: + emitline(J, F, exp); + emit(J, F, OP_TRUE); + break; + case EXP_FALSE: + emitline(J, F, exp); + emit(J, F, OP_FALSE); + break; + case EXP_THIS: + emitline(J, F, exp); + emit(J, F, OP_THIS); + break; + + case EXP_REGEXP: + emitline(J, F, exp); + emit(J, F, OP_NEWREGEXP); + emitarg(J, F, addstring(J, F, exp->string)); + emitarg(J, F, exp->number); + break; + + case EXP_OBJECT: + emitline(J, F, exp); + emit(J, F, OP_NEWOBJECT); + cobject(J, F, exp->a); + break; + + case EXP_ARRAY: + emitline(J, F, exp); + emit(J, F, OP_NEWARRAY); + carray(J, F, exp->a); + break; + + case EXP_FUN: + emitline(J, F, exp); + emitfunction(J, F, newfun(J, exp->line, exp->a, exp->b, exp->c, 0, F->strict)); + break; + + case EXP_IDENTIFIER: + emitline(J, F, exp); + emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, exp); + break; + + case EXP_INDEX: + cexp(J, F, exp->a); + cexp(J, F, exp->b); + emitline(J, F, exp); + emit(J, F, OP_GETPROP); + break; + + case EXP_MEMBER: + cexp(J, F, exp->a); + emitline(J, F, exp); + emitstring(J, F, OP_GETPROP_S, exp->b->string); + break; + + case EXP_CALL: + ccall(J, F, exp->a, exp->b); + break; + + case EXP_NEW: + cexp(J, F, exp->a); + n = cargs(J, F, exp->b); + emitline(J, F, exp); + emit(J, F, OP_NEW); + emitarg(J, F, n); + break; + + case EXP_DELETE: + cdelete(J, F, exp); + break; + + case EXP_PREINC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_INC); + cassignop2(J, F, exp->a, 0); + break; + + case EXP_PREDEC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_DEC); + cassignop2(J, F, exp->a, 0); + break; + + case EXP_POSTINC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POSTINC); + cassignop2(J, F, exp->a, 1); + emit(J, F, OP_POP); + break; + + case EXP_POSTDEC: + cassignop1(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POSTDEC); + cassignop2(J, F, exp->a, 1); + emit(J, F, OP_POP); + break; + + case EXP_VOID: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POP); + emit(J, F, OP_UNDEF); + break; + + case EXP_TYPEOF: ctypeof(J, F, exp); break; + case EXP_POS: cunary(J, F, exp, OP_POS); break; + case EXP_NEG: cunary(J, F, exp, OP_NEG); break; + case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break; + case EXP_LOGNOT: cunary(J, F, exp, OP_LOGNOT); break; + + case EXP_BITOR: cbinary(J, F, exp, OP_BITOR); break; + case EXP_BITXOR: cbinary(J, F, exp, OP_BITXOR); break; + case EXP_BITAND: cbinary(J, F, exp, OP_BITAND); break; + case EXP_EQ: cbinary(J, F, exp, OP_EQ); break; + case EXP_NE: cbinary(J, F, exp, OP_NE); break; + case EXP_STRICTEQ: cbinary(J, F, exp, OP_STRICTEQ); break; + case EXP_STRICTNE: cbinary(J, F, exp, OP_STRICTNE); break; + case EXP_LT: cbinary(J, F, exp, OP_LT); break; + case EXP_GT: cbinary(J, F, exp, OP_GT); break; + case EXP_LE: cbinary(J, F, exp, OP_LE); break; + case EXP_GE: cbinary(J, F, exp, OP_GE); break; + case EXP_INSTANCEOF: cbinary(J, F, exp, OP_INSTANCEOF); break; + case EXP_IN: cbinary(J, F, exp, OP_IN); break; + case EXP_SHL: cbinary(J, F, exp, OP_SHL); break; + case EXP_SHR: cbinary(J, F, exp, OP_SHR); break; + case EXP_USHR: cbinary(J, F, exp, OP_USHR); break; + case EXP_ADD: cbinary(J, F, exp, OP_ADD); break; + case EXP_SUB: cbinary(J, F, exp, OP_SUB); break; + case EXP_MUL: cbinary(J, F, exp, OP_MUL); break; + case EXP_DIV: cbinary(J, F, exp, OP_DIV); break; + case EXP_MOD: cbinary(J, F, exp, OP_MOD); break; + + case EXP_ASS: cassign(J, F, exp); break; + case EXP_ASS_MUL: cassignop(J, F, exp, OP_MUL); break; + case EXP_ASS_DIV: cassignop(J, F, exp, OP_DIV); break; + case EXP_ASS_MOD: cassignop(J, F, exp, OP_MOD); break; + case EXP_ASS_ADD: cassignop(J, F, exp, OP_ADD); break; + case EXP_ASS_SUB: cassignop(J, F, exp, OP_SUB); break; + case EXP_ASS_SHL: cassignop(J, F, exp, OP_SHL); break; + case EXP_ASS_SHR: cassignop(J, F, exp, OP_SHR); break; + case EXP_ASS_USHR: cassignop(J, F, exp, OP_USHR); break; + case EXP_ASS_BITAND: cassignop(J, F, exp, OP_BITAND); break; + case EXP_ASS_BITXOR: cassignop(J, F, exp, OP_BITXOR); break; + case EXP_ASS_BITOR: cassignop(J, F, exp, OP_BITOR); break; + + case EXP_COMMA: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_POP); + cexp(J, F, exp->b); + break; + + case EXP_LOGOR: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_DUP); + end = emitjump(J, F, OP_JTRUE); + emit(J, F, OP_POP); + cexp(J, F, exp->b); + label(J, F, end); + break; + + case EXP_LOGAND: + cexp(J, F, exp->a); + emitline(J, F, exp); + emit(J, F, OP_DUP); + end = emitjump(J, F, OP_JFALSE); + emit(J, F, OP_POP); + cexp(J, F, exp->b); + label(J, F, end); + break; + + case EXP_COND: + cexp(J, F, exp->a); + emitline(J, F, exp); + then = emitjump(J, F, OP_JTRUE); + cexp(J, F, exp->c); + end = emitjump(J, F, OP_JUMP); + label(J, F, then); + cexp(J, F, exp->b); + label(J, F, end); + break; + + default: + jsC_error(J, exp, "unknown expression: (%s)", jsP_aststring(exp->type)); + } +} + +/* Patch break and continue statements */ + +static void addjump(JF, enum js_AstType type, js_Ast *target, int inst) +{ + js_JumpList *jump = js_malloc(J, sizeof *jump); + jump->type = type; + jump->inst = inst; + jump->next = target->jumps; + target->jumps = jump; +} + +static void labeljumps(JF, js_JumpList *jump, int baddr, int caddr) +{ + while (jump) { + if (jump->type == STM_BREAK) + labelto(J, F, jump->inst, baddr); + if (jump->type == STM_CONTINUE) + labelto(J, F, jump->inst, caddr); + jump = jump->next; + } +} + +static int isloop(enum js_AstType T) +{ + return T == STM_DO || T == STM_WHILE || + T == STM_FOR || T == STM_FOR_VAR || + T == STM_FOR_IN || T == STM_FOR_IN_VAR; +} + +static int isfun(enum js_AstType T) +{ + return T == AST_FUNDEC || T == EXP_FUN || T == EXP_PROP_GET || T == EXP_PROP_SET; +} + +static int matchlabel(js_Ast *node, const char *label) +{ + while (node && node->type == STM_LABEL) { + if (!strcmp(node->a->string, label)) + return 1; + node = node->parent; + } + return 0; +} + +static js_Ast *breaktarget(JF, js_Ast *node, const char *label) +{ + while (node) { + if (isfun(node->type)) + break; + if (!label) { + if (isloop(node->type) || node->type == STM_SWITCH) + return node; + } else { + if (matchlabel(node->parent, label)) + return node; + } + node = node->parent; + } + return NULL; +} + +static js_Ast *continuetarget(JF, js_Ast *node, const char *label) +{ + while (node) { + if (isfun(node->type)) + break; + if (isloop(node->type)) { + if (!label) + return node; + else if (matchlabel(node->parent, label)) + return node; + } + node = node->parent; + } + return NULL; +} + +static js_Ast *returntarget(JF, js_Ast *node) +{ + while (node) { + if (isfun(node->type)) + return node; + node = node->parent; + } + return NULL; +} + +/* Emit code to rebalance stack and scopes during an abrupt exit */ + +static void cexit(JF, enum js_AstType T, js_Ast *node, js_Ast *target) +{ + js_Ast *prev; + do { + prev = node, node = node->parent; + switch (node->type) { + default: + /* impossible */ + break; + case STM_WITH: + emitline(J, F, node); + emit(J, F, OP_ENDWITH); + break; + case STM_FOR_IN: + case STM_FOR_IN_VAR: + emitline(J, F, node); + /* pop the iterator if leaving the loop */ + if (F->script) { + if (T == STM_RETURN || T == STM_BREAK || (T == STM_CONTINUE && target != node)) { + /* pop the iterator, save the return or exp value */ + emit(J, F, OP_ROT2); + emit(J, F, OP_POP); + } + if (T == STM_CONTINUE) + emit(J, F, OP_ROT2); /* put the iterator back on top */ + } else { + if (T == STM_RETURN) { + /* pop the iterator, save the return value */ + emit(J, F, OP_ROT2); + emit(J, F, OP_POP); + } + if (T == STM_BREAK || (T == STM_CONTINUE && target != node)) + emit(J, F, OP_POP); /* pop the iterator */ + } + break; + case STM_TRY: + emitline(J, F, node); + /* came from try block */ + if (prev == node->a) { + emit(J, F, OP_ENDTRY); + if (node->d) cstm(J, F, node->d); /* finally */ + } + /* came from catch block */ + if (prev == node->c) { + /* ... with finally */ + if (node->d) { + emit(J, F, OP_ENDCATCH); + emit(J, F, OP_ENDTRY); + cstm(J, F, node->d); /* finally */ + } else { + emit(J, F, OP_ENDCATCH); + } + } + break; + } + } while (node != target); +} + +/* Try/catch/finally */ + +static void ctryfinally(JF, js_Ast *trystm, js_Ast *finallystm) +{ + int L1; + L1 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the try block */ + cstm(J, F, finallystm); /* inline finally block */ + emit(J, F, OP_THROW); /* rethrow exception */ + } + label(J, F, L1); + cstm(J, F, trystm); + emit(J, F, OP_ENDTRY); + cstm(J, F, finallystm); +} + +static void ctrycatch(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm) +{ + int L1, L2; + L1 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the try block */ + checkfutureword(J, F, catchvar); + if (F->strict) { + if (!strcmp(catchvar->string, "arguments")) + jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode"); + if (!strcmp(catchvar->string, "eval")) + jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode"); + } + emitline(J, F, catchvar); + emitstring(J, F, OP_CATCH, catchvar->string); + cstm(J, F, catchstm); + emit(J, F, OP_ENDCATCH); + L2 = emitjump(J, F, OP_JUMP); /* skip past the try block */ + } + label(J, F, L1); + cstm(J, F, trystm); + emit(J, F, OP_ENDTRY); + label(J, F, L2); +} + +static void ctrycatchfinally(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm, js_Ast *finallystm) +{ + int L1, L2, L3; + L1 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the try block */ + L2 = emitjump(J, F, OP_TRY); + { + /* if we get here, we have caught an exception in the catch block */ + cstm(J, F, finallystm); /* inline finally block */ + emit(J, F, OP_THROW); /* rethrow exception */ + } + label(J, F, L2); + if (F->strict) { + checkfutureword(J, F, catchvar); + if (!strcmp(catchvar->string, "arguments")) + jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode"); + if (!strcmp(catchvar->string, "eval")) + jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode"); + } + emitline(J, F, catchvar); + emitstring(J, F, OP_CATCH, catchvar->string); + cstm(J, F, catchstm); + emit(J, F, OP_ENDCATCH); + emit(J, F, OP_ENDTRY); + L3 = emitjump(J, F, OP_JUMP); /* skip past the try block to the finally block */ + } + label(J, F, L1); + cstm(J, F, trystm); + emit(J, F, OP_ENDTRY); + label(J, F, L3); + cstm(J, F, finallystm); +} + +/* Switch */ + +static void cswitch(JF, js_Ast *ref, js_Ast *head) +{ + js_Ast *node, *clause, *def = NULL; + int end; + + cexp(J, F, ref); + + /* emit an if-else chain of tests for the case clause expressions */ + for (node = head; node; node = node->b) { + clause = node->a; + if (clause->type == STM_DEFAULT) { + if (def) + jsC_error(J, clause, "more than one default label in switch"); + def = clause; + } else { + cexp(J, F, clause->a); + emitline(J, F, clause); + clause->casejump = emitjump(J, F, OP_JCASE); + } + } + emit(J, F, OP_POP); + if (def) { + emitline(J, F, def); + def->casejump = emitjump(J, F, OP_JUMP); + end = 0; + } else { + end = emitjump(J, F, OP_JUMP); + } + + /* emit the case clause bodies */ + for (node = head; node; node = node->b) { + clause = node->a; + label(J, F, clause->casejump); + if (clause->type == STM_DEFAULT) + cstmlist(J, F, clause->a); + else + cstmlist(J, F, clause->b); + } + + if (end) + label(J, F, end); +} + +/* Statements */ + +static void cvarinit(JF, js_Ast *list) +{ + while (list) { + js_Ast *var = list->a; + if (var->b) { + cexp(J, F, var->b); + emitline(J, F, var); + emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, var->a); + emit(J, F, OP_POP); + } + list = list->b; + } +} + +static void cstm(JF, js_Ast *stm) +{ + js_Ast *target; + int loop, cont, then, end; + + emitline(J, F, stm); + + switch (stm->type) { + case AST_FUNDEC: + break; + + case STM_BLOCK: + cstmlist(J, F, stm->a); + break; + + case STM_EMPTY: + if (F->script) { + emitline(J, F, stm); + emit(J, F, OP_POP); + emit(J, F, OP_UNDEF); + } + break; + + case STM_VAR: + cvarinit(J, F, stm->a); + break; + + case STM_IF: + if (stm->c) { + cexp(J, F, stm->a); + emitline(J, F, stm); + then = emitjump(J, F, OP_JTRUE); + cstm(J, F, stm->c); + emitline(J, F, stm); + end = emitjump(J, F, OP_JUMP); + label(J, F, then); + cstm(J, F, stm->b); + label(J, F, end); + } else { + cexp(J, F, stm->a); + emitline(J, F, stm); + end = emitjump(J, F, OP_JFALSE); + cstm(J, F, stm->b); + label(J, F, end); + } + break; + + case STM_DO: + loop = here(J, F); + cstm(J, F, stm->a); + cont = here(J, F); + cexp(J, F, stm->b); + emitline(J, F, stm); + emitjumpto(J, F, OP_JTRUE, loop); + labeljumps(J, F, stm->jumps, here(J,F), cont); + break; + + case STM_WHILE: + loop = here(J, F); + cexp(J, F, stm->a); + emitline(J, F, stm); + end = emitjump(J, F, OP_JFALSE); + cstm(J, F, stm->b); + emitline(J, F, stm); + emitjumpto(J, F, OP_JUMP, loop); + label(J, F, end); + labeljumps(J, F, stm->jumps, here(J,F), loop); + break; + + case STM_FOR: + case STM_FOR_VAR: + if (stm->type == STM_FOR_VAR) { + cvarinit(J, F, stm->a); + } else { + if (stm->a) { + cexp(J, F, stm->a); + emit(J, F, OP_POP); + } + } + loop = here(J, F); + if (stm->b) { + cexp(J, F, stm->b); + emitline(J, F, stm); + end = emitjump(J, F, OP_JFALSE); + } else { + end = 0; + } + cstm(J, F, stm->d); + cont = here(J, F); + if (stm->c) { + cexp(J, F, stm->c); + emit(J, F, OP_POP); + } + emitline(J, F, stm); + emitjumpto(J, F, OP_JUMP, loop); + if (end) + label(J, F, end); + labeljumps(J, F, stm->jumps, here(J,F), cont); + break; + + case STM_FOR_IN: + case STM_FOR_IN_VAR: + cexp(J, F, stm->b); + emitline(J, F, stm); + emit(J, F, OP_ITERATOR); + loop = here(J, F); + { + emitline(J, F, stm); + emit(J, F, OP_NEXTITER); + end = emitjump(J, F, OP_JFALSE); + cassignforin(J, F, stm); + if (F->script) { + emit(J, F, OP_ROT2); + cstm(J, F, stm->c); + emit(J, F, OP_ROT2); + } else { + cstm(J, F, stm->c); + } + emitline(J, F, stm); + emitjumpto(J, F, OP_JUMP, loop); + } + label(J, F, end); + labeljumps(J, F, stm->jumps, here(J,F), loop); + break; + + case STM_SWITCH: + cswitch(J, F, stm->a, stm->b); + labeljumps(J, F, stm->jumps, here(J,F), 0); + break; + + case STM_LABEL: + cstm(J, F, stm->b); + /* skip consecutive labels */ + while (stm->type == STM_LABEL) + stm = stm->b; + /* loops and switches have already been labelled */ + if (!isloop(stm->type) && stm->type != STM_SWITCH) + labeljumps(J, F, stm->jumps, here(J,F), 0); + break; + + case STM_BREAK: + if (stm->a) { + checkfutureword(J, F, stm->a); + target = breaktarget(J, F, stm->parent, stm->a->string); + if (!target) + jsC_error(J, stm, "break label '%s' not found", stm->a->string); + } else { + target = breaktarget(J, F, stm->parent, NULL); + if (!target) + jsC_error(J, stm, "unlabelled break must be inside loop or switch"); + } + cexit(J, F, STM_BREAK, stm, target); + emitline(J, F, stm); + addjump(J, F, STM_BREAK, target, emitjump(J, F, OP_JUMP)); + break; + + case STM_CONTINUE: + if (stm->a) { + checkfutureword(J, F, stm->a); + target = continuetarget(J, F, stm->parent, stm->a->string); + if (!target) + jsC_error(J, stm, "continue label '%s' not found", stm->a->string); + } else { + target = continuetarget(J, F, stm->parent, NULL); + if (!target) + jsC_error(J, stm, "continue must be inside loop"); + } + cexit(J, F, STM_CONTINUE, stm, target); + emitline(J, F, stm); + addjump(J, F, STM_CONTINUE, target, emitjump(J, F, OP_JUMP)); + break; + + case STM_RETURN: + if (stm->a) + cexp(J, F, stm->a); + else + emit(J, F, OP_UNDEF); + target = returntarget(J, F, stm->parent); + if (!target) + jsC_error(J, stm, "return not in function"); + cexit(J, F, STM_RETURN, stm, target); + emitline(J, F, stm); + emit(J, F, OP_RETURN); + break; + + case STM_THROW: + cexp(J, F, stm->a); + emitline(J, F, stm); + emit(J, F, OP_THROW); + break; + + case STM_WITH: + F->lightweight = 0; + if (F->strict) + jsC_error(J, stm->a, "'with' statements are not allowed in strict mode"); + cexp(J, F, stm->a); + emitline(J, F, stm); + emit(J, F, OP_WITH); + cstm(J, F, stm->b); + emitline(J, F, stm); + emit(J, F, OP_ENDWITH); + break; + + case STM_TRY: + emitline(J, F, stm); + if (stm->b && stm->c) { + F->lightweight = 0; + if (stm->d) + ctrycatchfinally(J, F, stm->a, stm->b, stm->c, stm->d); + else + ctrycatch(J, F, stm->a, stm->b, stm->c); + } else { + ctryfinally(J, F, stm->a, stm->d); + } + break; + + case STM_DEBUGGER: + emitline(J, F, stm); + emit(J, F, OP_DEBUGGER); + break; + + default: + if (F->script) { + emitline(J, F, stm); + emit(J, F, OP_POP); + cexp(J, F, stm); + } else { + cexp(J, F, stm); + emitline(J, F, stm); + emit(J, F, OP_POP); + } + break; + } +} + +static void cstmlist(JF, js_Ast *list) +{ + while (list) { + cstm(J, F, list->a); + list = list->b; + } +} + +/* Declarations and programs */ + +static int listlength(js_Ast *list) +{ + int n = 0; + while (list) ++n, list = list->b; + return n; +} + +static void cparams(JF, js_Ast *list, js_Ast *fname) +{ + F->numparams = listlength(list); + while (list) { + checkfutureword(J, F, list->a); + addlocal(J, F, list->a, 0); + list = list->b; + } +} + +static void cvardecs(JF, js_Ast *node) +{ + if (node->type == AST_LIST) { + while (node) { + cvardecs(J, F, node->a); + node = node->b; + } + return; + } + + if (isfun(node->type)) + return; /* stop at inner functions */ + + if (node->type == EXP_VAR) { + checkfutureword(J, F, node->a); + addlocal(J, F, node->a, 1); + } + + if (node->a) cvardecs(J, F, node->a); + if (node->b) cvardecs(J, F, node->b); + if (node->c) cvardecs(J, F, node->c); + if (node->d) cvardecs(J, F, node->d); +} + +static void cfundecs(JF, js_Ast *list) +{ + while (list) { + js_Ast *stm = list->a; + if (stm->type == AST_FUNDEC) { + emitline(J, F, stm); + emitfunction(J, F, newfun(J, stm->line, stm->a, stm->b, stm->c, 0, F->strict)); + emitline(J, F, stm); + emit(J, F, OP_SETLOCAL); + emitarg(J, F, addlocal(J, F, stm->a, 0)); + emit(J, F, OP_POP); + } + list = list->b; + } +} + +static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body) +{ + F->lightweight = 1; + F->arguments = 0; + + if (F->script) + F->lightweight = 0; + + /* Check if first statement is 'use strict': */ + if (body && body->type == AST_LIST && body->a && body->a->type == EXP_STRING) + if (!strcmp(body->a->string, "use strict")) + F->strict = 1; + + F->lastline = F->line; + + cparams(J, F, params, name); + + if (body) { + cvardecs(J, F, body); + cfundecs(J, F, body); + } + + if (name) { + checkfutureword(J, F, name); + if (findlocal(J, F, name->string) < 0) { + emit(J, F, OP_CURRENT); + emit(J, F, OP_SETLOCAL); + emitarg(J, F, addlocal(J, F, name, 0)); + emit(J, F, OP_POP); + } + } + + if (F->script) { + emit(J, F, OP_UNDEF); + cstmlist(J, F, body); + emit(J, F, OP_RETURN); + } else { + cstmlist(J, F, body); + emit(J, F, OP_UNDEF); + emit(J, F, OP_RETURN); + } +} + +js_Function *jsC_compilefunction(js_State *J, js_Ast *prog) +{ + return newfun(J, prog->line, prog->a, prog->b, prog->c, 0, J->default_strict); +} + +js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict) +{ + return newfun(J, prog ? prog->line : 0, NULL, NULL, prog, 1, default_strict); +} diff --git a/programs/develop/kosjs/libmujs/include/jscompile.h b/programs/develop/kosjs/libmujs/jscompile.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/jscompile.h rename to programs/develop/kosjs/libmujs/jscompile.h diff --git a/programs/develop/kosjs/libmujs/jsdate.c b/programs/develop/kosjs/libmujs/jsdate.c new file mode 100755 index 0000000000..ca1358210d --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsdate.c @@ -0,0 +1,812 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +#include + +#if defined(__unix__) || defined(__APPLE__) +#include +#elif defined(_WIN32) +#include +#endif + +#define js_optnumber(J,I,V) (js_isdefined(J,I) ? js_tonumber(J,I) : V) + +static double Now(void) +{ +#if defined(__unix__) || defined(__APPLE__) + struct timeval tv; + gettimeofday(&tv, NULL); + return floor(tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0); +#elif defined(_WIN32) + struct _timeb tv; + _ftime(&tv); + return tv.time * 1000.0 + tv.millitm; +#else + return time(NULL) * 1000.0; +#endif +} + +static double LocalTZA(void) +{ + static int once = 1; + static double tza = 0; + if (once) { + time_t now = time(NULL); + time_t utc = mktime(gmtime(&now)); + time_t loc = mktime(localtime(&now)); + tza = (loc - utc) * 1000; + once = 0; + } + return tza; +} + +static double DaylightSavingTA(double t) +{ + return 0; /* TODO */ +} + +/* Helpers from the ECMA 262 specification */ + +#define HoursPerDay 24.0 +#define MinutesPerDay (HoursPerDay * MinutesPerHour) +#define MinutesPerHour 60.0 +#define SecondsPerDay (MinutesPerDay * SecondsPerMinute) +#define SecondsPerHour (MinutesPerHour * SecondsPerMinute) +#define SecondsPerMinute 60.0 + +#define msPerDay (SecondsPerDay * msPerSecond) +#define msPerHour (SecondsPerHour * msPerSecond) +#define msPerMinute (SecondsPerMinute * msPerSecond) +#define msPerSecond 1000.0 + +static double pmod(double x, double y) +{ + x = fmod(x, y); + if (x < 0) + x += y; + return x; +} + +static int Day(double t) +{ + return floor(t / msPerDay); +} + +static double TimeWithinDay(double t) +{ + return pmod(t, msPerDay); +} + +static int DaysInYear(int y) +{ + return y % 4 == 0 && (y % 100 || (y % 400 == 0)) ? 366 : 365; +} + +static int DayFromYear(int y) +{ + return 365 * (y - 1970) + + floor((y - 1969) / 4.0) - + floor((y - 1901) / 100.0) + + floor((y - 1601) / 400.0); +} + +static double TimeFromYear(int y) +{ + return DayFromYear(y) * msPerDay; +} + +static int YearFromTime(double t) +{ + int y = floor(t / (msPerDay * 365.2425)) + 1970; + double t2 = TimeFromYear(y); + if (t2 > t) + --y; + else if (t2 + msPerDay * DaysInYear(y) <= t) + ++y; + return y; +} + +static int InLeapYear(double t) +{ + return DaysInYear(YearFromTime(t)) == 366; +} + +static int DayWithinYear(double t) +{ + return Day(t) - DayFromYear(YearFromTime(t)); +} + +static int MonthFromTime(double t) +{ + int day = DayWithinYear(t); + int leap = InLeapYear(t); + if (day < 31) return 0; + if (day < 59 + leap) return 1; + if (day < 90 + leap) return 2; + if (day < 120 + leap) return 3; + if (day < 151 + leap) return 4; + if (day < 181 + leap) return 5; + if (day < 212 + leap) return 6; + if (day < 243 + leap) return 7; + if (day < 273 + leap) return 8; + if (day < 304 + leap) return 9; + if (day < 334 + leap) return 10; + return 11; +} + +static int DateFromTime(double t) +{ + int day = DayWithinYear(t); + int leap = InLeapYear(t); + switch (MonthFromTime(t)) { + case 0: return day + 1; + case 1: return day - 30; + case 2: return day - 58 - leap; + case 3: return day - 89 - leap; + case 4: return day - 119 - leap; + case 5: return day - 150 - leap; + case 6: return day - 180 - leap; + case 7: return day - 211 - leap; + case 8: return day - 242 - leap; + case 9: return day - 272 - leap; + case 10: return day - 303 - leap; + default : return day - 333 - leap; + } +} + +static int WeekDay(double t) +{ + return pmod(Day(t) + 4, 7); +} + +static double LocalTime(double utc) +{ + return utc + LocalTZA() + DaylightSavingTA(utc); +} + +static double UTC(double loc) +{ + return loc - LocalTZA() - DaylightSavingTA(loc - LocalTZA()); +} + +static int HourFromTime(double t) +{ + return pmod(floor(t / msPerHour), HoursPerDay); +} + +static int MinFromTime(double t) +{ + return pmod(floor(t / msPerMinute), MinutesPerHour); +} + +static int SecFromTime(double t) +{ + return pmod(floor(t / msPerSecond), SecondsPerMinute); +} + +static int msFromTime(double t) +{ + return pmod(t, msPerSecond); +} + +static double MakeTime(double hour, double min, double sec, double ms) +{ + return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; +} + +static double MakeDay(double y, double m, double date) +{ + /* + * The following array contains the day of year for the first day of + * each month, where index 0 is January, and day 0 is January 1. + */ + static const double firstDayOfMonth[2][12] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + + double yd, md; + int im; + + y += floor(m / 12); + m = pmod(m, 12); + + im = (int)m; + if (im < 0 || im >= 12) + return NAN; + + yd = floor(TimeFromYear(y) / msPerDay); + md = firstDayOfMonth[DaysInYear(y) == 366][im]; + + return yd + md + date - 1; +} + +static double MakeDate(double day, double time) +{ + return day * msPerDay + time; +} + +static double TimeClip(double t) +{ + if (!isfinite(t)) + return NAN; + if (fabs(t) > 8.64e15) + return NAN; + return t < 0 ? -floor(-t) : floor(t); +} + +static int toint(const char **sp, int w, int *v) +{ + const char *s = *sp; + *v = 0; + while (w--) { + if (*s < '0' || *s > '9') + return 0; + *v = *v * 10 + (*s++ - '0'); + } + *sp = s; + return 1; +} + +static double parseDateTime(const char *s) +{ + int y = 1970, m = 1, d = 1, H = 0, M = 0, S = 0, ms = 0; + int tza = 0; + double t; + + /* Parse ISO 8601 formatted date and time: */ + /* YYYY("-"MM("-"DD)?)?("T"HH":"mm(":"ss("."sss)?)?("Z"|[+-]HH(":"mm)?)?)? */ + + if (!toint(&s, 4, &y)) return NAN; + if (*s == '-') { + s += 1; + if (!toint(&s, 2, &m)) return NAN; + if (*s == '-') { + s += 1; + if (!toint(&s, 2, &d)) return NAN; + } + } + + if (*s == 'T') { + s += 1; + if (!toint(&s, 2, &H)) return NAN; + if (*s != ':') return NAN; + s += 1; + if (!toint(&s, 2, &M)) return NAN; + if (*s == ':') { + s += 1; + if (!toint(&s, 2, &S)) return NAN; + if (*s == '.') { + s += 1; + if (!toint(&s, 3, &ms)) return NAN; + } + } + if (*s == 'Z') { + s += 1; + tza = 0; + } else if (*s == '+' || *s == '-') { + int tzh = 0, tzm = 0; + int tzs = *s == '+' ? 1 : -1; + s += 1; + if (!toint(&s, 2, &tzh)) return NAN; + if (*s == ':') { + s += 1; + if (!toint(&s, 2, &tzm)) return NAN; + } + if (tzh > 23 || tzm > 59) return NAN; + tza = tzs * (tzh * msPerHour + tzm * msPerMinute); + } else { + tza = LocalTZA(); + } + } + + if (*s) return NAN; + + if (m < 1 || m > 12) return NAN; + if (d < 1 || d > 31) return NAN; + if (H < 0 || H > 24) return NAN; + if (M < 0 || M > 59) return NAN; + if (S < 0 || S > 59) return NAN; + if (ms < 0 || ms > 999) return NAN; + if (H == 24 && (M != 0 || S != 0 || ms != 0)) return NAN; + + /* TODO: DaylightSavingTA on local times */ + t = MakeDate(MakeDay(y, m-1, d), MakeTime(H, M, S, ms)); + return t - tza; +} + +/* date formatting */ + +static char *fmtdate(char *buf, double t) +{ + int y = YearFromTime(t); + int m = MonthFromTime(t); + int d = DateFromTime(t); + if (!isfinite(t)) + return "Invalid Date"; + sprintf(buf, "%04d-%02d-%02d", y, m+1, d); + return buf; +} + +static char *fmttime(char *buf, double t, double tza) +{ + int H = HourFromTime(t); + int M = MinFromTime(t); + int S = SecFromTime(t); + int ms = msFromTime(t); + int tzh = HourFromTime(fabs(tza)); + int tzm = MinFromTime(fabs(tza)); + if (!isfinite(t)) + return "Invalid Date"; + if (tza == 0) + sprintf(buf, "%02d:%02d:%02d.%03dZ", H, M, S, ms); + else if (tza < 0) + sprintf(buf, "%02d:%02d:%02d.%03d-%02d:%02d", H, M, S, ms, tzh, tzm); + else + sprintf(buf, "%02d:%02d:%02d.%03d+%02d:%02d", H, M, S, ms, tzh, tzm); + return buf; +} + +static char *fmtdatetime(char *buf, double t, double tza) +{ + char dbuf[20], tbuf[20]; + if (!isfinite(t)) + return "Invalid Date"; + fmtdate(dbuf, t); + fmttime(tbuf, t, tza); + sprintf(buf, "%sT%s", dbuf, tbuf); + return buf; +} + +/* Date functions */ + +static double js_todate(js_State *J, int idx) +{ + js_Object *self = js_toobject(J, idx); + if (self->type != JS_CDATE) + js_typeerror(J, "not a date"); + return self->u.number; +} + +static void js_setdate(js_State *J, int idx, double t) +{ + js_Object *self = js_toobject(J, idx); + if (self->type != JS_CDATE) + js_typeerror(J, "not a date"); + self->u.number = TimeClip(t); + js_pushnumber(J, self->u.number); +} + +static void D_parse(js_State *J) +{ + double t = parseDateTime(js_tostring(J, 1)); + js_pushnumber(J, t); +} + +static void D_UTC(js_State *J) +{ + double y, m, d, H, M, S, ms, t; + y = js_tonumber(J, 1); + if (y < 100) y += 1900; + m = js_tonumber(J, 2); + d = js_optnumber(J, 3, 1); + H = js_optnumber(J, 4, 0); + M = js_optnumber(J, 5, 0); + S = js_optnumber(J, 6, 0); + ms = js_optnumber(J, 7, 0); + t = MakeDate(MakeDay(y, m, d), MakeTime(H, M, S, ms)); + t = TimeClip(t); + js_pushnumber(J, t); +} + +static void D_now(js_State *J) +{ + js_pushnumber(J, Now()); +} + +static void jsB_Date(js_State *J) +{ + char buf[64]; + js_pushstring(J, fmtdatetime(buf, LocalTime(Now()), LocalTZA())); +} + +static void jsB_new_Date(js_State *J) +{ + int top = js_gettop(J); + js_Object *obj; + double t; + + if (top == 1) + t = Now(); + else if (top == 2) { + js_toprimitive(J, 1, JS_HNONE); + if (js_isstring(J, 1)) + t = parseDateTime(js_tostring(J, 1)); + else + t = TimeClip(js_tonumber(J, 1)); + } else { + double y, m, d, H, M, S, ms; + y = js_tonumber(J, 1); + if (y < 100) y += 1900; + m = js_tonumber(J, 2); + d = js_optnumber(J, 3, 1); + H = js_optnumber(J, 4, 0); + M = js_optnumber(J, 5, 0); + S = js_optnumber(J, 6, 0); + ms = js_optnumber(J, 7, 0); + t = MakeDate(MakeDay(y, m, d), MakeTime(H, M, S, ms)); + t = TimeClip(UTC(t)); + } + + obj = jsV_newobject(J, JS_CDATE, J->Date_prototype); + obj->u.number = t; + + js_pushobject(J, obj); +} + +static void Dp_valueOf(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, t); +} + +static void Dp_toString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmtdatetime(buf, LocalTime(t), LocalTZA())); +} + +static void Dp_toDateString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmtdate(buf, LocalTime(t))); +} + +static void Dp_toTimeString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmttime(buf, LocalTime(t), LocalTZA())); +} + +static void Dp_toUTCString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + js_pushstring(J, fmtdatetime(buf, t, 0)); +} + +static void Dp_toISOString(js_State *J) +{ + char buf[64]; + double t = js_todate(J, 0); + if (!isfinite(t)) + js_rangeerror(J, "invalid date"); + js_pushstring(J, fmtdatetime(buf, t, 0)); +} + +static void Dp_getFullYear(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, YearFromTime(LocalTime(t))); +} + +static void Dp_getMonth(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, MonthFromTime(LocalTime(t))); +} + +static void Dp_getDate(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, DateFromTime(LocalTime(t))); +} + +static void Dp_getDay(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, WeekDay(LocalTime(t))); +} + +static void Dp_getHours(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, HourFromTime(LocalTime(t))); +} + +static void Dp_getMinutes(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, MinFromTime(LocalTime(t))); +} + +static void Dp_getSeconds(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, SecFromTime(LocalTime(t))); +} + +static void Dp_getMilliseconds(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, msFromTime(LocalTime(t))); +} + +static void Dp_getUTCFullYear(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, YearFromTime(t)); +} + +static void Dp_getUTCMonth(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, MonthFromTime(t)); +} + +static void Dp_getUTCDate(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, DateFromTime(t)); +} + +static void Dp_getUTCDay(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, WeekDay(t)); +} + +static void Dp_getUTCHours(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, HourFromTime(t)); +} + +static void Dp_getUTCMinutes(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, MinFromTime(t)); +} + +static void Dp_getUTCSeconds(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, SecFromTime(t)); +} + +static void Dp_getUTCMilliseconds(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, msFromTime(t)); +} + +static void Dp_getTimezoneOffset(js_State *J) +{ + double t = js_todate(J, 0); + js_pushnumber(J, (t - LocalTime(t)) / msPerMinute); +} + +static void Dp_setTime(js_State *J) +{ + js_setdate(J, 0, js_tonumber(J, 1)); +} + +static void Dp_setMilliseconds(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = SecFromTime(t); + double ms = js_tonumber(J, 1); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setSeconds(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = js_tonumber(J, 1); + double ms = js_optnumber(J, 2, msFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setMinutes(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = HourFromTime(t); + double m = js_tonumber(J, 1); + double s = js_optnumber(J, 2, SecFromTime(t)); + double ms = js_optnumber(J, 3, msFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setHours(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double h = js_tonumber(J, 1); + double m = js_optnumber(J, 2, MinFromTime(t)); + double s = js_optnumber(J, 3, SecFromTime(t)); + double ms = js_optnumber(J, 4, msFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); +} + +static void Dp_setDate(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double y = YearFromTime(t); + double m = MonthFromTime(t); + double d = js_tonumber(J, 1); + js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); +} + +static void Dp_setMonth(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double y = YearFromTime(t); + double m = js_tonumber(J, 1); + double d = js_optnumber(J, 2, DateFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); +} + +static void Dp_setFullYear(js_State *J) +{ + double t = LocalTime(js_todate(J, 0)); + double y = js_tonumber(J, 1); + double m = js_optnumber(J, 2, MonthFromTime(t)); + double d = js_optnumber(J, 3, DateFromTime(t)); + js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); +} + +static void Dp_setUTCMilliseconds(js_State *J) +{ + double t = js_todate(J, 0); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = SecFromTime(t); + double ms = js_tonumber(J, 1); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCSeconds(js_State *J) +{ + double t = js_todate(J, 0); + double h = HourFromTime(t); + double m = MinFromTime(t); + double s = js_tonumber(J, 1); + double ms = js_optnumber(J, 2, msFromTime(t)); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCMinutes(js_State *J) +{ + double t = js_todate(J, 0); + double h = HourFromTime(t); + double m = js_tonumber(J, 1); + double s = js_optnumber(J, 2, SecFromTime(t)); + double ms = js_optnumber(J, 3, msFromTime(t)); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCHours(js_State *J) +{ + double t = js_todate(J, 0); + double h = js_tonumber(J, 1); + double m = js_optnumber(J, 2, HourFromTime(t)); + double s = js_optnumber(J, 3, SecFromTime(t)); + double ms = js_optnumber(J, 4, msFromTime(t)); + js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); +} + +static void Dp_setUTCDate(js_State *J) +{ + double t = js_todate(J, 0); + double y = YearFromTime(t); + double m = MonthFromTime(t); + double d = js_tonumber(J, 1); + js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); +} + +static void Dp_setUTCMonth(js_State *J) +{ + double t = js_todate(J, 0); + double y = YearFromTime(t); + double m = js_tonumber(J, 1); + double d = js_optnumber(J, 2, DateFromTime(t)); + js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); +} + +static void Dp_setUTCFullYear(js_State *J) +{ + double t = js_todate(J, 0); + double y = js_tonumber(J, 1); + double m = js_optnumber(J, 2, MonthFromTime(t)); + double d = js_optnumber(J, 3, DateFromTime(t)); + js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); +} + +static void Dp_toJSON(js_State *J) +{ + js_copy(J, 0); + js_toprimitive(J, -1, JS_HNUMBER); + if (js_isnumber(J, -1) && !isfinite(js_tonumber(J, -1))) { + js_pushnull(J); + return; + } + js_pop(J, 1); + + js_getproperty(J, 0, "toISOString"); + if (!js_iscallable(J, -1)) + js_typeerror(J, "this.toISOString is not a function"); + js_copy(J, 0); + js_call(J, 0); +} + +void jsB_initdate(js_State *J) +{ + J->Date_prototype->u.number = 0; + + js_pushobject(J, J->Date_prototype); + { + jsB_propf(J, "Date.prototype.valueOf", Dp_valueOf, 0); + jsB_propf(J, "Date.prototype.toString", Dp_toString, 0); + jsB_propf(J, "Date.prototype.toDateString", Dp_toDateString, 0); + jsB_propf(J, "Date.prototype.toTimeString", Dp_toTimeString, 0); + jsB_propf(J, "Date.prototype.toLocaleString", Dp_toString, 0); + jsB_propf(J, "Date.prototype.toLocaleDateString", Dp_toDateString, 0); + jsB_propf(J, "Date.prototype.toLocaleTimeString", Dp_toTimeString, 0); + jsB_propf(J, "Date.prototype.toUTCString", Dp_toUTCString, 0); + + jsB_propf(J, "Date.prototype.getTime", Dp_valueOf, 0); + jsB_propf(J, "Date.prototype.getFullYear", Dp_getFullYear, 0); + jsB_propf(J, "Date.prototype.getUTCFullYear", Dp_getUTCFullYear, 0); + jsB_propf(J, "Date.prototype.getMonth", Dp_getMonth, 0); + jsB_propf(J, "Date.prototype.getUTCMonth", Dp_getUTCMonth, 0); + jsB_propf(J, "Date.prototype.getDate", Dp_getDate, 0); + jsB_propf(J, "Date.prototype.getUTCDate", Dp_getUTCDate, 0); + jsB_propf(J, "Date.prototype.getDay", Dp_getDay, 0); + jsB_propf(J, "Date.prototype.getUTCDay", Dp_getUTCDay, 0); + jsB_propf(J, "Date.prototype.getHours", Dp_getHours, 0); + jsB_propf(J, "Date.prototype.getUTCHours", Dp_getUTCHours, 0); + jsB_propf(J, "Date.prototype.getMinutes", Dp_getMinutes, 0); + jsB_propf(J, "Date.prototype.getUTCMinutes", Dp_getUTCMinutes, 0); + jsB_propf(J, "Date.prototype.getSeconds", Dp_getSeconds, 0); + jsB_propf(J, "Date.prototype.getUTCSeconds", Dp_getUTCSeconds, 0); + jsB_propf(J, "Date.prototype.getMilliseconds", Dp_getMilliseconds, 0); + jsB_propf(J, "Date.prototype.getUTCMilliseconds", Dp_getUTCMilliseconds, 0); + jsB_propf(J, "Date.prototype.getTimezoneOffset", Dp_getTimezoneOffset, 0); + + jsB_propf(J, "Date.prototype.setTime", Dp_setTime, 1); + jsB_propf(J, "Date.prototype.setMilliseconds", Dp_setMilliseconds, 1); + jsB_propf(J, "Date.prototype.setUTCMilliseconds", Dp_setUTCMilliseconds, 1); + jsB_propf(J, "Date.prototype.setSeconds", Dp_setSeconds, 2); + jsB_propf(J, "Date.prototype.setUTCSeconds", Dp_setUTCSeconds, 2); + jsB_propf(J, "Date.prototype.setMinutes", Dp_setMinutes, 3); + jsB_propf(J, "Date.prototype.setUTCMinutes", Dp_setUTCMinutes, 3); + jsB_propf(J, "Date.prototype.setHours", Dp_setHours, 4); + jsB_propf(J, "Date.prototype.setUTCHours", Dp_setUTCHours, 4); + jsB_propf(J, "Date.prototype.setDate", Dp_setDate, 1); + jsB_propf(J, "Date.prototype.setUTCDate", Dp_setUTCDate, 1); + jsB_propf(J, "Date.prototype.setMonth", Dp_setMonth, 2); + jsB_propf(J, "Date.prototype.setUTCMonth", Dp_setUTCMonth, 2); + jsB_propf(J, "Date.prototype.setFullYear", Dp_setFullYear, 3); + jsB_propf(J, "Date.prototype.setUTCFullYear", Dp_setUTCFullYear, 3); + + /* ES5 */ + jsB_propf(J, "Date.prototype.toISOString", Dp_toISOString, 0); + jsB_propf(J, "Date.prototype.toJSON", Dp_toJSON, 1); + } + js_newcconstructor(J, jsB_Date, jsB_new_Date, "Date", 0); /* 1 */ + { + jsB_propf(J, "Date.parse", D_parse, 1); + jsB_propf(J, "Date.UTC", D_UTC, 7); + + /* ES5 */ + jsB_propf(J, "Date.now", D_now, 0); + } + js_defglobal(J, "Date", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsdtoa.c b/programs/develop/kosjs/libmujs/jsdtoa.c new file mode 100755 index 0000000000..858017d08b --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsdtoa.c @@ -0,0 +1,747 @@ +/* Locale-independent implementations of string <-> double conversions. */ + +#include "jsi.h" + +#if defined(_MSC_VER) && (_MSC_VER < 1700) /* VS2012 has stdint.h */ +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#include +#include + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* + * format exponent like sprintf(p, "e%+d", e) + */ +void +js_fmtexp(char *p, int e) +{ + char se[9]; + int i; + + *p++ = 'e'; + if(e < 0) { + *p++ = '-'; + e = -e; + } else + *p++ = '+'; + i = 0; + while(e) { + se[i++] = e % 10 + '0'; + e /= 10; + } + while(i < 1) + se[i++] = '0'; + while(i > 0) + *p++ = se[--i]; + *p++ = '\0'; +} + +/* + * grisu2_59_56.c + * + * Grisu prints the optimal decimal representation of floating-point numbers. + * + * Copyright (c) 2009 Florian Loitsch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +typedef struct diy_fp_t { + uint64_t f; + int e; +} diy_fp_t; + +#define DIY_SIGNIFICAND_SIZE 64 +#define D_1_LOG2_10 0.30102999566398114 /* 1 / lg(10) */ + +static const uint64_t powers_ten[] = { + 0xbf29dcaba82fdeae, 0xeef453d6923bd65a, 0x9558b4661b6565f8, + 0xbaaee17fa23ebf76, 0xe95a99df8ace6f54, 0x91d8a02bb6c10594, + 0xb64ec836a47146fa, 0xe3e27a444d8d98b8, 0x8e6d8c6ab0787f73, + 0xb208ef855c969f50, 0xde8b2b66b3bc4724, 0x8b16fb203055ac76, + 0xaddcb9e83c6b1794, 0xd953e8624b85dd79, 0x87d4713d6f33aa6c, + 0xa9c98d8ccb009506, 0xd43bf0effdc0ba48, 0x84a57695fe98746d, + 0xa5ced43b7e3e9188, 0xcf42894a5dce35ea, 0x818995ce7aa0e1b2, + 0xa1ebfb4219491a1f, 0xca66fa129f9b60a7, 0xfd00b897478238d1, + 0x9e20735e8cb16382, 0xc5a890362fddbc63, 0xf712b443bbd52b7c, + 0x9a6bb0aa55653b2d, 0xc1069cd4eabe89f9, 0xf148440a256e2c77, + 0x96cd2a865764dbca, 0xbc807527ed3e12bd, 0xeba09271e88d976c, + 0x93445b8731587ea3, 0xb8157268fdae9e4c, 0xe61acf033d1a45df, + 0x8fd0c16206306bac, 0xb3c4f1ba87bc8697, 0xe0b62e2929aba83c, + 0x8c71dcd9ba0b4926, 0xaf8e5410288e1b6f, 0xdb71e91432b1a24b, + 0x892731ac9faf056f, 0xab70fe17c79ac6ca, 0xd64d3d9db981787d, + 0x85f0468293f0eb4e, 0xa76c582338ed2622, 0xd1476e2c07286faa, + 0x82cca4db847945ca, 0xa37fce126597973d, 0xcc5fc196fefd7d0c, + 0xff77b1fcbebcdc4f, 0x9faacf3df73609b1, 0xc795830d75038c1e, + 0xf97ae3d0d2446f25, 0x9becce62836ac577, 0xc2e801fb244576d5, + 0xf3a20279ed56d48a, 0x9845418c345644d7, 0xbe5691ef416bd60c, + 0xedec366b11c6cb8f, 0x94b3a202eb1c3f39, 0xb9e08a83a5e34f08, + 0xe858ad248f5c22ca, 0x91376c36d99995be, 0xb58547448ffffb2e, + 0xe2e69915b3fff9f9, 0x8dd01fad907ffc3c, 0xb1442798f49ffb4b, + 0xdd95317f31c7fa1d, 0x8a7d3eef7f1cfc52, 0xad1c8eab5ee43b67, + 0xd863b256369d4a41, 0x873e4f75e2224e68, 0xa90de3535aaae202, + 0xd3515c2831559a83, 0x8412d9991ed58092, 0xa5178fff668ae0b6, + 0xce5d73ff402d98e4, 0x80fa687f881c7f8e, 0xa139029f6a239f72, + 0xc987434744ac874f, 0xfbe9141915d7a922, 0x9d71ac8fada6c9b5, + 0xc4ce17b399107c23, 0xf6019da07f549b2b, 0x99c102844f94e0fb, + 0xc0314325637a193a, 0xf03d93eebc589f88, 0x96267c7535b763b5, + 0xbbb01b9283253ca3, 0xea9c227723ee8bcb, 0x92a1958a7675175f, + 0xb749faed14125d37, 0xe51c79a85916f485, 0x8f31cc0937ae58d3, + 0xb2fe3f0b8599ef08, 0xdfbdcece67006ac9, 0x8bd6a141006042be, + 0xaecc49914078536d, 0xda7f5bf590966849, 0x888f99797a5e012d, + 0xaab37fd7d8f58179, 0xd5605fcdcf32e1d7, 0x855c3be0a17fcd26, + 0xa6b34ad8c9dfc070, 0xd0601d8efc57b08c, 0x823c12795db6ce57, + 0xa2cb1717b52481ed, 0xcb7ddcdda26da269, 0xfe5d54150b090b03, + 0x9efa548d26e5a6e2, 0xc6b8e9b0709f109a, 0xf867241c8cc6d4c1, + 0x9b407691d7fc44f8, 0xc21094364dfb5637, 0xf294b943e17a2bc4, + 0x979cf3ca6cec5b5b, 0xbd8430bd08277231, 0xece53cec4a314ebe, + 0x940f4613ae5ed137, 0xb913179899f68584, 0xe757dd7ec07426e5, + 0x9096ea6f3848984f, 0xb4bca50b065abe63, 0xe1ebce4dc7f16dfc, + 0x8d3360f09cf6e4bd, 0xb080392cc4349ded, 0xdca04777f541c568, + 0x89e42caaf9491b61, 0xac5d37d5b79b6239, 0xd77485cb25823ac7, + 0x86a8d39ef77164bd, 0xa8530886b54dbdec, 0xd267caa862a12d67, + 0x8380dea93da4bc60, 0xa46116538d0deb78, 0xcd795be870516656, + 0x806bd9714632dff6, 0xa086cfcd97bf97f4, 0xc8a883c0fdaf7df0, + 0xfad2a4b13d1b5d6c, 0x9cc3a6eec6311a64, 0xc3f490aa77bd60fd, + 0xf4f1b4d515acb93c, 0x991711052d8bf3c5, 0xbf5cd54678eef0b7, + 0xef340a98172aace5, 0x9580869f0e7aac0f, 0xbae0a846d2195713, + 0xe998d258869facd7, 0x91ff83775423cc06, 0xb67f6455292cbf08, + 0xe41f3d6a7377eeca, 0x8e938662882af53e, 0xb23867fb2a35b28e, + 0xdec681f9f4c31f31, 0x8b3c113c38f9f37f, 0xae0b158b4738705f, + 0xd98ddaee19068c76, 0x87f8a8d4cfa417ca, 0xa9f6d30a038d1dbc, + 0xd47487cc8470652b, 0x84c8d4dfd2c63f3b, 0xa5fb0a17c777cf0a, + 0xcf79cc9db955c2cc, 0x81ac1fe293d599c0, 0xa21727db38cb0030, + 0xca9cf1d206fdc03c, 0xfd442e4688bd304b, 0x9e4a9cec15763e2f, + 0xc5dd44271ad3cdba, 0xf7549530e188c129, 0x9a94dd3e8cf578ba, + 0xc13a148e3032d6e8, 0xf18899b1bc3f8ca2, 0x96f5600f15a7b7e5, + 0xbcb2b812db11a5de, 0xebdf661791d60f56, 0x936b9fcebb25c996, + 0xb84687c269ef3bfb, 0xe65829b3046b0afa, 0x8ff71a0fe2c2e6dc, + 0xb3f4e093db73a093, 0xe0f218b8d25088b8, 0x8c974f7383725573, + 0xafbd2350644eead0, 0xdbac6c247d62a584, 0x894bc396ce5da772, + 0xab9eb47c81f5114f, 0xd686619ba27255a3, 0x8613fd0145877586, + 0xa798fc4196e952e7, 0xd17f3b51fca3a7a1, 0x82ef85133de648c5, + 0xa3ab66580d5fdaf6, 0xcc963fee10b7d1b3, 0xffbbcfe994e5c620, + 0x9fd561f1fd0f9bd4, 0xc7caba6e7c5382c9, 0xf9bd690a1b68637b, + 0x9c1661a651213e2d, 0xc31bfa0fe5698db8, 0xf3e2f893dec3f126, + 0x986ddb5c6b3a76b8, 0xbe89523386091466, 0xee2ba6c0678b597f, + 0x94db483840b717f0, 0xba121a4650e4ddec, 0xe896a0d7e51e1566, + 0x915e2486ef32cd60, 0xb5b5ada8aaff80b8, 0xe3231912d5bf60e6, + 0x8df5efabc5979c90, 0xb1736b96b6fd83b4, 0xddd0467c64bce4a1, + 0x8aa22c0dbef60ee4, 0xad4ab7112eb3929e, 0xd89d64d57a607745, + 0x87625f056c7c4a8b, 0xa93af6c6c79b5d2e, 0xd389b47879823479, + 0x843610cb4bf160cc, 0xa54394fe1eedb8ff, 0xce947a3da6a9273e, + 0x811ccc668829b887, 0xa163ff802a3426a9, 0xc9bcff6034c13053, + 0xfc2c3f3841f17c68, 0x9d9ba7832936edc1, 0xc5029163f384a931, + 0xf64335bcf065d37d, 0x99ea0196163fa42e, 0xc06481fb9bcf8d3a, + 0xf07da27a82c37088, 0x964e858c91ba2655, 0xbbe226efb628afeb, + 0xeadab0aba3b2dbe5, 0x92c8ae6b464fc96f, 0xb77ada0617e3bbcb, + 0xe55990879ddcaabe, 0x8f57fa54c2a9eab7, 0xb32df8e9f3546564, + 0xdff9772470297ebd, 0x8bfbea76c619ef36, 0xaefae51477a06b04, + 0xdab99e59958885c5, 0x88b402f7fd75539b, 0xaae103b5fcd2a882, + 0xd59944a37c0752a2, 0x857fcae62d8493a5, 0xa6dfbd9fb8e5b88f, + 0xd097ad07a71f26b2, 0x825ecc24c8737830, 0xa2f67f2dfa90563b, + 0xcbb41ef979346bca, 0xfea126b7d78186bd, 0x9f24b832e6b0f436, + 0xc6ede63fa05d3144, 0xf8a95fcf88747d94, 0x9b69dbe1b548ce7d, + 0xc24452da229b021c, 0xf2d56790ab41c2a3, 0x97c560ba6b0919a6, + 0xbdb6b8e905cb600f, 0xed246723473e3813, 0x9436c0760c86e30c, + 0xb94470938fa89bcf, 0xe7958cb87392c2c3, 0x90bd77f3483bb9ba, + 0xb4ecd5f01a4aa828, 0xe2280b6c20dd5232, 0x8d590723948a535f, + 0xb0af48ec79ace837, 0xdcdb1b2798182245, 0x8a08f0f8bf0f156b, + 0xac8b2d36eed2dac6, 0xd7adf884aa879177, 0x86ccbb52ea94baeb, + 0xa87fea27a539e9a5, 0xd29fe4b18e88640f, 0x83a3eeeef9153e89, + 0xa48ceaaab75a8e2b, 0xcdb02555653131b6, 0x808e17555f3ebf12, + 0xa0b19d2ab70e6ed6, 0xc8de047564d20a8c, 0xfb158592be068d2f, + 0x9ced737bb6c4183d, 0xc428d05aa4751e4d, 0xf53304714d9265e0, + 0x993fe2c6d07b7fac, 0xbf8fdb78849a5f97, 0xef73d256a5c0f77d, + 0x95a8637627989aae, 0xbb127c53b17ec159, 0xe9d71b689dde71b0, + 0x9226712162ab070e, 0xb6b00d69bb55c8d1, 0xe45c10c42a2b3b06, + 0x8eb98a7a9a5b04e3, 0xb267ed1940f1c61c, 0xdf01e85f912e37a3, + 0x8b61313bbabce2c6, 0xae397d8aa96c1b78, 0xd9c7dced53c72256, + 0x881cea14545c7575, 0xaa242499697392d3, 0xd4ad2dbfc3d07788, + 0x84ec3c97da624ab5, 0xa6274bbdd0fadd62, 0xcfb11ead453994ba, + 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3e, + 0xfd87b5f28300ca0e, 0x9e74d1b791e07e48, 0xc612062576589ddb, + 0xf79687aed3eec551, 0x9abe14cd44753b53, 0xc16d9a0095928a27, + 0xf1c90080baf72cb1, 0x971da05074da7bef, 0xbce5086492111aeb, + 0xec1e4a7db69561a5, 0x9392ee8e921d5d07, 0xb877aa3236a4b449, + 0xe69594bec44de15b, 0x901d7cf73ab0acd9, 0xb424dc35095cd80f, + 0xe12e13424bb40e13, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, + 0xdbe6fecebdedd5bf, 0x89705f4136b4a597, 0xabcc77118461cefd, + 0xd6bf94d5e57a42bc, 0x8637bd05af6c69b6, 0xa7c5ac471b478423, + 0xd1b71758e219652c, 0x83126e978d4fdf3b, 0xa3d70a3d70a3d70a, + 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, + 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, + 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, + 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, + 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, + 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, + 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, + 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, + 0xa18f07d736b90be5, 0xc9f2c9cd04674edf, 0xfc6f7c4045812296, + 0x9dc5ada82b70b59e, 0xc5371912364ce305, 0xf684df56c3e01bc7, + 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, + 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, + 0x92efd1b8d0cf37be, 0xb7abc627050305ae, 0xe596b7b0c643c719, + 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f, + 0x8c213d9da502de45, 0xaf298d050e4395d7, 0xdaf3f04651d47b4c, + 0x88d8762bf324cd10, 0xab0e93b6efee0054, 0xd5d238a4abe98068, + 0x85a36366eb71f041, 0xa70c3c40a64e6c52, 0xd0cf4b50cfe20766, + 0x82818f1281ed44a0, 0xa321f2d7226895c8, 0xcbea6f8ceb02bb3a, + 0xfee50b7025c36a08, 0x9f4f2726179a2245, 0xc722f0ef9d80aad6, + 0xf8ebad2b84e0d58c, 0x9b934c3b330c8577, 0xc2781f49ffcfa6d5, + 0xf316271c7fc3908b, 0x97edd871cfda3a57, 0xbde94e8e43d0c8ec, + 0xed63a231d4c4fb27, 0x945e455f24fb1cf9, 0xb975d6b6ee39e437, + 0xe7d34c64a9c85d44, 0x90e40fbeea1d3a4b, 0xb51d13aea4a488dd, + 0xe264589a4dcdab15, 0x8d7eb76070a08aed, 0xb0de65388cc8ada8, + 0xdd15fe86affad912, 0x8a2dbf142dfcc7ab, 0xacb92ed9397bf996, + 0xd7e77a8f87daf7fc, 0x86f0ac99b4e8dafd, 0xa8acd7c0222311bd, + 0xd2d80db02aabd62c, 0x83c7088e1aab65db, 0xa4b8cab1a1563f52, + 0xcde6fd5e09abcf27, 0x80b05e5ac60b6178, 0xa0dc75f1778e39d6, + 0xc913936dd571c84c, 0xfb5878494ace3a5f, 0x9d174b2dcec0e47b, + 0xc45d1df942711d9a, 0xf5746577930d6501, 0x9968bf6abbe85f20, + 0xbfc2ef456ae276e9, 0xefb3ab16c59b14a3, 0x95d04aee3b80ece6, + 0xbb445da9ca61281f, 0xea1575143cf97227, 0x924d692ca61be758, + 0xb6e0c377cfa2e12e, 0xe498f455c38b997a, 0x8edf98b59a373fec, + 0xb2977ee300c50fe7, 0xdf3d5e9bc0f653e1, 0x8b865b215899f46d, + 0xae67f1e9aec07188, 0xda01ee641a708dea, 0x884134fe908658b2, + 0xaa51823e34a7eedf, 0xd4e5e2cdc1d1ea96, 0x850fadc09923329e, + 0xa6539930bf6bff46, 0xcfe87f7cef46ff17, 0x81f14fae158c5f6e, + 0xa26da3999aef774a, 0xcb090c8001ab551c, 0xfdcb4fa002162a63, + 0x9e9f11c4014dda7e, 0xc646d63501a1511e, 0xf7d88bc24209a565, + 0x9ae757596946075f, 0xc1a12d2fc3978937, 0xf209787bb47d6b85, + 0x9745eb4d50ce6333, 0xbd176620a501fc00, 0xec5d3fa8ce427b00, + 0x93ba47c980e98ce0, 0xb8a8d9bbe123f018, 0xe6d3102ad96cec1e, + 0x9043ea1ac7e41393, 0xb454e4a179dd1877, 0xe16a1dc9d8545e95, + 0x8ce2529e2734bb1d, 0xb01ae745b101e9e4, 0xdc21a1171d42645d, + 0x899504ae72497eba, 0xabfa45da0edbde69, 0xd6f8d7509292d603, + 0x865b86925b9bc5c2, 0xa7f26836f282b733, 0xd1ef0244af2364ff, + 0x8335616aed761f1f, 0xa402b9c5a8d3a6e7, 0xcd036837130890a1, + 0x802221226be55a65, 0xa02aa96b06deb0fe, 0xc83553c5c8965d3d, + 0xfa42a8b73abbf48d, 0x9c69a97284b578d8, 0xc38413cf25e2d70e, + 0xf46518c2ef5b8cd1, 0x98bf2f79d5993803, 0xbeeefb584aff8604, + 0xeeaaba2e5dbf6785, 0x952ab45cfa97a0b3, 0xba756174393d88e0, + 0xe912b9d1478ceb17, 0x91abb422ccb812ef, 0xb616a12b7fe617aa, + 0xe39c49765fdf9d95, 0x8e41ade9fbebc27d, 0xb1d219647ae6b31c, + 0xde469fbd99a05fe3, 0x8aec23d680043bee, 0xada72ccc20054aea, + 0xd910f7ff28069da4, 0x87aa9aff79042287, 0xa99541bf57452b28, + 0xd3fa922f2d1675f2, 0x847c9b5d7c2e09b7, 0xa59bc234db398c25, + 0xcf02b2c21207ef2f, 0x8161afb94b44f57d, 0xa1ba1ba79e1632dc, + 0xca28a291859bbf93, 0xfcb2cb35e702af78, 0x9defbf01b061adab, + 0xc56baec21c7a1916, 0xf6c69a72a3989f5c, 0x9a3c2087a63f6399, + 0xc0cb28a98fcf3c80, 0xf0fdf2d3f3c30b9f, 0x969eb7c47859e744, + 0xbc4665b596706115, 0xeb57ff22fc0c795a, 0x9316ff75dd87cbd8, + 0xb7dcbf5354e9bece, 0xe5d3ef282a242e82, 0x8fa475791a569d11, + 0xb38d92d760ec4455, 0xe070f78d3927556b, 0x8c469ab843b89563, + 0xaf58416654a6babb, 0xdb2e51bfe9d0696a, 0x88fcf317f22241e2, + 0xab3c2fddeeaad25b, 0xd60b3bd56a5586f2, 0x85c7056562757457, + 0xa738c6bebb12d16d, 0xd106f86e69d785c8, 0x82a45b450226b39d, + 0xa34d721642b06084, 0xcc20ce9bd35c78a5, 0xff290242c83396ce, + 0x9f79a169bd203e41, 0xc75809c42c684dd1, 0xf92e0c3537826146, + 0x9bbcc7a142b17ccc, 0xc2abf989935ddbfe, 0xf356f7ebf83552fe, + 0x98165af37b2153df, 0xbe1bf1b059e9a8d6, 0xeda2ee1c7064130c, + 0x9485d4d1c63e8be8, 0xb9a74a0637ce2ee1, 0xe8111c87c5c1ba9a, + 0x910ab1d4db9914a0, 0xb54d5e4a127f59c8, 0xe2a0b5dc971f303a, + 0x8da471a9de737e24, 0xb10d8e1456105dad, 0xdd50f1996b947519, + 0x8a5296ffe33cc930, 0xace73cbfdc0bfb7b, 0xd8210befd30efa5a, + 0x8714a775e3e95c78, 0xa8d9d1535ce3b396, 0xd31045a8341ca07c, + 0x83ea2b892091e44e, 0xa4e4b66b68b65d61, 0xce1de40642e3f4b9, + 0x80d2ae83e9ce78f4, 0xa1075a24e4421731, 0xc94930ae1d529cfd, + 0xfb9b7cd9a4a7443c, 0x9d412e0806e88aa6, 0xc491798a08a2ad4f, + 0xf5b5d7ec8acb58a3, 0x9991a6f3d6bf1766, 0xbff610b0cc6edd3f, + 0xeff394dcff8a948f, 0x95f83d0a1fb69cd9, 0xbb764c4ca7a44410, + 0xea53df5fd18d5514, 0x92746b9be2f8552c, 0xb7118682dbb66a77, + 0xe4d5e82392a40515, 0x8f05b1163ba6832d, 0xb2c71d5bca9023f8, + 0xdf78e4b2bd342cf7, 0x8bab8eefb6409c1a, 0xae9672aba3d0c321, + 0xda3c0f568cc4f3e9, 0x8865899617fb1871, 0xaa7eebfb9df9de8e, + 0xd51ea6fa85785631, 0x8533285c936b35df, 0xa67ff273b8460357, + 0xd01fef10a657842c, 0x8213f56a67f6b29c, 0xa298f2c501f45f43, + 0xcb3f2f7642717713, 0xfe0efb53d30dd4d8, 0x9ec95d1463e8a507, + 0xc67bb4597ce2ce49, 0xf81aa16fdc1b81db, 0x9b10a4e5e9913129, + 0xc1d4ce1f63f57d73, 0xf24a01a73cf2dcd0, 0x976e41088617ca02, + 0xbd49d14aa79dbc82, 0xec9c459d51852ba3, 0x93e1ab8252f33b46, + 0xb8da1662e7b00a17, 0xe7109bfba19c0c9d, 0x906a617d450187e2, + 0xb484f9dc9641e9db, 0xe1a63853bbd26451, 0x8d07e33455637eb3, + 0xb049dc016abc5e60, 0xdc5c5301c56b75f7, 0x89b9b3e11b6329bb, + 0xac2820d9623bf429, 0xd732290fbacaf134, 0x867f59a9d4bed6c0, + 0xa81f301449ee8c70, 0xd226fc195c6a2f8c, 0x83585d8fd9c25db8, + 0xa42e74f3d032f526, 0xcd3a1230c43fb26f, 0x80444b5e7aa7cf85, + 0xa0555e361951c367, 0xc86ab5c39fa63441, 0xfa856334878fc151, + 0x9c935e00d4b9d8d2, 0xc3b8358109e84f07, 0xf4a642e14c6262c9, + 0x98e7e9cccfbd7dbe, 0xbf21e44003acdd2d, 0xeeea5d5004981478, + 0x95527a5202df0ccb, 0xbaa718e68396cffe, 0xe950df20247c83fd, + 0x91d28b7416cdd27e, 0xb6472e511c81471e, 0xe3d8f9e563a198e5, + 0x8e679c2f5e44ff8f, 0xb201833b35d63f73, 0xde81e40a034bcf50, + 0x8b112e86420f6192, 0xadd57a27d29339f6, 0xd94ad8b1c7380874, + 0x87cec76f1c830549, 0xa9c2794ae3a3c69b, 0xd433179d9c8cb841, + 0x849feec281d7f329, 0xa5c7ea73224deff3, 0xcf39e50feae16bf0, + 0x81842f29f2cce376, 0xa1e53af46f801c53, 0xca5e89b18b602368, + 0xfcf62c1dee382c42, 0x9e19db92b4e31ba9, 0xc5a05277621be294, + 0xf70867153aa2db39, 0x9a65406d44a5c903, 0xc0fe908895cf3b44, + 0xf13e34aabb430a15, 0x96c6e0eab509e64d, 0xbc789925624c5fe1, + 0xeb96bf6ebadf77d9, 0x933e37a534cbaae8, 0xb80dc58e81fe95a1, + 0xe61136f2227e3b0a, 0x8fcac257558ee4e6, 0xb3bd72ed2af29e20, + 0xe0accfa875af45a8, 0x8c6c01c9498d8b89, 0xaf87023b9bf0ee6b, + 0xdb68c2ca82ed2a06, 0x892179be91d43a44, 0xab69d82e364948d4 +}; + +static const int powers_ten_e[] = { + -1203, -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, + -1170, -1166, -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, + -1136, -1133, -1130, -1127, -1123, -1120, -1117, -1113, -1110, -1107, + -1103, -1100, -1097, -1093, -1090, -1087, -1083, -1080, -1077, -1073, + -1070, -1067, -1063, -1060, -1057, -1053, -1050, -1047, -1043, -1040, + -1037, -1034, -1030, -1027, -1024, -1020, -1017, -1014, -1010, -1007, + -1004, -1000, -997, -994, -990, -987, -984, -980, -977, -974, -970, + -967, -964, -960, -957, -954, -950, -947, -944, -940, -937, -934, -931, + -927, -924, -921, -917, -914, -911, -907, -904, -901, -897, -894, -891, + -887, -884, -881, -877, -874, -871, -867, -864, -861, -857, -854, -851, + -847, -844, -841, -838, -834, -831, -828, -824, -821, -818, -814, -811, + -808, -804, -801, -798, -794, -791, -788, -784, -781, -778, -774, -771, + -768, -764, -761, -758, -754, -751, -748, -744, -741, -738, -735, -731, + -728, -725, -721, -718, -715, -711, -708, -705, -701, -698, -695, -691, + -688, -685, -681, -678, -675, -671, -668, -665, -661, -658, -655, -651, + -648, -645, -642, -638, -635, -632, -628, -625, -622, -618, -615, -612, + -608, -605, -602, -598, -595, -592, -588, -585, -582, -578, -575, -572, + -568, -565, -562, -558, -555, -552, -549, -545, -542, -539, -535, -532, + -529, -525, -522, -519, -515, -512, -509, -505, -502, -499, -495, -492, + -489, -485, -482, -479, -475, -472, -469, -465, -462, -459, -455, -452, + -449, -446, -442, -439, -436, -432, -429, -426, -422, -419, -416, -412, + -409, -406, -402, -399, -396, -392, -389, -386, -382, -379, -376, -372, + -369, -366, -362, -359, -356, -353, -349, -346, -343, -339, -336, -333, + -329, -326, -323, -319, -316, -313, -309, -306, -303, -299, -296, -293, + -289, -286, -283, -279, -276, -273, -269, -266, -263, -259, -256, -253, + -250, -246, -243, -240, -236, -233, -230, -226, -223, -220, -216, -213, + -210, -206, -203, -200, -196, -193, -190, -186, -183, -180, -176, -173, + -170, -166, -163, -160, -157, -153, -150, -147, -143, -140, -137, -133, + -130, -127, -123, -120, -117, -113, -110, -107, -103, -100, -97, -93, + -90, -87, -83, -80, -77, -73, -70, -67, -63, -60, -57, -54, -50, -47, + -44, -40, -37, -34, -30, -27, -24, -20, -17, -14, -10, -7, -4, 0, 3, 6, + 10, 13, 16, 20, 23, 26, 30, 33, 36, 39, 43, 46, 49, 53, 56, 59, 63, 66, + 69, 73, 76, 79, 83, 86, 89, 93, 96, 99, 103, 106, 109, 113, 116, 119, + 123, 126, 129, 132, 136, 139, 142, 146, 149, 152, 156, 159, 162, 166, + 169, 172, 176, 179, 182, 186, 189, 192, 196, 199, 202, 206, 209, 212, + 216, 219, 222, 226, 229, 232, 235, 239, 242, 245, 249, 252, 255, 259, + 262, 265, 269, 272, 275, 279, 282, 285, 289, 292, 295, 299, 302, 305, + 309, 312, 315, 319, 322, 325, 328, 332, 335, 338, 342, 345, 348, 352, + 355, 358, 362, 365, 368, 372, 375, 378, 382, 385, 388, 392, 395, 398, + 402, 405, 408, 412, 415, 418, 422, 425, 428, 431, 435, 438, 441, 445, + 448, 451, 455, 458, 461, 465, 468, 471, 475, 478, 481, 485, 488, 491, + 495, 498, 501, 505, 508, 511, 515, 518, 521, 524, 528, 531, 534, 538, + 541, 544, 548, 551, 554, 558, 561, 564, 568, 571, 574, 578, 581, 584, + 588, 591, 594, 598, 601, 604, 608, 611, 614, 617, 621, 624, 627, 631, + 634, 637, 641, 644, 647, 651, 654, 657, 661, 664, 667, 671, 674, 677, + 681, 684, 687, 691, 694, 697, 701, 704, 707, 711, 714, 717, 720, 724, + 727, 730, 734, 737, 740, 744, 747, 750, 754, 757, 760, 764, 767, 770, + 774, 777, 780, 784, 787, 790, 794, 797, 800, 804, 807, 810, 813, 817, + 820, 823, 827, 830, 833, 837, 840, 843, 847, 850, 853, 857, 860, 863, + 867, 870, 873, 877, 880, 883, 887, 890, 893, 897, 900, 903, 907, 910, + 913, 916, 920, 923, 926, 930, 933, 936, 940, 943, 946, 950, 953, 956, + 960, 963, 966, 970, 973, 976, 980, 983, 986, 990, 993, 996, 1000, 1003, + 1006, 1009, 1013, 1016, 1019, 1023, 1026, 1029, 1033, 1036, 1039, 1043, + 1046, 1049, 1053, 1056, 1059, 1063, 1066, 1069, 1073, 1076 +}; + +static diy_fp_t cached_power(int k) +{ + diy_fp_t res; + int index = 343 + k; + res.f = powers_ten[index]; + res.e = powers_ten_e[index]; + return res; +} + +static int k_comp(int e, int alpha, int gamma) { + return ceil((alpha-e+63) * D_1_LOG2_10); +} + +static diy_fp_t minus(diy_fp_t x, diy_fp_t y) +{ + diy_fp_t r; + assert(x.e == y.e); + assert(x.f >= y.f); + r.f = x.f - y.f; + r.e = x.e; + return r; +} + +static diy_fp_t multiply(diy_fp_t x, diy_fp_t y) +{ + uint64_t a,b,c,d,ac,bc,ad,bd,tmp; + diy_fp_t r; + uint64_t M32 = 0xFFFFFFFF; + a = x.f >> 32; b = x.f & M32; + c = y.f >> 32; d = y.f & M32; + ac = a*c; bc = b*c; ad = a*d; bd = b*d; + tmp = (bd>>32) + (ad&M32) + (bc&M32); + tmp += 1U << 31; + r.f = ac+(ad>>32)+(bc>>32)+(tmp >>32); + r.e = x.e + y.e + 64; + return r; +} + +static uint64_t double_to_uint64(double d) +{ + uint64_t n; + memcpy(&n, &d, 8); + return n; +} + +#define DP_SIGNIFICAND_SIZE 52 +#define DP_EXPONENT_BIAS (0x3FF + DP_SIGNIFICAND_SIZE) +#define DP_MIN_EXPONENT (-DP_EXPONENT_BIAS) +#define DP_EXPONENT_MASK 0x7FF0000000000000 +#define DP_SIGNIFICAND_MASK 0x000FFFFFFFFFFFFF +#define DP_HIDDEN_BIT 0x0010000000000000 + +static diy_fp_t double2diy_fp(double d) +{ + uint64_t d64 = double_to_uint64(d); + int biased_e = (d64 & DP_EXPONENT_MASK) >> DP_SIGNIFICAND_SIZE; + uint64_t significand = (d64 & DP_SIGNIFICAND_MASK); + diy_fp_t res; + if (biased_e != 0) { + res.f = significand + DP_HIDDEN_BIT; + res.e = biased_e - DP_EXPONENT_BIAS; + } else { + res.f = significand; + res.e = DP_MIN_EXPONENT + 1; + } + return res; +} + +static diy_fp_t normalize_boundary(diy_fp_t in) +{ + diy_fp_t res = in; + /* Normalize now */ + /* the original number could have been a denormal. */ + while (! (res.f & (DP_HIDDEN_BIT << 1))) { + res.f <<= 1; + res.e--; + } + /* do the final shifts in one go. Don't forget the hidden bit (the '-1') */ + res.f <<= (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2); + res.e = res.e - (DIY_SIGNIFICAND_SIZE - DP_SIGNIFICAND_SIZE - 2); + return res; +} + +static void normalized_boundaries(double d, diy_fp_t* out_m_minus, diy_fp_t* out_m_plus) +{ + diy_fp_t v = double2diy_fp(d); + diy_fp_t pl, mi; + int significand_is_zero = v.f == DP_HIDDEN_BIT; + pl.f = (v.f << 1) + 1; pl.e = v.e - 1; + pl = normalize_boundary(pl); + if (significand_is_zero) { + mi.f = (v.f << 2) - 1; + mi.e = v.e - 2; + } else { + mi.f = (v.f << 1) - 1; + mi.e = v.e - 1; + } + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *out_m_plus = pl; + *out_m_minus = mi; +} + +#define TEN2 100 +static void digit_gen(diy_fp_t Mp, diy_fp_t delta, char* buffer, int* len, int* K) +{ + uint32_t div, p1; + uint64_t p2; + int d,kappa; + diy_fp_t one; + one.f = ((uint64_t) 1) << -Mp.e; one.e = Mp.e; + p1 = Mp.f >> -one.e; + p2 = Mp.f & (one.f - 1); + *len = 0; kappa = 3; div = TEN2; + while (kappa > 0) { + d = p1 / div; + if (d || *len) buffer[(*len)++] = '0' + d; + p1 %= div; kappa--; div /= 10; + if ((((uint64_t)p1)<<-one.e)+p2 <= delta.f) { + *K += kappa; return; + } + } + do { + p2 *= 10; + d = p2 >> -one.e; + if (d || *len) buffer[(*len)++] = '0' + d; + p2 &= one.f - 1; kappa--; delta.f *= 10; + } while (p2 > delta.f); + *K += kappa; +} + +int +js_grisu2(double v, char *buffer, int *K) +{ + int length, mk; + diy_fp_t w_m, w_p, c_mk, Wp, Wm, delta; + int q = 64, alpha = -59, gamma = -56; + normalized_boundaries(v, &w_m, &w_p); + mk = k_comp(w_p.e + q, alpha, gamma); + c_mk = cached_power(mk); + Wp = multiply(w_p, c_mk); + Wm = multiply(w_m, c_mk); + Wm.f++; Wp.f--; + delta = minus(Wp, Wm); + *K = -mk; + digit_gen(Wp, delta, buffer, &length, K); + return length; +} + +/* + * strtod.c + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies. The University of + * California makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + */ + +/* Largest possible base 10 exponent. Any exponent larger than this will + * already produce underflow or overflow, so there's no need to worry about + * additional digits. + */ +static int maxExponent = 511; + +/* Table giving binary powers of 10. Entry + * is 10^2^i. Used to convert decimal + * exponents into floating-point numbers. + */ +static double powersOf10[] = { + 10., + 100., + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +/* Parse a decimal ASCII floating-point number, optionally preceded by white + * space. Must have form "-I.FE-X", where I is the integer part of the + * mantissa, F is the fractional part of the mantissa, and X is the exponent. + * Either of the signs may be "+", "-", or omitted. Either I or F may be + * omitted, or both. The decimal point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X may both be omitted (but not just + * one). + */ +double +js_strtod(const char *string, char **endPtr) +{ + int sign, expSign = FALSE; + double fraction, dblExp, *d; + register const char *p; + register int c; + + /* Exponent read from "EX" field. */ + int exp = 0; + + /* Exponent that derives from the fractional part. Under normal + * circumstances, it is the negative of the number of digits in F. + * However, if I is very long, the last digits of I get dropped + * (otherwise a long I with a large negative exponent could cause an + * unnecessary overflow on I alone). In this case, fracExp is + * incremented one for each dropped digit. + */ + int fracExp = 0; + + /* Number of digits in mantissa. */ + int mantSize; + + /* Number of mantissa digits BEFORE decimal point. */ + int decPt; + + /* Temporarily holds location of exponent in string. */ + const char *pExp; + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!(c>='0'&&c<='9')) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while ((*p >= '0') && (*p <= '9')) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < -maxExponent) { + exp = maxExponent; + expSign = TRUE; + errno = ERANGE; + } else if (exp > maxExponent) { + exp = maxExponent; + expSign = FALSE; + errno = ERANGE; + } else if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} diff --git a/programs/develop/kosjs/libmujs/jsdump.c b/programs/develop/kosjs/libmujs/jsdump.c new file mode 100755 index 0000000000..8f0ff69cb2 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsdump.c @@ -0,0 +1,924 @@ +#include "jsi.h" +#include "jsparse.h" +#include "jscompile.h" +#include "jsvalue.h" + +#include "utf.h" + +#include + +static const char *astname[] = { +#include "astnames.h" +NULL +}; + +static const char *opname[] = { +#include "opnames.h" +NULL +}; + +static int minify = 0; + +const char *jsP_aststring(enum js_AstType type) +{ + if (type < nelem(astname)-1) + return astname[type]; + return ""; +} + +const char *jsC_opcodestring(enum js_OpCode opcode) +{ + if (opcode < nelem(opname)-1) + return opname[opcode]; + return ""; +} + +static int prec(enum js_AstType type) +{ + switch (type) { + case AST_IDENTIFIER: + case EXP_IDENTIFIER: + case EXP_NUMBER: + case EXP_STRING: + case EXP_REGEXP: + case EXP_UNDEF: + case EXP_NULL: + case EXP_TRUE: + case EXP_FALSE: + case EXP_THIS: + case EXP_ARRAY: + case EXP_OBJECT: + return 170; + + case EXP_FUN: + case EXP_INDEX: + case EXP_MEMBER: + case EXP_CALL: + case EXP_NEW: + return 160; + + case EXP_POSTINC: + case EXP_POSTDEC: + return 150; + + case EXP_DELETE: + case EXP_VOID: + case EXP_TYPEOF: + case EXP_PREINC: + case EXP_PREDEC: + case EXP_POS: + case EXP_NEG: + case EXP_BITNOT: + case EXP_LOGNOT: + return 140; + + case EXP_MOD: + case EXP_DIV: + case EXP_MUL: + return 130; + + case EXP_SUB: + case EXP_ADD: + return 120; + + case EXP_USHR: + case EXP_SHR: + case EXP_SHL: + return 110; + + case EXP_IN: + case EXP_INSTANCEOF: + case EXP_GE: + case EXP_LE: + case EXP_GT: + case EXP_LT: + return 100; + + case EXP_STRICTNE: + case EXP_STRICTEQ: + case EXP_NE: + case EXP_EQ: + return 90; + + case EXP_BITAND: return 80; + case EXP_BITXOR: return 70; + case EXP_BITOR: return 60; + case EXP_LOGAND: return 50; + case EXP_LOGOR: return 40; + + case EXP_COND: + return 30; + + case EXP_ASS: + case EXP_ASS_MUL: + case EXP_ASS_DIV: + case EXP_ASS_MOD: + case EXP_ASS_ADD: + case EXP_ASS_SUB: + case EXP_ASS_SHL: + case EXP_ASS_SHR: + case EXP_ASS_USHR: + case EXP_ASS_BITAND: + case EXP_ASS_BITXOR: + case EXP_ASS_BITOR: + return 20; + +#define COMMA 15 + + case EXP_COMMA: + return 10; + + default: + return 0; + } +} + +static void pc(int c) +{ + putchar(c); +} + +static void ps(const char *s) +{ + fputs(s, stdout); +} + +static void pn(int n) +{ + printf("%d", n); +} + +static void in(int d) +{ + if (minify < 1) + while (d-- > 0) + putchar('\t'); +} + +static void nl(void) +{ + if (minify < 2) + putchar('\n'); +} + +static void sp(void) +{ + if (minify < 1) + putchar(' '); +} + +static void comma(void) +{ + putchar(','); + sp(); +} + +/* Pretty-printed Javascript syntax */ + +static void pstmlist(int d, js_Ast *list); +static void pexpi(int d, int i, js_Ast *exp); +static void pstm(int d, js_Ast *stm); +static void slist(int d, js_Ast *list); +static void sblock(int d, js_Ast *list); + +static void pargs(int d, js_Ast *list) +{ + while (list) { + assert(list->type == AST_LIST); + pexpi(d, COMMA, list->a); + list = list->b; + if (list) + comma(); + } +} + +static void parray(int d, js_Ast *list) +{ + pc('['); + while (list) { + assert(list->type == AST_LIST); + pexpi(d, COMMA, list->a); + list = list->b; + if (list) + comma(); + } + pc(']'); +} + +static void pobject(int d, js_Ast *list) +{ + pc('{'); + if (list) { + nl(); + in(d+1); + } + while (list) { + js_Ast *kv = list->a; + assert(list->type == AST_LIST); + switch (kv->type) { + default: break; + case EXP_PROP_VAL: + pexpi(d+1, COMMA, kv->a); + pc(':'); sp(); + pexpi(d+1, COMMA, kv->b); + break; + case EXP_PROP_GET: + ps("get "); + pexpi(d+1, COMMA, kv->a); + ps("()"); sp(); pc('{'); nl(); + pstmlist(d+1, kv->c); + in(d+1); pc('}'); + break; + case EXP_PROP_SET: + ps("set "); + pexpi(d+1, COMMA, kv->a); + pc('('); + pargs(d+1, kv->b); + pc(')'); sp(); pc('{'); nl(); + pstmlist(d+1, kv->c); + in(d+1); pc('}'); + break; + } + list = list->b; + if (list) { + pc(','); + nl(); + in(d+1); + } else { + nl(); + in(d); + } + } + pc('}'); +} + +static void pstr(const char *s) +{ + static const char *HEX = "0123456789ABCDEF"; + Rune c; + pc(minify ? '\'' : '"'); + while (*s) { + s += chartorune(&c, s); + switch (c) { + case '\'': ps("\\'"); break; + case '"': ps("\\\""); break; + case '\\': ps("\\\\"); break; + case '\b': ps("\\b"); break; + case '\f': ps("\\f"); break; + case '\n': ps("\\n"); break; + case '\r': ps("\\r"); break; + case '\t': ps("\\t"); break; + default: + if (c < ' ' || c > 127) { + ps("\\u"); + pc(HEX[(c>>12)&15]); + pc(HEX[(c>>8)&15]); + pc(HEX[(c>>4)&15]); + pc(HEX[c&15]); + } else { + pc(c); break; + } + } + } + pc(minify ? '\'' : '"'); +} + +static void pregexp(const char *prog, int flags) +{ + pc('/'); + ps(prog); + pc('/'); + if (flags & JS_REGEXP_G) pc('g'); + if (flags & JS_REGEXP_I) pc('i'); + if (flags & JS_REGEXP_M) pc('m'); +} + +static void pbin(int d, int p, js_Ast *exp, const char *op) +{ + pexpi(d, p, exp->a); + sp(); + ps(op); + sp(); + pexpi(d, p, exp->b); +} + +static void puna(int d, int p, js_Ast *exp, const char *pre, const char *suf) +{ + ps(pre); + pexpi(d, p, exp->a); + ps(suf); +} + +static void pexpi(int d, int p, js_Ast *exp) +{ + int tp, paren; + + if (!exp) return; + + tp = prec(exp->type); + paren = 0; + if (tp < p) { + pc('('); + paren = 1; + } + p = tp; + + switch (exp->type) { + case AST_IDENTIFIER: ps(exp->string); break; + case EXP_IDENTIFIER: ps(exp->string); break; + case EXP_NUMBER: printf("%.9g", exp->number); break; + case EXP_STRING: pstr(exp->string); break; + case EXP_REGEXP: pregexp(exp->string, exp->number); break; + + case EXP_UNDEF: break; + case EXP_NULL: ps("null"); break; + case EXP_TRUE: ps("true"); break; + case EXP_FALSE: ps("false"); break; + case EXP_THIS: ps("this"); break; + + case EXP_OBJECT: pobject(d, exp->a); break; + case EXP_ARRAY: parray(d, exp->a); break; + + case EXP_DELETE: puna(d, p, exp, "delete ", ""); break; + case EXP_VOID: puna(d, p, exp, "void ", ""); break; + case EXP_TYPEOF: puna(d, p, exp, "typeof ", ""); break; + case EXP_PREINC: puna(d, p, exp, "++", ""); break; + case EXP_PREDEC: puna(d, p, exp, "--", ""); break; + case EXP_POSTINC: puna(d, p, exp, "", "++"); break; + case EXP_POSTDEC: puna(d, p, exp, "", "--"); break; + case EXP_POS: puna(d, p, exp, "+", ""); break; + case EXP_NEG: puna(d, p, exp, "-", ""); break; + case EXP_BITNOT: puna(d, p, exp, "~", ""); break; + case EXP_LOGNOT: puna(d, p, exp, "!", ""); break; + + case EXP_LOGOR: pbin(d, p, exp, "||"); break; + case EXP_LOGAND: pbin(d, p, exp, "&&"); break; + case EXP_BITOR: pbin(d, p, exp, "|"); break; + case EXP_BITXOR: pbin(d, p, exp, "^"); break; + case EXP_BITAND: pbin(d, p, exp, "&"); break; + case EXP_EQ: pbin(d, p, exp, "=="); break; + case EXP_NE: pbin(d, p, exp, "!="); break; + case EXP_STRICTEQ: pbin(d, p, exp, "==="); break; + case EXP_STRICTNE: pbin(d, p, exp, "!=="); break; + case EXP_LT: pbin(d, p, exp, "<"); break; + case EXP_GT: pbin(d, p, exp, ">"); break; + case EXP_LE: pbin(d, p, exp, "<="); break; + case EXP_GE: pbin(d, p, exp, ">="); break; + case EXP_IN: pbin(d, p, exp, "in"); break; + case EXP_SHL: pbin(d, p, exp, "<<"); break; + case EXP_SHR: pbin(d, p, exp, ">>"); break; + case EXP_USHR: pbin(d, p, exp, ">>>"); break; + case EXP_ADD: pbin(d, p, exp, "+"); break; + case EXP_SUB: pbin(d, p, exp, "-"); break; + case EXP_MUL: pbin(d, p, exp, "*"); break; + case EXP_DIV: pbin(d, p, exp, "/"); break; + case EXP_MOD: pbin(d, p, exp, "%"); break; + case EXP_ASS: pbin(d, p, exp, "="); break; + case EXP_ASS_MUL: pbin(d, p, exp, "*="); break; + case EXP_ASS_DIV: pbin(d, p, exp, "/="); break; + case EXP_ASS_MOD: pbin(d, p, exp, "%="); break; + case EXP_ASS_ADD: pbin(d, p, exp, "+="); break; + case EXP_ASS_SUB: pbin(d, p, exp, "-="); break; + case EXP_ASS_SHL: pbin(d, p, exp, "<<="); break; + case EXP_ASS_SHR: pbin(d, p, exp, ">>="); break; + case EXP_ASS_USHR: pbin(d, p, exp, ">>>="); break; + case EXP_ASS_BITAND: pbin(d, p, exp, "&="); break; + case EXP_ASS_BITXOR: pbin(d, p, exp, "^="); break; + case EXP_ASS_BITOR: pbin(d, p, exp, "|="); break; + + case EXP_INSTANCEOF: + pexpi(d, p, exp->a); + ps(" instanceof "); + pexpi(d, p, exp->b); + break; + + case EXP_COMMA: + pexpi(d, p, exp->a); + pc(','); sp(); + pexpi(d, p, exp->b); + break; + + case EXP_COND: + pexpi(d, p, exp->a); + sp(); pc('?'); sp(); + pexpi(d, p, exp->b); + sp(); pc(':'); sp(); + pexpi(d, p, exp->c); + break; + + case EXP_INDEX: + pexpi(d, p, exp->a); + pc('['); + pexpi(d, 0, exp->b); + pc(']'); + break; + + case EXP_MEMBER: + pexpi(d, p, exp->a); + pc('.'); + pexpi(d, 0, exp->b); + break; + + case EXP_CALL: + pexpi(d, p, exp->a); + pc('('); + pargs(d, exp->b); + pc(')'); + break; + + case EXP_NEW: + ps("new "); + pexpi(d, p, exp->a); + pc('('); + pargs(d, exp->b); + pc(')'); + break; + + case EXP_FUN: + if (p == 0) pc('('); + ps("function "); + pexpi(d, 0, exp->a); + pc('('); + pargs(d, exp->b); + pc(')'); sp(); pc('{'); nl(); + pstmlist(d, exp->c); + in(d); pc('}'); + if (p == 0) pc(')'); + break; + + default: + ps(""); + break; + } + + if (paren) pc(')'); +} + +static void pexp(int d, js_Ast *exp) +{ + pexpi(d, 0, exp); +} + +static void pvar(int d, js_Ast *var) +{ + assert(var->type == EXP_VAR); + pexp(d, var->a); + if (var->b) { + sp(); pc('='); sp(); + pexp(d, var->b); + } +} + +static void pvarlist(int d, js_Ast *list) +{ + while (list) { + assert(list->type == AST_LIST); + pvar(d, list->a); + list = list->b; + if (list) + comma(); + } +} + +static void pblock(int d, js_Ast *block) +{ + assert(block->type == STM_BLOCK); + pc('{'); nl(); + pstmlist(d, block->a); + in(d); pc('}'); +} + +static void pstmh(int d, js_Ast *stm) +{ + if (stm->type == STM_BLOCK) { + sp(); + pblock(d, stm); + } else { + nl(); + pstm(d+1, stm); + } +} + +static void pcaselist(int d, js_Ast *list) +{ + while (list) { + js_Ast *stm = list->a; + if (stm->type == STM_CASE) { + in(d); ps("case "); pexp(d, stm->a); pc(':'); nl(); + pstmlist(d, stm->b); + } + if (stm->type == STM_DEFAULT) { + in(d); ps("default:"); nl(); + pstmlist(d, stm->a); + } + list = list->b; + } +} + +static void pstm(int d, js_Ast *stm) +{ + if (stm->type == STM_BLOCK) { + pblock(d, stm); + return; + } + + in(d); + + switch (stm->type) { + case AST_FUNDEC: + ps("function "); + pexp(d, stm->a); + pc('('); + pargs(d, stm->b); + pc(')'); sp(); pc('{'); nl(); + pstmlist(d, stm->c); + in(d); pc('}'); + break; + + case STM_EMPTY: + pc(';'); + break; + + case STM_VAR: + ps("var "); + pvarlist(d, stm->a); + pc(';'); + break; + + case STM_IF: + ps("if"); sp(); pc('('); pexp(d, stm->a); pc(')'); + pstmh(d, stm->b); + if (stm->c) { + nl(); in(d); ps("else"); + pstmh(d, stm->c); + } + break; + + case STM_DO: + ps("do"); + pstmh(d, stm->a); + nl(); + in(d); ps("while"); sp(); pc('('); pexp(d, stm->b); pc(')'); pc(';'); + break; + + case STM_WHILE: + ps("while"); sp(); pc('('); pexp(d, stm->a); pc(')'); + pstmh(d, stm->b); + break; + + case STM_FOR: + ps("for"); sp(); pc('('); + pexp(d, stm->a); pc(';'); sp(); + pexp(d, stm->b); pc(';'); sp(); + pexp(d, stm->c); pc(')'); + pstmh(d, stm->d); + break; + case STM_FOR_VAR: + ps("for"); sp(); ps("(var "); + pvarlist(d, stm->a); pc(';'); sp(); + pexp(d, stm->b); pc(';'); sp(); + pexp(d, stm->c); pc(')'); + pstmh(d, stm->d); + break; + case STM_FOR_IN: + ps("for"); sp(); pc('('); + pexp(d, stm->a); ps(" in "); + pexp(d, stm->b); pc(')'); + pstmh(d, stm->c); + break; + case STM_FOR_IN_VAR: + ps("for"); sp(); ps("(var "); + pvarlist(d, stm->a); ps(" in "); + pexp(d, stm->b); pc(')'); + pstmh(d, stm->c); + break; + + case STM_CONTINUE: + ps("continue"); + if (stm->a) { + pc(' '); pexp(d, stm->a); + } + pc(';'); + break; + + case STM_BREAK: + ps("break"); + if (stm->a) { + pc(' '); pexp(d, stm->a); + } + pc(';'); + break; + + case STM_RETURN: + ps("return"); + if (stm->a) { + pc(' '); pexp(d, stm->a); + } + pc(';'); + break; + + case STM_WITH: + ps("with"); sp(); pc('('); pexp(d, stm->a); pc(')'); + pstmh(d, stm->b); + break; + + case STM_SWITCH: + ps("switch"); sp(); pc('('); + pexp(d, stm->a); + pc(')'); sp(); pc('{'); nl(); + pcaselist(d, stm->b); + in(d); pc('}'); + break; + + case STM_THROW: + ps("throw "); pexp(d, stm->a); pc(';'); + break; + + case STM_TRY: + ps("try"); + if (minify && stm->a->type != STM_BLOCK) + pc(' '); + pstmh(d, stm->a); + if (stm->b && stm->c) { + nl(); in(d); ps("catch"); sp(); pc('('); pexp(d, stm->b); pc(')'); + pstmh(d, stm->c); + } + if (stm->d) { + nl(); in(d); ps("finally"); + pstmh(d, stm->d); + } + break; + + case STM_LABEL: + pexp(d, stm->a); pc(':'); sp(); pstm(d, stm->b); + break; + + case STM_DEBUGGER: + ps("debugger"); + pc(';'); + break; + + default: + pexp(d, stm); + pc(';'); + } +} + +static void pstmlist(int d, js_Ast *list) +{ + while (list) { + assert(list->type == AST_LIST); + pstm(d+1, list->a); + nl(); + list = list->b; + } +} + +void jsP_dumpsyntax(js_State *J, js_Ast *prog, int dominify) +{ + minify = dominify; + if (prog->type == AST_LIST) + pstmlist(-1, prog); + else { + pstm(0, prog); + nl(); + } + if (minify > 1) + putchar('\n'); +} + +/* S-expression list representation */ + +static void snode(int d, js_Ast *node) +{ + void (*afun)(int,js_Ast*) = snode; + void (*bfun)(int,js_Ast*) = snode; + void (*cfun)(int,js_Ast*) = snode; + void (*dfun)(int,js_Ast*) = snode; + + if (!node) { + return; + } + + if (node->type == AST_LIST) { + slist(d, node); + return; + } + + pc('('); + ps(astname[node->type]); + pc(':'); + pn(node->line); + switch (node->type) { + default: break; + case AST_IDENTIFIER: pc(' '); ps(node->string); break; + case EXP_IDENTIFIER: pc(' '); ps(node->string); break; + case EXP_STRING: pc(' '); pstr(node->string); break; + case EXP_REGEXP: pc(' '); pregexp(node->string, node->number); break; + case EXP_NUMBER: printf(" %.9g", node->number); break; + case STM_BLOCK: afun = sblock; break; + case AST_FUNDEC: case EXP_FUN: cfun = sblock; break; + case EXP_PROP_GET: cfun = sblock; break; + case EXP_PROP_SET: cfun = sblock; break; + case STM_SWITCH: bfun = sblock; break; + case STM_CASE: bfun = sblock; break; + case STM_DEFAULT: afun = sblock; break; + } + if (node->a) { pc(' '); afun(d, node->a); } + if (node->b) { pc(' '); bfun(d, node->b); } + if (node->c) { pc(' '); cfun(d, node->c); } + if (node->d) { pc(' '); dfun(d, node->d); } + pc(')'); +} + +static void slist(int d, js_Ast *list) +{ + pc('['); + while (list) { + assert(list->type == AST_LIST); + snode(d, list->a); + list = list->b; + if (list) + pc(' '); + } + pc(']'); +} + +static void sblock(int d, js_Ast *list) +{ + ps("[\n"); + in(d+1); + while (list) { + assert(list->type == AST_LIST); + snode(d+1, list->a); + list = list->b; + if (list) { + nl(); + in(d+1); + } + } + nl(); in(d); pc(']'); +} + +void jsP_dumplist(js_State *J, js_Ast *prog) +{ + minify = 0; + if (prog->type == AST_LIST) + sblock(0, prog); + else + snode(0, prog); + nl(); +} + +/* Compiled code */ + +void jsC_dumpfunction(js_State *J, js_Function *F) +{ + js_Instruction *p = F->code; + js_Instruction *end = F->code + F->codelen; + int i; + + minify = 0; + + printf("%s(%d)\n", F->name, F->numparams); + if (F->lightweight) printf("\tlightweight\n"); + if (F->arguments) printf("\targuments\n"); + printf("\tsource %s:%d\n", F->filename, F->line); + for (i = 0; i < F->funlen; ++i) + printf("\tfunction %d %s\n", i, F->funtab[i]->name); + for (i = 0; i < F->varlen; ++i) + printf("\tlocal %d %s\n", i + 1, F->vartab[i]); + + printf("{\n"); + while (p < end) { + int ln = *p++; + int c = *p++; + + printf("%5d(%3d): ", (int)(p - F->code) - 2, ln); + ps(opname[c]); + + switch (c) { + case OP_INTEGER: + printf(" %ld", (long)((*p++) - 32768)); + break; + case OP_NUMBER: + printf(" %.9g", F->numtab[*p++]); + break; + case OP_STRING: + pc(' '); + pstr(F->strtab[*p++]); + break; + case OP_NEWREGEXP: + pc(' '); + pregexp(F->strtab[p[0]], p[1]); + p += 2; + break; + + case OP_GETVAR: + case OP_HASVAR: + case OP_SETVAR: + case OP_DELVAR: + case OP_GETPROP_S: + case OP_SETPROP_S: + case OP_DELPROP_S: + case OP_CATCH: + pc(' '); + ps(F->strtab[*p++]); + break; + + case OP_GETLOCAL: + case OP_SETLOCAL: + case OP_DELLOCAL: + printf(" %s", F->vartab[*p++ - 1]); + break; + + case OP_CLOSURE: + case OP_CALL: + case OP_NEW: + case OP_JUMP: + case OP_JTRUE: + case OP_JFALSE: + case OP_JCASE: + case OP_TRY: + printf(" %ld", (long)*p++); + break; + } + + nl(); + } + printf("}\n"); + + for (i = 0; i < F->funlen; ++i) { + if (F->funtab[i] != F) { + printf("function %d ", i); + jsC_dumpfunction(J, F->funtab[i]); + } + } +} + +/* Runtime values */ + +void js_dumpvalue(js_State *J, js_Value v) +{ + minify = 0; + switch (v.type) { + case JS_TUNDEFINED: printf("undefined"); break; + case JS_TNULL: printf("null"); break; + case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break; + case JS_TNUMBER: printf("%.9g", v.u.number); break; + case JS_TSHRSTR: printf("'%s'", v.u.shrstr); break; + case JS_TLITSTR: printf("'%s'", v.u.litstr); break; + case JS_TMEMSTR: printf("'%s'", v.u.memstr->p); break; + case JS_TOBJECT: + if (v.u.object == J->G) { + printf("[Global]"); + break; + } + switch (v.u.object->type) { + case JS_COBJECT: printf("[Object %p]", (void*)v.u.object); break; + case JS_CARRAY: printf("[Array %p]", (void*)v.u.object); break; + case JS_CFUNCTION: + printf("[Function %p, %s, %s:%d]", + (void*)v.u.object, + v.u.object->u.f.function->name, + v.u.object->u.f.function->filename, + v.u.object->u.f.function->line); + break; + case JS_CSCRIPT: printf("[Script %s]", v.u.object->u.f.function->filename); break; + case JS_CEVAL: printf("[Eval %s]", v.u.object->u.f.function->filename); break; + case JS_CCFUNCTION: printf("[CFunction %s]", v.u.object->u.c.name); break; + case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break; + case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break; + case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break; + case JS_CERROR: printf("[Error]"); break; + case JS_CARGUMENTS: printf("[Arguments %p]", (void*)v.u.object); break; + case JS_CITERATOR: printf("[Iterator %p]", (void*)v.u.object); break; + case JS_CUSERDATA: + printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data); + break; + default: printf("[Object %p]", (void*)v.u.object); break; + } + break; + } +} + +static void js_dumpproperty(js_State *J, js_Property *node) +{ + minify = 0; + if (node->left->level) + js_dumpproperty(J, node->left); + printf("\t%s: ", node->name); + js_dumpvalue(J, node->value); + printf(",\n"); + if (node->right->level) + js_dumpproperty(J, node->right); +} + +void js_dumpobject(js_State *J, js_Object *obj) +{ + minify = 0; + printf("{\n"); + if (obj->properties->level) + js_dumpproperty(J, obj->properties); + printf("}\n"); +} diff --git a/programs/develop/kosjs/libmujs/jserror.c b/programs/develop/kosjs/libmujs/jserror.c new file mode 100755 index 0000000000..b3a71f0e03 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jserror.c @@ -0,0 +1,132 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +#define QQ(X) #X +#define Q(X) QQ(X) + +static int jsB_stacktrace(js_State *J, int skip) +{ + char buf[256]; + int n = J->tracetop - skip; + if (n <= 0) + return 0; + for (; n > 0; --n) { + const char *name = J->trace[n].name; + const char *file = J->trace[n].file; + int line = J->trace[n].line; + if (line > 0) { + if (name[0]) + snprintf(buf, sizeof buf, "\n\tat %s (%s:%d)", name, file, line); + else + snprintf(buf, sizeof buf, "\n\tat %s:%d", file, line); + } else + snprintf(buf, sizeof buf, "\n\tat %s (%s)", name, file); + js_pushstring(J, buf); + if (n < J->tracetop - skip) + js_concat(J); + } + return 1; +} + +static void Ep_toString(js_State *J) +{ + const char *name = "Error"; + const char *message = ""; + + if (!js_isobject(J, -1)) + js_typeerror(J, "not an object"); + + if (js_hasproperty(J, 0, "name")) + name = js_tostring(J, -1); + if (js_hasproperty(J, 0, "message")) + message = js_tostring(J, -1); + + if (name[0] == 0) + js_pushstring(J, message); + else if (message[0] == 0) + js_pushstring(J, name); + else { + js_pushstring(J, name); + js_pushstring(J, ": "); + js_concat(J); + js_pushstring(J, message); + js_concat(J); + } +} + +static int jsB_ErrorX(js_State *J, js_Object *prototype) +{ + int top = js_gettop(J); + js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype)); + if (top > 1) { + js_pushstring(J, js_tostring(J, 1)); + js_defproperty(J, -2, "message", JS_DONTENUM); + } + if (jsB_stacktrace(J, 1)) + js_defproperty(J, -2, "stackTrace", JS_DONTENUM); + return 1; +} + +static void js_newerrorx(js_State *J, const char *message, js_Object *prototype) +{ + js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype)); + js_pushstring(J, message); + js_setproperty(J, -2, "message"); + if (jsB_stacktrace(J, 0)) + js_setproperty(J, -2, "stackTrace"); +} + +#define DERROR(name, Name) \ + static void jsB_##Name(js_State *J) { \ + jsB_ErrorX(J, J->Name##_prototype); \ + } \ + void js_new##name(js_State *J, const char *s) { \ + js_newerrorx(J, s, J->Name##_prototype); \ + } \ + void js_##name(js_State *J, const char *fmt, ...) { \ + va_list ap; \ + char buf[256]; \ + va_start(ap, fmt); \ + vsnprintf(buf, sizeof buf, fmt, ap); \ + va_end(ap); \ + js_newerrorx(J, buf, J->Name##_prototype); \ + js_throw(J); \ + } + +DERROR(error, Error) +DERROR(evalerror, EvalError) +DERROR(rangeerror, RangeError) +DERROR(referenceerror, ReferenceError) +DERROR(syntaxerror, SyntaxError) +DERROR(typeerror, TypeError) +DERROR(urierror, URIError) + +#undef DERROR + +void jsB_initerror(js_State *J) +{ + js_pushobject(J, J->Error_prototype); + { + jsB_props(J, "name", "Error"); + jsB_props(J, "message", "an error has occurred"); + jsB_propf(J, "Error.prototype.toString", Ep_toString, 0); + } + js_newcconstructor(J, jsB_Error, jsB_Error, "Error", 1); + js_defglobal(J, "Error", JS_DONTENUM); + + #define IERROR(NAME) \ + js_pushobject(J, J->NAME##_prototype); \ + jsB_props(J, "name", Q(NAME)); \ + js_newcconstructor(J, jsB_##NAME, jsB_##NAME, Q(NAME), 1); \ + js_defglobal(J, Q(NAME), JS_DONTENUM); + + IERROR(EvalError); + IERROR(RangeError); + IERROR(ReferenceError); + IERROR(SyntaxError); + IERROR(TypeError); + IERROR(URIError); + + #undef IERROR +} diff --git a/programs/develop/kosjs/libmujs/jsfunction.c b/programs/develop/kosjs/libmujs/jsfunction.c new file mode 100755 index 0000000000..964dc118cb --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsfunction.c @@ -0,0 +1,229 @@ +#include "jsi.h" +#include "jsparse.h" +#include "jscompile.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +static void jsB_Function(js_State *J) +{ + int i, top = js_gettop(J); + js_Buffer *sb = NULL; + const char *body; + js_Ast *parse; + js_Function *fun; + + if (js_try(J)) { + js_free(J, sb); + jsP_freeparse(J); + js_throw(J); + } + + /* p1, p2, ..., pn */ + if (top > 2) { + for (i = 1; i < top - 1; ++i) { + if (i > 1) + js_putc(J, &sb, ','); + js_puts(J, &sb, js_tostring(J, i)); + } + js_putc(J, &sb, ')'); + js_putc(J, &sb, 0); + } + + /* body */ + body = js_isdefined(J, top - 1) ? js_tostring(J, top - 1) : ""; + + parse = jsP_parsefunction(J, "[string]", sb ? sb->s : NULL, body); + fun = jsC_compilefunction(J, parse); + + js_endtry(J); + js_free(J, sb); + jsP_freeparse(J); + + js_newfunction(J, fun, J->GE); +} + +static void jsB_Function_prototype(js_State *J) +{ + js_pushundefined(J); +} + +static void Fp_toString(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + js_Buffer *sb = NULL; + int i; + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT || self->type == JS_CEVAL) { + js_Function *F = self->u.f.function; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_puts(J, &sb, "function "); + js_puts(J, &sb, F->name); + js_putc(J, &sb, '('); + for (i = 0; i < F->numparams; ++i) { + if (i > 0) js_putc(J, &sb, ','); + js_puts(J, &sb, F->vartab[i]); + } + js_puts(J, &sb, ") { [byte code] }"); + js_putc(J, &sb, 0); + + js_pushstring(J, sb->s); + js_endtry(J); + js_free(J, sb); + } else if (self->type == JS_CCFUNCTION) { + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_puts(J, &sb, "function "); + js_puts(J, &sb, self->u.c.name); + js_puts(J, &sb, "() { [native code] }"); + js_putc(J, &sb, 0); + + js_pushstring(J, sb->s); + js_endtry(J); + js_free(J, sb); + } else { + js_pushliteral(J, "function () { }"); + } +} + +static void Fp_apply(js_State *J) +{ + int i, n; + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + js_copy(J, 0); + js_copy(J, 1); + + if (js_isnull(J, 2) || js_isundefined(J, 2)) { + n = 0; + } else { + n = js_getlength(J, 2); + for (i = 0; i < n; ++i) + js_getindex(J, 2, i); + } + + js_call(J, n); +} + +static void Fp_call(js_State *J) +{ + int i, top = js_gettop(J); + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + for (i = 0; i < top; ++i) + js_copy(J, i); + + js_call(J, top - 2); +} + +static void callbound(js_State *J) +{ + int top = js_gettop(J); + int i, fun, args, n; + + fun = js_gettop(J); + js_currentfunction(J); + js_getproperty(J, fun, "__TargetFunction__"); + js_getproperty(J, fun, "__BoundThis__"); + + args = js_gettop(J); + js_getproperty(J, fun, "__BoundArguments__"); + n = js_getlength(J, args); + for (i = 0; i < n; ++i) + js_getindex(J, args, i); + js_remove(J, args); + + for (i = 1; i < top; ++i) + js_copy(J, i); + + js_call(J, n + top - 1); +} + +static void constructbound(js_State *J) +{ + int top = js_gettop(J); + int i, fun, args, n; + + fun = js_gettop(J); + js_currentfunction(J); + js_getproperty(J, fun, "__TargetFunction__"); + + args = js_gettop(J); + js_getproperty(J, fun, "__BoundArguments__"); + n = js_getlength(J, args); + for (i = 0; i < n; ++i) + js_getindex(J, args, i); + js_remove(J, args); + + for (i = 1; i < top; ++i) + js_copy(J, i); + + js_construct(J, n + top - 1); +} + +static void Fp_bind(js_State *J) +{ + int i, top = js_gettop(J); + int n; + + if (!js_iscallable(J, 0)) + js_typeerror(J, "not a function"); + + n = js_getlength(J, 0); + if (n > top - 2) + n -= top - 2; + else + n = 0; + + /* Reuse target function's prototype for HasInstance check. */ + js_getproperty(J, 0, "prototype"); + js_newcconstructor(J, callbound, constructbound, "[bind]", n); + + /* target function */ + js_copy(J, 0); + js_defproperty(J, -2, "__TargetFunction__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + /* bound this */ + js_copy(J, 1); + js_defproperty(J, -2, "__BoundThis__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + + /* bound arguments */ + js_newarray(J); + for (i = 2; i < top; ++i) { + js_copy(J, i); + js_setindex(J, -2, i - 2); + } + js_defproperty(J, -2, "__BoundArguments__", JS_READONLY | JS_DONTENUM | JS_DONTCONF); +} + +void jsB_initfunction(js_State *J) +{ + J->Function_prototype->u.c.name = "Function.prototype"; + J->Function_prototype->u.c.function = jsB_Function_prototype; + J->Function_prototype->u.c.constructor = NULL; + J->Function_prototype->u.c.length = 0; + + js_pushobject(J, J->Function_prototype); + { + jsB_propf(J, "Function.prototype.toString", Fp_toString, 2); + jsB_propf(J, "Function.prototype.apply", Fp_apply, 2); + jsB_propf(J, "Function.prototype.call", Fp_call, 1); + jsB_propf(J, "Function.prototype.bind", Fp_bind, 1); + } + js_newcconstructor(J, jsB_Function, jsB_Function, "Function", 1); + js_defglobal(J, "Function", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsgc.c b/programs/develop/kosjs/libmujs/jsgc.c new file mode 100755 index 0000000000..62567ac162 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsgc.c @@ -0,0 +1,278 @@ +#include "jsi.h" +#include "jscompile.h" +#include "jsvalue.h" +#include "jsrun.h" + +#include "regexp.h" + +static void jsG_freeenvironment(js_State *J, js_Environment *env) +{ + js_free(J, env); +} + +static void jsG_freefunction(js_State *J, js_Function *fun) +{ + js_free(J, fun->funtab); + js_free(J, fun->numtab); + js_free(J, fun->strtab); + js_free(J, fun->vartab); + js_free(J, fun->code); + js_free(J, fun); +} + +static void jsG_freeproperty(js_State *J, js_Property *node) +{ + if (node->left->level) jsG_freeproperty(J, node->left); + if (node->right->level) jsG_freeproperty(J, node->right); + js_free(J, node); +} + +static void jsG_freeiterator(js_State *J, js_Iterator *node) +{ + while (node) { + js_Iterator *next = node->next; + js_free(J, node); + node = next; + } +} + +static void jsG_freeobject(js_State *J, js_Object *obj) +{ + if (obj->properties->level) + jsG_freeproperty(J, obj->properties); + if (obj->type == JS_CREGEXP) { + js_free(J, obj->u.r.source); + js_regfreex(J->alloc, J->actx, obj->u.r.prog); + } + if (obj->type == JS_CITERATOR) + jsG_freeiterator(J, obj->u.iter.head); + if (obj->type == JS_CUSERDATA && obj->u.user.finalize) + obj->u.user.finalize(J, obj->u.user.data); + js_free(J, obj); +} + +/* Mark and add object to scan queue */ +static void jsG_markobject(js_State *J, int mark, js_Object *obj) +{ + obj->gcmark = mark; + obj->gcroot = J->gcroot; + J->gcroot = obj; +} + +static void jsG_markfunction(js_State *J, int mark, js_Function *fun) +{ + int i; + fun->gcmark = mark; + for (i = 0; i < fun->funlen; ++i) + if (fun->funtab[i]->gcmark != mark) + jsG_markfunction(J, mark, fun->funtab[i]); +} + +static void jsG_markenvironment(js_State *J, int mark, js_Environment *env) +{ + do { + env->gcmark = mark; + if (env->variables->gcmark != mark) + jsG_markobject(J, mark, env->variables); + env = env->outer; + } while (env && env->gcmark != mark); +} + +static void jsG_markproperty(js_State *J, int mark, js_Property *node) +{ + if (node->left->level) jsG_markproperty(J, mark, node->left); + if (node->right->level) jsG_markproperty(J, mark, node->right); + + if (node->value.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark) + node->value.u.memstr->gcmark = mark; + if (node->value.type == JS_TOBJECT && node->value.u.object->gcmark != mark) + jsG_markobject(J, mark, node->value.u.object); + if (node->getter && node->getter->gcmark != mark) + jsG_markobject(J, mark, node->getter); + if (node->setter && node->setter->gcmark != mark) + jsG_markobject(J, mark, node->setter); +} + +/* Mark everything the object can reach. */ +static void jsG_scanobject(js_State *J, int mark, js_Object *obj) +{ + if (obj->properties->level) + jsG_markproperty(J, mark, obj->properties); + if (obj->prototype && obj->prototype->gcmark != mark) + jsG_markobject(J, mark, obj->prototype); + if (obj->type == JS_CITERATOR && obj->u.iter.target->gcmark != mark) { + jsG_markobject(J, mark, obj->u.iter.target); + } + if (obj->type == JS_CFUNCTION || obj->type == JS_CSCRIPT || obj->type == JS_CEVAL) { + if (obj->u.f.scope && obj->u.f.scope->gcmark != mark) + jsG_markenvironment(J, mark, obj->u.f.scope); + if (obj->u.f.function && obj->u.f.function->gcmark != mark) + jsG_markfunction(J, mark, obj->u.f.function); + } +} + +static void jsG_markstack(js_State *J, int mark) +{ + js_Value *v = J->stack; + int n = J->top; + while (n--) { + if (v->type == JS_TMEMSTR && v->u.memstr->gcmark != mark) + v->u.memstr->gcmark = mark; + if (v->type == JS_TOBJECT && v->u.object->gcmark != mark) + jsG_markobject(J, mark, v->u.object); + ++v; + } +} + +void js_gc(js_State *J, int report) +{ + js_Function *fun, *nextfun, **prevnextfun; + js_Object *obj, *nextobj, **prevnextobj; + js_String *str, *nextstr, **prevnextstr; + js_Environment *env, *nextenv, **prevnextenv; + unsigned int nenv = 0, nfun = 0, nobj = 0, nstr = 0, nprop = 0; + unsigned int genv = 0, gfun = 0, gobj = 0, gstr = 0, gprop = 0; + int mark; + int i; + + if (J->gcpause) { + if (report) + js_report(J, "garbage collector is paused"); + return; + } + + mark = J->gcmark = J->gcmark == 1 ? 2 : 1; + + /* Add initial roots. */ + + jsG_markobject(J, mark, J->Object_prototype); + jsG_markobject(J, mark, J->Array_prototype); + jsG_markobject(J, mark, J->Function_prototype); + jsG_markobject(J, mark, J->Boolean_prototype); + jsG_markobject(J, mark, J->Number_prototype); + jsG_markobject(J, mark, J->String_prototype); + jsG_markobject(J, mark, J->RegExp_prototype); + jsG_markobject(J, mark, J->Date_prototype); + + jsG_markobject(J, mark, J->Error_prototype); + jsG_markobject(J, mark, J->EvalError_prototype); + jsG_markobject(J, mark, J->RangeError_prototype); + jsG_markobject(J, mark, J->ReferenceError_prototype); + jsG_markobject(J, mark, J->SyntaxError_prototype); + jsG_markobject(J, mark, J->TypeError_prototype); + jsG_markobject(J, mark, J->URIError_prototype); + + jsG_markobject(J, mark, J->R); + jsG_markobject(J, mark, J->G); + + jsG_markstack(J, mark); + + jsG_markenvironment(J, mark, J->E); + jsG_markenvironment(J, mark, J->GE); + for (i = 0; i < J->envtop; ++i) + jsG_markenvironment(J, mark, J->envstack[i]); + + /* Scan objects until none remain. */ + + while ((obj = J->gcroot) != NULL) { + J->gcroot = obj->gcroot; + obj->gcroot = NULL; + jsG_scanobject(J, mark, obj); + } + + /* Free everything not marked. */ + + prevnextenv = &J->gcenv; + for (env = J->gcenv; env; env = nextenv) { + nextenv = env->gcnext; + if (env->gcmark != mark) { + *prevnextenv = nextenv; + jsG_freeenvironment(J, env); + ++genv; + } else { + prevnextenv = &env->gcnext; + } + ++nenv; + } + + prevnextfun = &J->gcfun; + for (fun = J->gcfun; fun; fun = nextfun) { + nextfun = fun->gcnext; + if (fun->gcmark != mark) { + *prevnextfun = nextfun; + jsG_freefunction(J, fun); + ++gfun; + } else { + prevnextfun = &fun->gcnext; + } + ++nfun; + } + + prevnextobj = &J->gcobj; + for (obj = J->gcobj; obj; obj = nextobj) { + nprop += obj->count; + nextobj = obj->gcnext; + if (obj->gcmark != mark) { + gprop += obj->count; + *prevnextobj = nextobj; + jsG_freeobject(J, obj); + ++gobj; + } else { + prevnextobj = &obj->gcnext; + } + ++nobj; + } + + prevnextstr = &J->gcstr; + for (str = J->gcstr; str; str = nextstr) { + nextstr = str->gcnext; + if (str->gcmark != mark) { + *prevnextstr = nextstr; + js_free(J, str); + ++gstr; + } else { + prevnextstr = &str->gcnext; + } + ++nstr; + } + + unsigned int ntot = nenv + nfun + nobj + nstr + nprop; + unsigned int gtot = genv + gfun + gobj + gstr + gprop; + unsigned int remaining = ntot - gtot; + + J->gccounter = remaining; + J->gcthresh = remaining * JS_GCFACTOR; + + if (report) { + char buf[256]; + snprintf(buf, sizeof buf, "garbage collected (%d%%): %d/%d envs, %d/%d funs, %d/%d objs, %d/%d props, %d/%d strs", + 100*gtot/ntot, genv, nenv, gfun, nfun, gobj, nobj, gprop, nprop, gstr, nstr); + js_report(J, buf); + } +} + +void js_freestate(js_State *J) +{ + js_Function *fun, *nextfun; + js_Object *obj, *nextobj; + js_Environment *env, *nextenv; + js_String *str, *nextstr; + + if (!J) + return; + + for (env = J->gcenv; env; env = nextenv) + nextenv = env->gcnext, jsG_freeenvironment(J, env); + for (fun = J->gcfun; fun; fun = nextfun) + nextfun = fun->gcnext, jsG_freefunction(J, fun); + for (obj = J->gcobj; obj; obj = nextobj) + nextobj = obj->gcnext, jsG_freeobject(J, obj); + for (str = J->gcstr; str; str = nextstr) + nextstr = str->gcnext, js_free(J, str); + + jsS_freestrings(J); + + js_free(J, J->lexbuf.text); + J->alloc(J->actx, J->stack, 0); + J->alloc(J->actx, J, 0); +} diff --git a/programs/develop/kosjs/libmujs/include/jsi.h b/programs/develop/kosjs/libmujs/jsi.h similarity index 90% rename from programs/develop/kosjs/libmujs/include/jsi.h rename to programs/develop/kosjs/libmujs/jsi.h index 5fb179a606..05479248fe 100755 --- a/programs/develop/kosjs/libmujs/include/jsi.h +++ b/programs/develop/kosjs/libmujs/jsi.h @@ -78,8 +78,16 @@ typedef struct js_StackTrace js_StackTrace; #ifndef JS_TRYLIMIT #define JS_TRYLIMIT 64 /* exception stack size */ #endif -#ifndef JS_GCLIMIT -#define JS_GCLIMIT 10000 /* run gc cycle every N allocations */ +#ifndef JS_GCFACTOR +/* + * GC will try to trigger when memory usage is this value times the minimum + * needed memory. E.g. if there are 100 remaining objects after GC and this + * value is 5.0, then the next GC will trigger when the overall number is 500. + * I.e. a value of 5.0 aims at 80% garbage, 20% remain-used on each GC. + * The bigger the value the less impact GC has on overall performance, but more + * memory is used and individual GC pauses are longer (but fewer). + */ +#define JS_GCFACTOR 5.0 /* memory overhead factor >= 1.0 */ #endif #ifndef JS_ASTLIMIT #define JS_ASTLIMIT 100 /* max nested expressions */ @@ -233,12 +241,14 @@ struct js_State /* garbage collector list */ int gcpause; int gcmark; - int gccounter; + unsigned int gccounter, gcthresh; js_Environment *gcenv; js_Function *gcfun; js_Object *gcobj; js_String *gcstr; + js_Object *gcroot; /* gc scan list */ + /* environments on the call stack but currently not in scope */ int envtop; js_Environment *envstack[JS_ENVLIMIT]; diff --git a/programs/develop/kosjs/libmujs/jsintern.c b/programs/develop/kosjs/libmujs/jsintern.c new file mode 100755 index 0000000000..097d905968 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsintern.c @@ -0,0 +1,135 @@ +#include "jsi.h" + +/* Dynamically grown string buffer */ + +void js_putc(js_State *J, js_Buffer **sbp, int c) +{ + js_Buffer *sb = *sbp; + if (!sb) { + sb = js_malloc(J, sizeof *sb); + sb->n = 0; + sb->m = sizeof sb->s; + *sbp = sb; + } else if (sb->n == sb->m) { + sb = js_realloc(J, sb, (sb->m *= 2) + soffsetof(js_Buffer, s)); + *sbp = sb; + } + sb->s[sb->n++] = c; +} + +void js_puts(js_State *J, js_Buffer **sb, const char *s) +{ + while (*s) + js_putc(J, sb, *s++); +} + +void js_putm(js_State *J, js_Buffer **sb, const char *s, const char *e) +{ + while (s < e) + js_putc(J, sb, *s++); +} + +/* Use an AA-tree to quickly look up interned strings. */ + +struct js_StringNode +{ + js_StringNode *left, *right; + int level; + char string[1]; +}; + +static js_StringNode jsS_sentinel = { &jsS_sentinel, &jsS_sentinel, 0, ""}; + +static js_StringNode *jsS_newstringnode(js_State *J, const char *string, const char **result) +{ + int n = strlen(string); + js_StringNode *node = js_malloc(J, soffsetof(js_StringNode, string) + n + 1); + node->left = node->right = &jsS_sentinel; + node->level = 1; + memcpy(node->string, string, n + 1); + return *result = node->string, node; +} + +static js_StringNode *jsS_skew(js_StringNode *node) +{ + if (node->left->level == node->level) { + js_StringNode *temp = node; + node = node->left; + temp->left = node->right; + node->right = temp; + } + return node; +} + +static js_StringNode *jsS_split(js_StringNode *node) +{ + if (node->right->right->level == node->level) { + js_StringNode *temp = node; + node = node->right; + temp->right = node->left; + node->left = temp; + ++node->level; + } + return node; +} + +static js_StringNode *jsS_insert(js_State *J, js_StringNode *node, const char *string, const char **result) +{ + if (node != &jsS_sentinel) { + int c = strcmp(string, node->string); + if (c < 0) + node->left = jsS_insert(J, node->left, string, result); + else if (c > 0) + node->right = jsS_insert(J, node->right, string, result); + else + return *result = node->string, node; + node = jsS_skew(node); + node = jsS_split(node); + return node; + } + return jsS_newstringnode(J, string, result); +} + +static void dumpstringnode(js_StringNode *node, int level) +{ + int i; + if (node->left != &jsS_sentinel) + dumpstringnode(node->left, level + 1); + printf("%d: ", node->level); + for (i = 0; i < level; ++i) + putchar('\t'); + printf("'%s'\n", node->string); + if (node->right != &jsS_sentinel) + dumpstringnode(node->right, level + 1); +} + +void jsS_dumpstrings(js_State *J) +{ + js_StringNode *root = J->strings; + printf("interned strings {\n"); + if (root && root != &jsS_sentinel) + dumpstringnode(root, 1); + printf("}\n"); +} + +static void jsS_freestringnode(js_State *J, js_StringNode *node) +{ + if (node->left != &jsS_sentinel) jsS_freestringnode(J, node->left); + if (node->right != &jsS_sentinel) jsS_freestringnode(J, node->right); + js_free(J, node); +} + +void jsS_freestrings(js_State *J) +{ + if (J->strings && J->strings != &jsS_sentinel) + jsS_freestringnode(J, J->strings); +} + +const char *js_intern(js_State *J, const char *s) +{ + const char *result; + if (!J->strings) + J->strings = &jsS_sentinel; + J->strings = jsS_insert(J, J->strings, s, &result); + return result; +} diff --git a/programs/develop/kosjs/libmujs/jslex.c b/programs/develop/kosjs/libmujs/jslex.c new file mode 100755 index 0000000000..3da6b550e5 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jslex.c @@ -0,0 +1,879 @@ +#include "jsi.h" +#include "jslex.h" +#include "utf.h" + +JS_NORETURN static void jsY_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); + +static void jsY_error(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); + strcat(buf, msgbuf); + + js_newsyntaxerror(J, buf); + js_throw(J); +} + +static const char *tokenstring[] = { + "(end-of-file)", + "'\\x01'", "'\\x02'", "'\\x03'", "'\\x04'", "'\\x05'", "'\\x06'", "'\\x07'", + "'\\x08'", "'\\x09'", "'\\x0A'", "'\\x0B'", "'\\x0C'", "'\\x0D'", "'\\x0E'", "'\\x0F'", + "'\\x10'", "'\\x11'", "'\\x12'", "'\\x13'", "'\\x14'", "'\\x15'", "'\\x16'", "'\\x17'", + "'\\x18'", "'\\x19'", "'\\x1A'", "'\\x1B'", "'\\x1C'", "'\\x1D'", "'\\x1E'", "'\\x1F'", + "' '", "'!'", "'\"'", "'#'", "'$'", "'%'", "'&'", "'\\''", + "'('", "')'", "'*'", "'+'", "','", "'-'", "'.'", "'/'", + "'0'", "'1'", "'2'", "'3'", "'4'", "'5'", "'6'", "'7'", + "'8'", "'9'", "':'", "';'", "'<'", "'='", "'>'", "'?'", + "'@'", "'A'", "'B'", "'C'", "'D'", "'E'", "'F'", "'G'", + "'H'", "'I'", "'J'", "'K'", "'L'", "'M'", "'N'", "'O'", + "'P'", "'Q'", "'R'", "'S'", "'T'", "'U'", "'V'", "'W'", + "'X'", "'Y'", "'Z'", "'['", "'\'", "']'", "'^'", "'_'", + "'`'", "'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'", + "'h'", "'i'", "'j'", "'k'", "'l'", "'m'", "'n'", "'o'", + "'p'", "'q'", "'r'", "'s'", "'t'", "'u'", "'v'", "'w'", + "'x'", "'y'", "'z'", "'{'", "'|'", "'}'", "'~'", "'\\x7F'", + + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + + "(identifier)", "(number)", "(string)", "(regexp)", + + "'<='", "'>='", "'=='", "'!='", "'==='", "'!=='", + "'<<'", "'>>'", "'>>>'", "'&&'", "'||'", + "'+='", "'-='", "'*='", "'/='", "'%='", + "'<<='", "'>>='", "'>>>='", "'&='", "'|='", "'^='", + "'++'", "'--'", + + "'break'", "'case'", "'catch'", "'continue'", "'debugger'", + "'default'", "'delete'", "'do'", "'else'", "'false'", "'finally'", "'for'", + "'function'", "'if'", "'in'", "'instanceof'", "'new'", "'null'", "'return'", + "'switch'", "'this'", "'throw'", "'true'", "'try'", "'typeof'", "'var'", + "'void'", "'while'", "'with'", +}; + +const char *jsY_tokenstring(int token) +{ + if (token >= 0 && token < (int)nelem(tokenstring)) + if (tokenstring[token]) + return tokenstring[token]; + return ""; +} + +static const char *keywords[] = { + "break", "case", "catch", "continue", "debugger", "default", "delete", + "do", "else", "false", "finally", "for", "function", "if", "in", + "instanceof", "new", "null", "return", "switch", "this", "throw", + "true", "try", "typeof", "var", "void", "while", "with", +}; + +int jsY_findword(const char *s, const char **list, int num) +{ + int l = 0; + int r = num - 1; + while (l <= r) { + int m = (l + r) >> 1; + int c = strcmp(s, list[m]); + if (c < 0) + r = m - 1; + else if (c > 0) + l = m + 1; + else + return m; + } + return -1; +} + +static int jsY_findkeyword(js_State *J, const char *s) +{ + int i = jsY_findword(s, keywords, nelem(keywords)); + if (i >= 0) { + J->text = keywords[i]; + return TK_BREAK + i; /* first keyword + i */ + } + J->text = js_intern(J, s); + return TK_IDENTIFIER; +} + +int jsY_iswhite(int c) +{ + return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF; +} + +int jsY_isnewline(int c) +{ + return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; +} + +#ifndef isalpha +#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) +#endif +#ifndef isdigit +#define isdigit(c) (c >= '0' && c <= '9') +#endif +#ifndef ishex +#define ishex(c) ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) +#endif + +static int jsY_isidentifierstart(int c) +{ + return isalpha(c) || c == '$' || c == '_' || isalpharune(c); +} + +static int jsY_isidentifierpart(int c) +{ + return isdigit(c) || isalpha(c) || c == '$' || c == '_' || isalpharune(c); +} + +static int jsY_isdec(int c) +{ + return isdigit(c); +} + +int jsY_ishex(int c) +{ + return isdigit(c) || ishex(c); +} + +int jsY_tohex(int c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; + if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; + return 0; +} + +static void jsY_next(js_State *J) +{ + Rune c; + if (*J->source == 0) { + J->lexchar = EOF; + return; + } + J->source += chartorune(&c, J->source); + /* consume CR LF as one unit */ + if (c == '\r' && *J->source == '\n') + ++J->source; + if (jsY_isnewline(c)) { + J->line++; + c = '\n'; + } + J->lexchar = c; +} + +#define jsY_accept(J, x) (J->lexchar == x ? (jsY_next(J), 1) : 0) + +#define jsY_expect(J, x) if (!jsY_accept(J, x)) jsY_error(J, "expected '%c'", x) + +static void jsY_unescape(js_State *J) +{ + if (jsY_accept(J, '\\')) { + if (jsY_accept(J, 'u')) { + int x = 0; + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); + if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar); + J->lexchar = x; + return; + } +error: + jsY_error(J, "unexpected escape sequence"); + } +} + +static void textinit(js_State *J) +{ + if (!J->lexbuf.text) { + J->lexbuf.cap = 4096; + J->lexbuf.text = js_malloc(J, J->lexbuf.cap); + } + J->lexbuf.len = 0; +} + +static void textpush(js_State *J, Rune c) +{ + int n; + if (c == EOF) + n = 1; + else + n = runelen(c); + if (J->lexbuf.len + n > J->lexbuf.cap) { + J->lexbuf.cap = J->lexbuf.cap * 2; + J->lexbuf.text = js_realloc(J, J->lexbuf.text, J->lexbuf.cap); + } + if (c == EOF) + J->lexbuf.text[J->lexbuf.len++] = 0; + else + J->lexbuf.len += runetochar(J->lexbuf.text + J->lexbuf.len, &c); +} + +static char *textend(js_State *J) +{ + textpush(J, EOF); + return J->lexbuf.text; +} + +static void lexlinecomment(js_State *J) +{ + while (J->lexchar != EOF && J->lexchar != '\n') + jsY_next(J); +} + +static int lexcomment(js_State *J) +{ + /* already consumed initial '/' '*' sequence */ + while (J->lexchar != EOF) { + if (jsY_accept(J, '*')) { + while (J->lexchar == '*') + jsY_next(J); + if (jsY_accept(J, '/')) + return 0; + } + else + jsY_next(J); + } + return -1; +} + +static double lexhex(js_State *J) +{ + double n = 0; + if (!jsY_ishex(J->lexchar)) + jsY_error(J, "malformed hexadecimal number"); + while (jsY_ishex(J->lexchar)) { + n = n * 16 + jsY_tohex(J->lexchar); + jsY_next(J); + } + return n; +} + +#if 0 + +static double lexinteger(js_State *J) +{ + double n = 0; + if (!jsY_isdec(J->lexchar)) + jsY_error(J, "malformed number"); + while (jsY_isdec(J->lexchar)) { + n = n * 10 + (J->lexchar - '0'); + jsY_next(J); + } + return n; +} + +static double lexfraction(js_State *J) +{ + double n = 0; + double d = 1; + while (jsY_isdec(J->lexchar)) { + n = n * 10 + (J->lexchar - '0'); + d = d * 10; + jsY_next(J); + } + return n / d; +} + +static double lexexponent(js_State *J) +{ + double sign; + if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) { + if (jsY_accept(J, '-')) sign = -1; + else if (jsY_accept(J, '+')) sign = 1; + else sign = 1; + return sign * lexinteger(J); + } + return 0; +} + +static int lexnumber(js_State *J) +{ + double n; + double e; + + if (jsY_accept(J, '0')) { + if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) { + J->number = lexhex(J); + return TK_NUMBER; + } + if (jsY_isdec(J->lexchar)) + jsY_error(J, "number with leading zero"); + n = 0; + if (jsY_accept(J, '.')) + n += lexfraction(J); + } else if (jsY_accept(J, '.')) { + if (!jsY_isdec(J->lexchar)) + return '.'; + n = lexfraction(J); + } else { + n = lexinteger(J); + if (jsY_accept(J, '.')) + n += lexfraction(J); + } + + e = lexexponent(J); + if (e < 0) + n /= pow(10, -e); + else if (e > 0) + n *= pow(10, e); + + if (jsY_isidentifierstart(J->lexchar)) + jsY_error(J, "number with letter suffix"); + + J->number = n; + return TK_NUMBER; +} + +#else + +static int lexnumber(js_State *J) +{ + const char *s = J->source - 1; + + if (jsY_accept(J, '0')) { + if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) { + J->number = lexhex(J); + return TK_NUMBER; + } + if (jsY_isdec(J->lexchar)) + jsY_error(J, "number with leading zero"); + if (jsY_accept(J, '.')) { + while (jsY_isdec(J->lexchar)) + jsY_next(J); + } + } else if (jsY_accept(J, '.')) { + if (!jsY_isdec(J->lexchar)) + return '.'; + while (jsY_isdec(J->lexchar)) + jsY_next(J); + } else { + while (jsY_isdec(J->lexchar)) + jsY_next(J); + if (jsY_accept(J, '.')) { + while (jsY_isdec(J->lexchar)) + jsY_next(J); + } + } + + if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) { + if (J->lexchar == '-' || J->lexchar == '+') + jsY_next(J); + if (jsY_isdec(J->lexchar)) + while (jsY_isdec(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "missing exponent"); + } + + if (jsY_isidentifierstart(J->lexchar)) + jsY_error(J, "number with letter suffix"); + + J->number = js_strtod(s, NULL); + return TK_NUMBER; +} + +#endif + +static int lexescape(js_State *J) +{ + int x = 0; + + /* already consumed '\' */ + + if (jsY_accept(J, '\n')) + return 0; + + switch (J->lexchar) { + case EOF: jsY_error(J, "unterminated escape sequence"); + case 'u': + jsY_next(J); + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); } + textpush(J, x); + break; + case 'x': + jsY_next(J); + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); } + textpush(J, x); + break; + case '0': textpush(J, 0); jsY_next(J); break; + case '\\': textpush(J, '\\'); jsY_next(J); break; + case '\'': textpush(J, '\''); jsY_next(J); break; + case '"': textpush(J, '"'); jsY_next(J); break; + case 'b': textpush(J, '\b'); jsY_next(J); break; + case 'f': textpush(J, '\f'); jsY_next(J); break; + case 'n': textpush(J, '\n'); jsY_next(J); break; + case 'r': textpush(J, '\r'); jsY_next(J); break; + case 't': textpush(J, '\t'); jsY_next(J); break; + case 'v': textpush(J, '\v'); jsY_next(J); break; + default: textpush(J, J->lexchar); jsY_next(J); break; + } + return 0; +} + +static int lexstring(js_State *J) +{ + const char *s; + + int q = J->lexchar; + jsY_next(J); + + textinit(J); + + while (J->lexchar != q) { + if (J->lexchar == EOF || J->lexchar == '\n') + jsY_error(J, "string not terminated"); + if (jsY_accept(J, '\\')) { + if (lexescape(J)) + jsY_error(J, "malformed escape sequence"); + } else { + textpush(J, J->lexchar); + jsY_next(J); + } + } + jsY_expect(J, q); + + s = textend(J); + + J->text = js_intern(J, s); + return TK_STRING; +} + +/* the ugliest language wart ever... */ +static int isregexpcontext(int last) +{ + switch (last) { + case ']': + case ')': + case '}': + case TK_IDENTIFIER: + case TK_NUMBER: + case TK_STRING: + case TK_FALSE: + case TK_NULL: + case TK_THIS: + case TK_TRUE: + return 0; + default: + return 1; + } +} + +static int lexregexp(js_State *J) +{ + const char *s; + int g, m, i; + int inclass = 0; + + /* already consumed initial '/' */ + + textinit(J); + + /* regexp body */ + while (J->lexchar != '/' || inclass) { + if (J->lexchar == EOF || J->lexchar == '\n') { + jsY_error(J, "regular expression not terminated"); + } else if (jsY_accept(J, '\\')) { + if (jsY_accept(J, '/')) { + textpush(J, '/'); + } else { + textpush(J, '\\'); + if (J->lexchar == EOF || J->lexchar == '\n') + jsY_error(J, "regular expression not terminated"); + textpush(J, J->lexchar); + jsY_next(J); + } + } else { + if (J->lexchar == '[' && !inclass) + inclass = 1; + if (J->lexchar == ']' && inclass) + inclass = 0; + textpush(J, J->lexchar); + jsY_next(J); + } + } + jsY_expect(J, '/'); + + s = textend(J); + + /* regexp flags */ + g = i = m = 0; + + while (jsY_isidentifierpart(J->lexchar)) { + if (jsY_accept(J, 'g')) ++g; + else if (jsY_accept(J, 'i')) ++i; + else if (jsY_accept(J, 'm')) ++m; + else jsY_error(J, "illegal flag in regular expression: %c", J->lexchar); + } + + if (g > 1 || i > 1 || m > 1) + jsY_error(J, "duplicated flag in regular expression"); + + J->text = js_intern(J, s); + J->number = 0; + if (g) J->number += JS_REGEXP_G; + if (i) J->number += JS_REGEXP_I; + if (m) J->number += JS_REGEXP_M; + return TK_REGEXP; +} + +/* simple "return [no Line Terminator here] ..." contexts */ +static int isnlthcontext(int last) +{ + switch (last) { + case TK_BREAK: + case TK_CONTINUE: + case TK_RETURN: + case TK_THROW: + return 1; + default: + return 0; + } +} + +static int jsY_lexx(js_State *J) +{ + J->newline = 0; + + while (1) { + J->lexline = J->line; /* save location of beginning of token */ + + while (jsY_iswhite(J->lexchar)) + jsY_next(J); + + if (jsY_accept(J, '\n')) { + J->newline = 1; + if (isnlthcontext(J->lasttoken)) + return ';'; + continue; + } + + if (jsY_accept(J, '/')) { + if (jsY_accept(J, '/')) { + lexlinecomment(J); + continue; + } else if (jsY_accept(J, '*')) { + if (lexcomment(J)) + jsY_error(J, "multi-line comment not terminated"); + continue; + } else if (isregexpcontext(J->lasttoken)) { + return lexregexp(J); + } else if (jsY_accept(J, '=')) { + return TK_DIV_ASS; + } else { + return '/'; + } + } + + if (J->lexchar >= '0' && J->lexchar <= '9') { + return lexnumber(J); + } + + switch (J->lexchar) { + case '(': jsY_next(J); return '('; + case ')': jsY_next(J); return ')'; + case ',': jsY_next(J); return ','; + case ':': jsY_next(J); return ':'; + case ';': jsY_next(J); return ';'; + case '?': jsY_next(J); return '?'; + case '[': jsY_next(J); return '['; + case ']': jsY_next(J); return ']'; + case '{': jsY_next(J); return '{'; + case '}': jsY_next(J); return '}'; + case '~': jsY_next(J); return '~'; + + case '\'': + case '"': + return lexstring(J); + + case '.': + return lexnumber(J); + + case '<': + jsY_next(J); + if (jsY_accept(J, '<')) { + if (jsY_accept(J, '=')) + return TK_SHL_ASS; + return TK_SHL; + } + if (jsY_accept(J, '=')) + return TK_LE; + return '<'; + + case '>': + jsY_next(J); + if (jsY_accept(J, '>')) { + if (jsY_accept(J, '>')) { + if (jsY_accept(J, '=')) + return TK_USHR_ASS; + return TK_USHR; + } + if (jsY_accept(J, '=')) + return TK_SHR_ASS; + return TK_SHR; + } + if (jsY_accept(J, '=')) + return TK_GE; + return '>'; + + case '=': + jsY_next(J); + if (jsY_accept(J, '=')) { + if (jsY_accept(J, '=')) + return TK_STRICTEQ; + return TK_EQ; + } + return '='; + + case '!': + jsY_next(J); + if (jsY_accept(J, '=')) { + if (jsY_accept(J, '=')) + return TK_STRICTNE; + return TK_NE; + } + return '!'; + + case '+': + jsY_next(J); + if (jsY_accept(J, '+')) + return TK_INC; + if (jsY_accept(J, '=')) + return TK_ADD_ASS; + return '+'; + + case '-': + jsY_next(J); + if (jsY_accept(J, '-')) + return TK_DEC; + if (jsY_accept(J, '=')) + return TK_SUB_ASS; + return '-'; + + case '*': + jsY_next(J); + if (jsY_accept(J, '=')) + return TK_MUL_ASS; + return '*'; + + case '%': + jsY_next(J); + if (jsY_accept(J, '=')) + return TK_MOD_ASS; + return '%'; + + case '&': + jsY_next(J); + if (jsY_accept(J, '&')) + return TK_AND; + if (jsY_accept(J, '=')) + return TK_AND_ASS; + return '&'; + + case '|': + jsY_next(J); + if (jsY_accept(J, '|')) + return TK_OR; + if (jsY_accept(J, '=')) + return TK_OR_ASS; + return '|'; + + case '^': + jsY_next(J); + if (jsY_accept(J, '=')) + return TK_XOR_ASS; + return '^'; + + case EOF: + return 0; /* EOF */ + } + + /* Handle \uXXXX escapes in identifiers */ + jsY_unescape(J); + if (jsY_isidentifierstart(J->lexchar)) { + textinit(J); + textpush(J, J->lexchar); + + jsY_next(J); + jsY_unescape(J); + while (jsY_isidentifierpart(J->lexchar)) { + textpush(J, J->lexchar); + jsY_next(J); + jsY_unescape(J); + } + + textend(J); + + return jsY_findkeyword(J, J->lexbuf.text); + } + + if (J->lexchar >= 0x20 && J->lexchar <= 0x7E) + jsY_error(J, "unexpected character: '%c'", J->lexchar); + jsY_error(J, "unexpected character: \\u%04X", J->lexchar); + } +} + +void jsY_initlex(js_State *J, const char *filename, const char *source) +{ + J->filename = filename; + J->source = source; + J->line = 1; + J->lasttoken = 0; + jsY_next(J); /* load first lookahead character */ +} + +int jsY_lex(js_State *J) +{ + return J->lasttoken = jsY_lexx(J); +} + +static int lexjsonnumber(js_State *J) +{ + const char *s = J->source - 1; + + if (J->lexchar == '-') + jsY_next(J); + + if (J->lexchar == '0') + jsY_next(J); + else if (J->lexchar >= '1' && J->lexchar <= '9') + while (isdigit(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "unexpected non-digit"); + + if (jsY_accept(J, '.')) { + if (isdigit(J->lexchar)) + while (isdigit(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "missing digits after decimal point"); + } + + if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) { + if (J->lexchar == '-' || J->lexchar == '+') + jsY_next(J); + if (isdigit(J->lexchar)) + while (isdigit(J->lexchar)) + jsY_next(J); + else + jsY_error(J, "missing digits after exponent indicator"); + } + + J->number = js_strtod(s, NULL); + return TK_NUMBER; +} + +static int lexjsonescape(js_State *J) +{ + int x = 0; + + /* already consumed '\' */ + + switch (J->lexchar) { + default: jsY_error(J, "invalid escape sequence"); + case 'u': + jsY_next(J); + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); } + if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); } + textpush(J, x); + break; + case '"': textpush(J, '"'); jsY_next(J); break; + case '\\': textpush(J, '\\'); jsY_next(J); break; + case '/': textpush(J, '/'); jsY_next(J); break; + case 'b': textpush(J, '\b'); jsY_next(J); break; + case 'f': textpush(J, '\f'); jsY_next(J); break; + case 'n': textpush(J, '\n'); jsY_next(J); break; + case 'r': textpush(J, '\r'); jsY_next(J); break; + case 't': textpush(J, '\t'); jsY_next(J); break; + } + return 0; +} + +static int lexjsonstring(js_State *J) +{ + const char *s; + + textinit(J); + + while (J->lexchar != '"') { + if (J->lexchar == EOF) + jsY_error(J, "unterminated string"); + else if (J->lexchar < 32) + jsY_error(J, "invalid control character in string"); + else if (jsY_accept(J, '\\')) + lexjsonescape(J); + else { + textpush(J, J->lexchar); + jsY_next(J); + } + } + jsY_expect(J, '"'); + + s = textend(J); + + J->text = js_intern(J, s); + return TK_STRING; +} + +int jsY_lexjson(js_State *J) +{ + while (1) { + J->lexline = J->line; /* save location of beginning of token */ + + while (jsY_iswhite(J->lexchar) || J->lexchar == '\n') + jsY_next(J); + + if ((J->lexchar >= '0' && J->lexchar <= '9') || J->lexchar == '-') + return lexjsonnumber(J); + + switch (J->lexchar) { + case ',': jsY_next(J); return ','; + case ':': jsY_next(J); return ':'; + case '[': jsY_next(J); return '['; + case ']': jsY_next(J); return ']'; + case '{': jsY_next(J); return '{'; + case '}': jsY_next(J); return '}'; + + case '"': + jsY_next(J); + return lexjsonstring(J); + + case 'f': + jsY_next(J); jsY_expect(J, 'a'); jsY_expect(J, 'l'); jsY_expect(J, 's'); jsY_expect(J, 'e'); + return TK_FALSE; + + case 'n': + jsY_next(J); jsY_expect(J, 'u'); jsY_expect(J, 'l'); jsY_expect(J, 'l'); + return TK_NULL; + + case 't': + jsY_next(J); jsY_expect(J, 'r'); jsY_expect(J, 'u'); jsY_expect(J, 'e'); + return TK_TRUE; + + case EOF: + return 0; /* EOF */ + } + + if (J->lexchar >= 0x20 && J->lexchar <= 0x7E) + jsY_error(J, "unexpected character: '%c'", J->lexchar); + jsY_error(J, "unexpected character: \\u%04X", J->lexchar); + } +} diff --git a/programs/develop/kosjs/libmujs/include/jslex.h b/programs/develop/kosjs/libmujs/jslex.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/jslex.h rename to programs/develop/kosjs/libmujs/jslex.h diff --git a/programs/develop/kosjs/libmujs/jsmath.c b/programs/develop/kosjs/libmujs/jsmath.c new file mode 100755 index 0000000000..cbc66121dd --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsmath.c @@ -0,0 +1,192 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +#include + +#define JS_RAND_MAX (0x7fffffff) + +static unsigned int jsM_rand_temper(unsigned int x) +{ + x ^= x>>11; + x ^= x<<7 & 0x9D2C5680; + x ^= x<<15 & 0xEFC60000; + x ^= x>>18; + return x; +} + +static int jsM_rand_r(unsigned int *seed) +{ + return jsM_rand_temper(*seed = *seed * 1103515245 + 12345)/2; +} + +static double jsM_round(double x) +{ + if (isnan(x)) return x; + if (isinf(x)) return x; + if (x == 0) return x; + if (x > 0 && x < 0.5) return 0; + if (x < 0 && x >= -0.5) return -0; + return floor(x + 0.5); +} + +static void Math_abs(js_State *J) +{ + js_pushnumber(J, fabs(js_tonumber(J, 1))); +} + +static void Math_acos(js_State *J) +{ + js_pushnumber(J, acos(js_tonumber(J, 1))); +} + +static void Math_asin(js_State *J) +{ + js_pushnumber(J, asin(js_tonumber(J, 1))); +} + +static void Math_atan(js_State *J) +{ + js_pushnumber(J, atan(js_tonumber(J, 1))); +} + +static void Math_atan2(js_State *J) +{ + double y = js_tonumber(J, 1); + double x = js_tonumber(J, 2); + js_pushnumber(J, atan2(y, x)); +} + +static void Math_ceil(js_State *J) +{ + js_pushnumber(J, ceil(js_tonumber(J, 1))); +} + +static void Math_cos(js_State *J) +{ + js_pushnumber(J, cos(js_tonumber(J, 1))); +} + +static void Math_exp(js_State *J) +{ + js_pushnumber(J, exp(js_tonumber(J, 1))); +} + +static void Math_floor(js_State *J) +{ + js_pushnumber(J, floor(js_tonumber(J, 1))); +} + +static void Math_log(js_State *J) +{ + js_pushnumber(J, log(js_tonumber(J, 1))); +} + +static void Math_pow(js_State *J) +{ + double x = js_tonumber(J, 1); + double y = js_tonumber(J, 2); + if (!isfinite(y) && fabs(x) == 1) + js_pushnumber(J, NAN); + else + js_pushnumber(J, pow(x,y)); +} + +static void Math_random(js_State *J) +{ + js_pushnumber(J, jsM_rand_r(&J->seed) / (JS_RAND_MAX + 1.0)); +} + +static void Math_round(js_State *J) +{ + double x = js_tonumber(J, 1); + js_pushnumber(J, jsM_round(x)); +} + +static void Math_sin(js_State *J) +{ + js_pushnumber(J, sin(js_tonumber(J, 1))); +} + +static void Math_sqrt(js_State *J) +{ + js_pushnumber(J, sqrt(js_tonumber(J, 1))); +} + +static void Math_tan(js_State *J) +{ + js_pushnumber(J, tan(js_tonumber(J, 1))); +} + +static void Math_max(js_State *J) +{ + int i, n = js_gettop(J); + double x = -INFINITY; + for (i = 1; i < n; ++i) { + double y = js_tonumber(J, i); + if (isnan(y)) { + x = y; + break; + } + if (signbit(x) == signbit(y)) + x = x > y ? x : y; + else if (signbit(x)) + x = y; + } + js_pushnumber(J, x); +} + +static void Math_min(js_State *J) +{ + int i, n = js_gettop(J); + double x = INFINITY; + for (i = 1; i < n; ++i) { + double y = js_tonumber(J, i); + if (isnan(y)) { + x = y; + break; + } + if (signbit(x) == signbit(y)) + x = x < y ? x : y; + else if (signbit(y)) + x = y; + } + js_pushnumber(J, x); +} + +void jsB_initmath(js_State *J) +{ + J->seed = time(NULL); + + js_pushobject(J, jsV_newobject(J, JS_CMATH, J->Object_prototype)); + { + jsB_propn(J, "E", 2.7182818284590452354); + jsB_propn(J, "LN10", 2.302585092994046); + jsB_propn(J, "LN2", 0.6931471805599453); + jsB_propn(J, "LOG2E", 1.4426950408889634); + jsB_propn(J, "LOG10E", 0.4342944819032518); + jsB_propn(J, "PI", 3.1415926535897932); + jsB_propn(J, "SQRT1_2", 0.7071067811865476); + jsB_propn(J, "SQRT2", 1.4142135623730951); + + jsB_propf(J, "Math.abs", Math_abs, 1); + jsB_propf(J, "Math.acos", Math_acos, 1); + jsB_propf(J, "Math.asin", Math_asin, 1); + jsB_propf(J, "Math.atan", Math_atan, 1); + jsB_propf(J, "Math.atan2", Math_atan2, 2); + jsB_propf(J, "Math.ceil", Math_ceil, 1); + jsB_propf(J, "Math.cos", Math_cos, 1); + jsB_propf(J, "Math.exp", Math_exp, 1); + jsB_propf(J, "Math.floor", Math_floor, 1); + jsB_propf(J, "Math.log", Math_log, 1); + jsB_propf(J, "Math.max", Math_max, 0); /* 2 */ + jsB_propf(J, "Math.min", Math_min, 0); /* 2 */ + jsB_propf(J, "Math.pow", Math_pow, 2); + jsB_propf(J, "Math.random", Math_random, 0); + jsB_propf(J, "Math.round", Math_round, 1); + jsB_propf(J, "Math.sin", Math_sin, 1); + jsB_propf(J, "Math.sqrt", Math_sqrt, 1); + jsB_propf(J, "Math.tan", Math_tan, 1); + } + js_defglobal(J, "Math", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsnumber.c b/programs/develop/kosjs/libmujs/jsnumber.c new file mode 100755 index 0000000000..7050ff3908 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsnumber.c @@ -0,0 +1,198 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +#if defined(_MSC_VER) && (_MSC_VER < 1700) /* VS2012 has stdint.h */ +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +static void jsB_new_Number(js_State *J) +{ + js_newnumber(J, js_gettop(J) > 1 ? js_tonumber(J, 1) : 0); +} + +static void jsB_Number(js_State *J) +{ + js_pushnumber(J, js_gettop(J) > 1 ? js_tonumber(J, 1) : 0); +} + +static void Np_valueOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + js_pushnumber(J, self->u.number); +} + +static void Np_toString(js_State *J) +{ + char buf[100]; + js_Object *self = js_toobject(J, 0); + int radix = js_isundefined(J, 1) ? 10 : js_tointeger(J, 1); + if (self->type != JS_CNUMBER) + js_typeerror(J, "not a number"); + if (radix == 10) { + js_pushstring(J, jsV_numbertostring(J, buf, self->u.number)); + return; + } + if (radix < 2 || radix > 36) + js_rangeerror(J, "invalid radix"); + + /* lame number to string conversion for any radix from 2 to 36 */ + { + static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + double number = self->u.number; + int sign = self->u.number < 0; + js_Buffer *sb = NULL; + uint64_t u, limit = ((uint64_t)1<<52); + + int ndigits, exp, point; + + if (number == 0) { js_pushstring(J, "0"); return; } + if (isnan(number)) { js_pushstring(J, "NaN"); return; } + if (isinf(number)) { js_pushstring(J, sign ? "-Infinity" : "Infinity"); return; } + + if (sign) + number = -number; + + /* fit as many digits as we want in an int */ + exp = 0; + while (number * pow(radix, exp) > limit) + --exp; + while (number * pow(radix, exp+1) < limit) + ++exp; + u = number * pow(radix, exp) + 0.5; + + /* trim trailing zeros */ + while (u > 0 && (u % radix) == 0) { + u /= radix; + --exp; + } + + /* serialize digits */ + ndigits = 0; + while (u > 0) { + buf[ndigits++] = digits[u % radix]; + u /= radix; + } + point = ndigits - exp; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + if (sign) + js_putc(J, &sb, '-'); + + if (point <= 0) { + js_putc(J, &sb, '0'); + js_putc(J, &sb, '.'); + while (point++ < 0) + js_putc(J, &sb, '0'); + while (ndigits-- > 0) + js_putc(J, &sb, buf[ndigits]); + } else { + while (ndigits-- > 0) { + js_putc(J, &sb, buf[ndigits]); + if (--point == 0 && ndigits > 0) + js_putc(J, &sb, '.'); + } + while (point-- > 0) + js_putc(J, &sb, '0'); + } + + js_putc(J, &sb, 0); + js_pushstring(J, sb->s); + + js_endtry(J); + js_free(J, sb); + } +} + +/* Customized ToString() on a number */ +static void numtostr(js_State *J, const char *fmt, int w, double n) +{ + /* buf needs to fit printf("%.20f", 1e20) */ + char buf[50], *e; + sprintf(buf, fmt, w, n); + e = strchr(buf, 'e'); + if (e) { + int exp = atoi(e+1); + sprintf(e, "e%+d", exp); + } + js_pushstring(J, buf); +} + +static void Np_toFixed(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + int width = js_tointeger(J, 1); + char buf[32]; + double x; + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + if (width < 0) js_rangeerror(J, "precision %d out of range", width); + if (width > 20) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x) || x <= -1e21 || x >= 1e21) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*f", width, x); +} + +static void Np_toExponential(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + int width = js_tointeger(J, 1); + char buf[32]; + double x; + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + if (width < 0) js_rangeerror(J, "precision %d out of range", width); + if (width > 20) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x)) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*e", width, self->u.number); +} + +static void Np_toPrecision(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + int width = js_tointeger(J, 1); + char buf[32]; + double x; + if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); + if (width < 1) js_rangeerror(J, "precision %d out of range", width); + if (width > 21) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x)) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*g", width, self->u.number); +} + +void jsB_initnumber(js_State *J) +{ + J->Number_prototype->u.number = 0; + + js_pushobject(J, J->Number_prototype); + { + jsB_propf(J, "Number.prototype.valueOf", Np_valueOf, 0); + jsB_propf(J, "Number.prototype.toString", Np_toString, 1); + jsB_propf(J, "Number.prototype.toLocaleString", Np_toString, 0); + jsB_propf(J, "Number.prototype.toFixed", Np_toFixed, 1); + jsB_propf(J, "Number.prototype.toExponential", Np_toExponential, 1); + jsB_propf(J, "Number.prototype.toPrecision", Np_toPrecision, 1); + } + js_newcconstructor(J, jsB_Number, jsB_new_Number, "Number", 0); /* 1 */ + { + jsB_propn(J, "MAX_VALUE", 1.7976931348623157e+308); + jsB_propn(J, "MIN_VALUE", 5e-324); + jsB_propn(J, "NaN", NAN); + jsB_propn(J, "NEGATIVE_INFINITY", -INFINITY); + jsB_propn(J, "POSITIVE_INFINITY", INFINITY); + } + js_defglobal(J, "Number", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsobject.c b/programs/develop/kosjs/libmujs/jsobject.c new file mode 100755 index 0000000000..1d807b2cb7 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsobject.c @@ -0,0 +1,521 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +static void jsB_new_Object(js_State *J) +{ + if (js_isundefined(J, 1) || js_isnull(J, 1)) + js_newobject(J); + else + js_pushobject(J, js_toobject(J, 1)); +} + +static void jsB_Object(js_State *J) +{ + if (js_isundefined(J, 1) || js_isnull(J, 1)) + js_newobject(J); + else + js_pushobject(J, js_toobject(J, 1)); +} + +static void Op_toString(js_State *J) +{ + if (js_isundefined(J, 0)) + js_pushliteral(J, "[object Undefined]"); + else if (js_isnull(J, 0)) + js_pushliteral(J, "[object Null]"); + else { + js_Object *self = js_toobject(J, 0); + switch (self->type) { + case JS_COBJECT: js_pushliteral(J, "[object Object]"); break; + case JS_CARRAY: js_pushliteral(J, "[object Array]"); break; + case JS_CFUNCTION: js_pushliteral(J, "[object Function]"); break; + case JS_CSCRIPT: js_pushliteral(J, "[object Function]"); break; + case JS_CEVAL: js_pushliteral(J, "[object Function]"); break; + case JS_CCFUNCTION: js_pushliteral(J, "[object Function]"); break; + case JS_CERROR: js_pushliteral(J, "[object Error]"); break; + case JS_CBOOLEAN: js_pushliteral(J, "[object Boolean]"); break; + case JS_CNUMBER: js_pushliteral(J, "[object Number]"); break; + case JS_CSTRING: js_pushliteral(J, "[object String]"); break; + case JS_CREGEXP: js_pushliteral(J, "[object RegExp]"); break; + case JS_CDATE: js_pushliteral(J, "[object Date]"); break; + case JS_CMATH: js_pushliteral(J, "[object Math]"); break; + case JS_CJSON: js_pushliteral(J, "[object JSON]"); break; + case JS_CARGUMENTS: js_pushliteral(J, "[object Arguments]"); break; + case JS_CITERATOR: js_pushliteral(J, "[object Iterator]"); break; + case JS_CUSERDATA: + js_pushliteral(J, "[object "); + js_pushliteral(J, self->u.user.tag); + js_concat(J); + js_pushliteral(J, "]"); + js_concat(J); + break; + } + } +} + +static void Op_valueOf(js_State *J) +{ + js_copy(J, 0); +} + +static void Op_hasOwnProperty(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + const char *name = js_tostring(J, 1); + js_Property *ref = jsV_getownproperty(J, self, name); + js_pushboolean(J, ref != NULL); +} + +static void Op_isPrototypeOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (js_isobject(J, 1)) { + js_Object *V = js_toobject(J, 1); + do { + V = V->prototype; + if (V == self) { + js_pushboolean(J, 1); + return; + } + } while (V); + } + js_pushboolean(J, 0); +} + +static void Op_propertyIsEnumerable(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + const char *name = js_tostring(J, 1); + js_Property *ref = jsV_getownproperty(J, self, name); + js_pushboolean(J, ref && !(ref->atts & JS_DONTENUM)); +} + +static void O_getPrototypeOf(js_State *J) +{ + js_Object *obj; + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + if (obj->prototype) + js_pushobject(J, obj->prototype); + else + js_pushnull(J); +} + +static void O_getOwnPropertyDescriptor(js_State *J) +{ + js_Object *obj; + js_Property *ref; + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + ref = jsV_getproperty(J, obj, js_tostring(J, 2)); + if (!ref) + js_pushundefined(J); + else { + js_newobject(J); + if (!ref->getter && !ref->setter) { + js_pushvalue(J, ref->value); + js_setproperty(J, -2, "value"); + js_pushboolean(J, !(ref->atts & JS_READONLY)); + js_setproperty(J, -2, "writable"); + } else { + if (ref->getter) + js_pushobject(J, ref->getter); + else + js_pushundefined(J); + js_setproperty(J, -2, "get"); + if (ref->setter) + js_pushobject(J, ref->setter); + else + js_pushundefined(J); + js_setproperty(J, -2, "set"); + } + js_pushboolean(J, !(ref->atts & JS_DONTENUM)); + js_setproperty(J, -2, "enumerable"); + js_pushboolean(J, !(ref->atts & JS_DONTCONF)); + js_setproperty(J, -2, "configurable"); + } +} + +static int O_getOwnPropertyNames_walk(js_State *J, js_Property *ref, int i) +{ + if (ref->left->level) + i = O_getOwnPropertyNames_walk(J, ref->left, i); + js_pushliteral(J, ref->name); + js_setindex(J, -2, i++); + if (ref->right->level) + i = O_getOwnPropertyNames_walk(J, ref->right, i); + return i; +} + +static void O_getOwnPropertyNames(js_State *J) +{ + js_Object *obj; + int k; + int i; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + + js_newarray(J); + + if (obj->properties->level) + i = O_getOwnPropertyNames_walk(J, obj->properties, 0); + else + i = 0; + + if (obj->type == JS_CARRAY) { + js_pushliteral(J, "length"); + js_setindex(J, -2, i++); + } + + if (obj->type == JS_CSTRING) { + js_pushliteral(J, "length"); + js_setindex(J, -2, i++); + for (k = 0; k < obj->u.s.length; ++k) { + js_pushnumber(J, k); + js_setindex(J, -2, i++); + } + } + + if (obj->type == JS_CREGEXP) { + js_pushliteral(J, "source"); + js_setindex(J, -2, i++); + js_pushliteral(J, "global"); + js_setindex(J, -2, i++); + js_pushliteral(J, "ignoreCase"); + js_setindex(J, -2, i++); + js_pushliteral(J, "multiline"); + js_setindex(J, -2, i++); + js_pushliteral(J, "lastIndex"); + js_setindex(J, -2, i++); + } +} + +static void ToPropertyDescriptor(js_State *J, js_Object *obj, const char *name, js_Object *desc) +{ + int haswritable = 0; + int hasvalue = 0; + int enumerable = 0; + int configurable = 0; + int writable = 0; + int atts = 0; + + js_pushobject(J, obj); + js_pushobject(J, desc); + + if (js_hasproperty(J, -1, "writable")) { + haswritable = 1; + writable = js_toboolean(J, -1); + js_pop(J, 1); + } + if (js_hasproperty(J, -1, "enumerable")) { + enumerable = js_toboolean(J, -1); + js_pop(J, 1); + } + if (js_hasproperty(J, -1, "configurable")) { + configurable = js_toboolean(J, -1); + js_pop(J, 1); + } + if (js_hasproperty(J, -1, "value")) { + hasvalue = 1; + js_setproperty(J, -3, name); + } + + if (!writable) atts |= JS_READONLY; + if (!enumerable) atts |= JS_DONTENUM; + if (!configurable) atts |= JS_DONTCONF; + + if (js_hasproperty(J, -1, "get")) { + if (haswritable || hasvalue) + js_typeerror(J, "value/writable and get/set attributes are exclusive"); + } else { + js_pushundefined(J); + } + + if (js_hasproperty(J, -2, "set")) { + if (haswritable || hasvalue) + js_typeerror(J, "value/writable and get/set attributes are exclusive"); + } else { + js_pushundefined(J); + } + + js_defaccessor(J, -4, name, atts); + + js_pop(J, 2); +} + +static void O_defineProperty(js_State *J) +{ + if (!js_isobject(J, 1)) js_typeerror(J, "not an object"); + if (!js_isobject(J, 3)) js_typeerror(J, "not an object"); + ToPropertyDescriptor(J, js_toobject(J, 1), js_tostring(J, 2), js_toobject(J, 3)); + js_copy(J, 1); +} + +static void O_defineProperties_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + O_defineProperties_walk(J, ref->left); + if (!(ref->atts & JS_DONTENUM)) { + js_pushvalue(J, ref->value); + ToPropertyDescriptor(J, js_toobject(J, 1), ref->name, js_toobject(J, -1)); + js_pop(J, 1); + } + if (ref->right->level) + O_defineProperties_walk(J, ref->right); +} + +static void O_defineProperties(js_State *J) +{ + js_Object *props; + + if (!js_isobject(J, 1)) js_typeerror(J, "not an object"); + if (!js_isobject(J, 2)) js_typeerror(J, "not an object"); + + props = js_toobject(J, 2); + if (props->properties->level) + O_defineProperties_walk(J, props->properties); + + js_copy(J, 1); +} + +static void O_create_walk(js_State *J, js_Object *obj, js_Property *ref) +{ + if (ref->left->level) + O_create_walk(J, obj, ref->left); + if (!(ref->atts & JS_DONTENUM)) { + if (ref->value.type != JS_TOBJECT) + js_typeerror(J, "not an object"); + ToPropertyDescriptor(J, obj, ref->name, ref->value.u.object); + } + if (ref->right->level) + O_create_walk(J, obj, ref->right); +} + +static void O_create(js_State *J) +{ + js_Object *obj; + js_Object *proto; + js_Object *props; + + if (js_isobject(J, 1)) + proto = js_toobject(J, 1); + else if (js_isnull(J, 1)) + proto = NULL; + else + js_typeerror(J, "not an object or null"); + + obj = jsV_newobject(J, JS_COBJECT, proto); + js_pushobject(J, obj); + + if (js_isdefined(J, 2)) { + if (!js_isobject(J, 2)) + js_typeerror(J, "not an object"); + props = js_toobject(J, 2); + if (props->properties->level) + O_create_walk(J, obj, props->properties); + } +} + +static int O_keys_walk(js_State *J, js_Property *ref, int i) +{ + if (ref->left->level) + i = O_keys_walk(J, ref->left, i); + if (!(ref->atts & JS_DONTENUM)) { + js_pushliteral(J, ref->name); + js_setindex(J, -2, i++); + } + if (ref->right->level) + i = O_keys_walk(J, ref->right, i); + return i; +} + +static void O_keys(js_State *J) +{ + js_Object *obj; + int i, k; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + obj = js_toobject(J, 1); + + js_newarray(J); + + if (obj->properties->level) + i = O_keys_walk(J, obj->properties, 0); + else + i = 0; + + if (obj->type == JS_CSTRING) { + for (k = 0; k < obj->u.s.length; ++k) { + js_pushnumber(J, k); + js_setindex(J, -2, i++); + } + } +} + +static void O_preventExtensions(js_State *J) +{ + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + js_toobject(J, 1)->extensible = 0; + js_copy(J, 1); +} + +static void O_isExtensible(js_State *J) +{ + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + js_pushboolean(J, js_toobject(J, 1)->extensible); +} + +static void O_seal_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + O_seal_walk(J, ref->left); + ref->atts |= JS_DONTCONF; + if (ref->right->level) + O_seal_walk(J, ref->right); +} + +static void O_seal(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + obj->extensible = 0; + + if (obj->properties->level) + O_seal_walk(J, obj->properties); + + js_copy(J, 1); +} + +static int O_isSealed_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + if (!O_isSealed_walk(J, ref->left)) + return 0; + if (!(ref->atts & JS_DONTCONF)) + return 0; + if (ref->right->level) + if (!O_isSealed_walk(J, ref->right)) + return 0; + return 1; +} + +static void O_isSealed(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + if (obj->extensible) { + js_pushboolean(J, 0); + return; + } + + if (obj->properties->level) + js_pushboolean(J, O_isSealed_walk(J, obj->properties)); + else + js_pushboolean(J, 1); +} + +static void O_freeze_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + O_freeze_walk(J, ref->left); + ref->atts |= JS_READONLY | JS_DONTCONF; + if (ref->right->level) + O_freeze_walk(J, ref->right); +} + +static void O_freeze(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + obj->extensible = 0; + + if (obj->properties->level) + O_freeze_walk(J, obj->properties); + + js_copy(J, 1); +} + +static int O_isFrozen_walk(js_State *J, js_Property *ref) +{ + if (ref->left->level) + if (!O_isFrozen_walk(J, ref->left)) + return 0; + if (!(ref->atts & JS_READONLY)) + return 0; + if (!(ref->atts & JS_DONTCONF)) + return 0; + if (ref->right->level) + if (!O_isFrozen_walk(J, ref->right)) + return 0; + return 1; +} + +static void O_isFrozen(js_State *J) +{ + js_Object *obj; + + if (!js_isobject(J, 1)) + js_typeerror(J, "not an object"); + + obj = js_toobject(J, 1); + + if (obj->properties->level) { + if (!O_isFrozen_walk(J, obj->properties)) { + js_pushboolean(J, 0); + return; + } + } + + js_pushboolean(J, !obj->extensible); +} + +void jsB_initobject(js_State *J) +{ + js_pushobject(J, J->Object_prototype); + { + jsB_propf(J, "Object.prototype.toString", Op_toString, 0); + jsB_propf(J, "Object.prototype.toLocaleString", Op_toString, 0); + jsB_propf(J, "Object.prototype.valueOf", Op_valueOf, 0); + jsB_propf(J, "Object.prototype.hasOwnProperty", Op_hasOwnProperty, 1); + jsB_propf(J, "Object.prototype.isPrototypeOf", Op_isPrototypeOf, 1); + jsB_propf(J, "Object.prototype.propertyIsEnumerable", Op_propertyIsEnumerable, 1); + } + js_newcconstructor(J, jsB_Object, jsB_new_Object, "Object", 1); + { + /* ES5 */ + jsB_propf(J, "Object.getPrototypeOf", O_getPrototypeOf, 1); + jsB_propf(J, "Object.getOwnPropertyDescriptor", O_getOwnPropertyDescriptor, 2); + jsB_propf(J, "Object.getOwnPropertyNames", O_getOwnPropertyNames, 1); + jsB_propf(J, "Object.create", O_create, 2); + jsB_propf(J, "Object.defineProperty", O_defineProperty, 3); + jsB_propf(J, "Object.defineProperties", O_defineProperties, 2); + jsB_propf(J, "Object.seal", O_seal, 1); + jsB_propf(J, "Object.freeze", O_freeze, 1); + jsB_propf(J, "Object.preventExtensions", O_preventExtensions, 1); + jsB_propf(J, "Object.isSealed", O_isSealed, 1); + jsB_propf(J, "Object.isFrozen", O_isFrozen, 1); + jsB_propf(J, "Object.isExtensible", O_isExtensible, 1); + jsB_propf(J, "Object.keys", O_keys, 1); + } + js_defglobal(J, "Object", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/json.c b/programs/develop/kosjs/libmujs/json.c new file mode 100755 index 0000000000..e1022735b2 --- /dev/null +++ b/programs/develop/kosjs/libmujs/json.c @@ -0,0 +1,414 @@ +#include "jsi.h" +#include "jslex.h" +#include "jsvalue.h" +#include "jsbuiltin.h" + +#include "utf.h" + +int js_isnumberobject(js_State *J, int idx) +{ + return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CNUMBER; +} + +int js_isstringobject(js_State *J, int idx) +{ + return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CSTRING; +} + +static void jsonnext(js_State *J) +{ + J->lookahead = jsY_lexjson(J); +} + +static int jsonaccept(js_State *J, int t) +{ + if (J->lookahead == t) { + jsonnext(J); + return 1; + } + return 0; +} + +static void jsonexpect(js_State *J, int t) +{ + if (!jsonaccept(J, t)) + js_syntaxerror(J, "JSON: unexpected token: %s (expected %s)", + jsY_tokenstring(J->lookahead), jsY_tokenstring(t)); +} + +static void jsonvalue(js_State *J) +{ + int i; + const char *name; + + switch (J->lookahead) { + case TK_STRING: + js_pushstring(J, J->text); + jsonnext(J); + break; + + case TK_NUMBER: + js_pushnumber(J, J->number); + jsonnext(J); + break; + + case '{': + js_newobject(J); + jsonnext(J); + if (jsonaccept(J, '}')) + return; + do { + if (J->lookahead != TK_STRING) + js_syntaxerror(J, "JSON: unexpected token: %s (expected string)", jsY_tokenstring(J->lookahead)); + name = J->text; + jsonnext(J); + jsonexpect(J, ':'); + jsonvalue(J); + js_setproperty(J, -2, name); + } while (jsonaccept(J, ',')); + jsonexpect(J, '}'); + break; + + case '[': + js_newarray(J); + jsonnext(J); + i = 0; + if (jsonaccept(J, ']')) + return; + do { + jsonvalue(J); + js_setindex(J, -2, i++); + } while (jsonaccept(J, ',')); + jsonexpect(J, ']'); + break; + + case TK_TRUE: + js_pushboolean(J, 1); + jsonnext(J); + break; + + case TK_FALSE: + js_pushboolean(J, 0); + jsonnext(J); + break; + + case TK_NULL: + js_pushnull(J); + jsonnext(J); + break; + + default: + js_syntaxerror(J, "JSON: unexpected token: %s", jsY_tokenstring(J->lookahead)); + } +} + +static void jsonrevive(js_State *J, const char *name) +{ + const char *key; + char buf[32]; + + /* revive is in 2 */ + /* holder is in -1 */ + + js_getproperty(J, -1, name); /* get value from holder */ + + if (js_isobject(J, -1)) { + if (js_isarray(J, -1)) { + int i = 0; + int n = js_getlength(J, -1); + for (i = 0; i < n; ++i) { + jsonrevive(J, js_itoa(buf, i)); + if (js_isundefined(J, -1)) { + js_pop(J, 1); + js_delproperty(J, -1, buf); + } else { + js_setproperty(J, -2, buf); + } + } + } else { + js_pushiterator(J, -1, 1); + while ((key = js_nextiterator(J, -1))) { + js_rot2(J); + jsonrevive(J, key); + if (js_isundefined(J, -1)) { + js_pop(J, 1); + js_delproperty(J, -1, key); + } else { + js_setproperty(J, -2, key); + } + js_rot2(J); + } + js_pop(J, 1); + } + } + + js_copy(J, 2); /* reviver function */ + js_copy(J, -3); /* holder as this */ + js_pushstring(J, name); /* name */ + js_copy(J, -4); /* value */ + js_call(J, 2); + js_rot2pop1(J); /* pop old value, leave new value on stack */ +} + +static void JSON_parse(js_State *J) +{ + const char *source = js_tostring(J, 1); + jsY_initlex(J, "JSON", source); + jsonnext(J); + + if (js_iscallable(J, 2)) { + js_newobject(J); + jsonvalue(J); + js_defproperty(J, -2, "", 0); + jsonrevive(J, ""); + } else { + jsonvalue(J); + } +} + +static void fmtnum(js_State *J, js_Buffer **sb, double n) +{ + if (isnan(n)) js_puts(J, sb, "null"); + else if (isinf(n)) js_puts(J, sb, "null"); + else if (n == 0) js_puts(J, sb, "0"); + else { + char buf[40]; + js_puts(J, sb, jsV_numbertostring(J, buf, n)); + } +} + +static void fmtstr(js_State *J, js_Buffer **sb, const char *s) +{ + static const char *HEX = "0123456789ABCDEF"; + int i, n; + Rune c; + js_putc(J, sb, '"'); + while (*s) { + n = chartorune(&c, s); + switch (c) { + case '"': js_puts(J, sb, "\\\""); break; + case '\\': js_puts(J, sb, "\\\\"); break; + case '\b': js_puts(J, sb, "\\b"); break; + case '\f': js_puts(J, sb, "\\f"); break; + case '\n': js_puts(J, sb, "\\n"); break; + case '\r': js_puts(J, sb, "\\r"); break; + case '\t': js_puts(J, sb, "\\t"); break; + default: + if (c < ' ') { + js_putc(J, sb, '\\'); + js_putc(J, sb, 'u'); + js_putc(J, sb, HEX[(c>>12)&15]); + js_putc(J, sb, HEX[(c>>8)&15]); + js_putc(J, sb, HEX[(c>>4)&15]); + js_putc(J, sb, HEX[c&15]); + } else if (c < 128) { + js_putc(J, sb, c); + } else { + for (i = 0; i < n; ++i) + js_putc(J, sb, s[i]); + } + break; + } + s += n; + } + js_putc(J, sb, '"'); +} + +static void fmtindent(js_State *J, js_Buffer **sb, const char *gap, int level) +{ + js_putc(J, sb, '\n'); + while (level--) + js_puts(J, sb, gap); +} + +static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level); + +static int filterprop(js_State *J, const char *key) +{ + int i, n, found; + /* replacer/property-list is in stack slot 2 */ + if (js_isarray(J, 2)) { + found = 0; + n = js_getlength(J, 2); + for (i = 0; i < n && !found; ++i) { + js_getindex(J, 2, i); + if (js_isstring(J, -1) || js_isnumber(J, -1) || + js_isstringobject(J, -1) || js_isnumberobject(J, -1)) + found = !strcmp(key, js_tostring(J, -1)); + js_pop(J, 1); + } + return found; + } + return 1; +} + +static void fmtobject(js_State *J, js_Buffer **sb, js_Object *obj, const char *gap, int level) +{ + const char *key; + int save; + int i, n; + + n = js_gettop(J) - 1; + for (i = 4; i < n; ++i) + if (js_isobject(J, i)) + if (js_toobject(J, i) == js_toobject(J, -1)) + js_typeerror(J, "cyclic object value"); + + n = 0; + js_putc(J, sb, '{'); + js_pushiterator(J, -1, 1); + while ((key = js_nextiterator(J, -1))) { + if (filterprop(J, key)) { + save = (*sb)->n; + if (n) js_putc(J, sb, ','); + if (gap) fmtindent(J, sb, gap, level + 1); + fmtstr(J, sb, key); + js_putc(J, sb, ':'); + if (gap) + js_putc(J, sb, ' '); + js_rot2(J); + if (!fmtvalue(J, sb, key, gap, level + 1)) + (*sb)->n = save; + else + ++n; + js_rot2(J); + } + } + js_pop(J, 1); + if (gap && n) fmtindent(J, sb, gap, level); + js_putc(J, sb, '}'); +} + +static void fmtarray(js_State *J, js_Buffer **sb, const char *gap, int level) +{ + int n, i; + char buf[32]; + + n = js_gettop(J) - 1; + for (i = 4; i < n; ++i) + if (js_isobject(J, i)) + if (js_toobject(J, i) == js_toobject(J, -1)) + js_typeerror(J, "cyclic object value"); + + js_putc(J, sb, '['); + n = js_getlength(J, -1); + for (i = 0; i < n; ++i) { + if (i) js_putc(J, sb, ','); + if (gap) fmtindent(J, sb, gap, level + 1); + if (!fmtvalue(J, sb, js_itoa(buf, i), gap, level + 1)) + js_puts(J, sb, "null"); + } + if (gap && n) fmtindent(J, sb, gap, level); + js_putc(J, sb, ']'); +} + +static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level) +{ + /* replacer/property-list is in 2 */ + /* holder is in -1 */ + + js_getproperty(J, -1, key); + + if (js_isobject(J, -1)) { + if (js_hasproperty(J, -1, "toJSON")) { + if (js_iscallable(J, -1)) { + js_copy(J, -2); + js_pushstring(J, key); + js_call(J, 1); + js_rot2pop1(J); + } else { + js_pop(J, 1); + } + } + } + + if (js_iscallable(J, 2)) { + js_copy(J, 2); /* replacer function */ + js_copy(J, -3); /* holder as this */ + js_pushstring(J, key); /* name */ + js_copy(J, -4); /* old value */ + js_call(J, 2); + js_rot2pop1(J); /* pop old value, leave new value on stack */ + } + + if (js_isobject(J, -1) && !js_iscallable(J, -1)) { + js_Object *obj = js_toobject(J, -1); + switch (obj->type) { + case JS_CNUMBER: fmtnum(J, sb, obj->u.number); break; + case JS_CSTRING: fmtstr(J, sb, obj->u.s.string); break; + case JS_CBOOLEAN: js_puts(J, sb, obj->u.boolean ? "true" : "false"); break; + case JS_CARRAY: fmtarray(J, sb, gap, level); break; + default: fmtobject(J, sb, obj, gap, level); break; + } + } + else if (js_isboolean(J, -1)) + js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false"); + else if (js_isnumber(J, -1)) + fmtnum(J, sb, js_tonumber(J, -1)); + else if (js_isstring(J, -1)) + fmtstr(J, sb, js_tostring(J, -1)); + else if (js_isnull(J, -1)) + js_puts(J, sb, "null"); + else { + js_pop(J, 1); + return 0; + } + + js_pop(J, 1); + return 1; +} + +static void JSON_stringify(js_State *J) +{ + js_Buffer *sb = NULL; + char buf[12]; + const char *s, *gap; + int n; + + gap = NULL; + + if (js_isnumber(J, 3) || js_isnumberobject(J, 3)) { + n = js_tointeger(J, 3); + if (n < 0) n = 0; + if (n > 10) n = 10; + memset(buf, ' ', n); + buf[n] = 0; + if (n > 0) gap = buf; + } else if (js_isstring(J, 3) || js_isstringobject(J, 3)) { + s = js_tostring(J, 3); + n = strlen(s); + if (n > 10) n = 10; + memcpy(buf, s, n); + buf[n] = 0; + if (n > 0) gap = buf; + } + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_newobject(J); /* wrapper */ + js_copy(J, 1); + js_defproperty(J, -2, "", 0); + if (!fmtvalue(J, &sb, "", gap, 0)) { + js_pushundefined(J); + } else { + js_putc(J, &sb, 0); + js_pushstring(J, sb ? sb->s : ""); + js_rot2pop1(J); + } + + js_endtry(J); + js_free(J, sb); +} + +void jsB_initjson(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, JS_CJSON, J->Object_prototype)); + { + jsB_propf(J, "JSON.parse", JSON_parse, 2); + jsB_propf(J, "JSON.stringify", JSON_stringify, 3); + } + js_defglobal(J, "JSON", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsparse.c b/programs/develop/kosjs/libmujs/jsparse.c new file mode 100755 index 0000000000..f91f491eea --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsparse.c @@ -0,0 +1,1067 @@ +#include "jsi.h" +#include "jslex.h" +#include "jsparse.h" + +#define LIST(h) jsP_newnode(J, AST_LIST, 0, h, 0, 0, 0) + +#define EXP0(x) jsP_newnode(J, EXP_ ## x, line, 0, 0, 0, 0) +#define EXP1(x,a) jsP_newnode(J, EXP_ ## x, line, a, 0, 0, 0) +#define EXP2(x,a,b) jsP_newnode(J, EXP_ ## x, line, a, b, 0, 0) +#define EXP3(x,a,b,c) jsP_newnode(J, EXP_ ## x, line, a, b, c, 0) + +#define STM0(x) jsP_newnode(J, STM_ ## x, line, 0, 0, 0, 0) +#define STM1(x,a) jsP_newnode(J, STM_ ## x, line, a, 0, 0, 0) +#define STM2(x,a,b) jsP_newnode(J, STM_ ## x, line, a, b, 0, 0) +#define STM3(x,a,b,c) jsP_newnode(J, STM_ ## x, line, a, b, c, 0) +#define STM4(x,a,b,c,d) jsP_newnode(J, STM_ ## x, line, a, b, c, d) + +static js_Ast *expression(js_State *J, int notin); +static js_Ast *assignment(js_State *J, int notin); +static js_Ast *memberexp(js_State *J); +static js_Ast *statement(js_State *J); +static js_Ast *funbody(js_State *J); + +JS_NORETURN static void jsP_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); + +#define INCREC() if (++J->astdepth > JS_ASTLIMIT) jsP_error(J, "too much recursion") +#define DECREC() --J->astdepth +#define SAVEREC() int SAVE=J->astdepth +#define POPREC() J->astdepth=SAVE + +static void jsP_error(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msgbuf[256]; + + va_start(ap, fmt); + vsnprintf(msgbuf, 256, fmt, ap); + va_end(ap); + + snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); + strcat(buf, msgbuf); + + js_newsyntaxerror(J, buf); + js_throw(J); +} + +static void jsP_warning(js_State *J, const char *fmt, ...) +{ + va_list ap; + char buf[512]; + char msg[256]; + + va_start(ap, fmt); + vsnprintf(msg, sizeof msg, fmt, ap); + va_end(ap); + + snprintf(buf, sizeof buf, "%s:%d: warning: %s", J->filename, J->lexline, msg); + js_report(J, buf); +} + +static js_Ast *jsP_newnode(js_State *J, enum js_AstType type, int line, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d) +{ + js_Ast *node = js_malloc(J, sizeof *node); + + node->type = type; + node->line = line; + node->a = a; + node->b = b; + node->c = c; + node->d = d; + node->number = 0; + node->string = NULL; + node->jumps = NULL; + node->casejump = 0; + + node->parent = NULL; + if (a) a->parent = node; + if (b) b->parent = node; + if (c) c->parent = node; + if (d) d->parent = node; + + node->gcnext = J->gcast; + J->gcast = node; + + return node; +} + +static js_Ast *jsP_list(js_Ast *head) +{ + /* set parent pointers in list nodes */ + js_Ast *prev = head, *node = head->b; + while (node) { + node->parent = prev; + prev = node; + node = node->b; + } + return head; +} + +static js_Ast *jsP_newstrnode(js_State *J, enum js_AstType type, const char *s) +{ + js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); + node->string = s; + return node; +} + +static js_Ast *jsP_newnumnode(js_State *J, enum js_AstType type, double n) +{ + js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); + node->number = n; + return node; +} + +static void jsP_freejumps(js_State *J, js_JumpList *node) +{ + while (node) { + js_JumpList *next = node->next; + js_free(J, node); + node = next; + } +} + +void jsP_freeparse(js_State *J) +{ + js_Ast *node = J->gcast; + while (node) { + js_Ast *next = node->gcnext; + jsP_freejumps(J, node->jumps); + js_free(J, node); + node = next; + } + J->gcast = NULL; +} + +/* Lookahead */ + +static void jsP_next(js_State *J) +{ + J->lookahead = jsY_lex(J); +} + +#define jsP_accept(J,x) (J->lookahead == x ? (jsP_next(J), 1) : 0) + +#define jsP_expect(J,x) if (!jsP_accept(J, x)) jsP_error(J, "unexpected token: %s (expected %s)", jsY_tokenstring(J->lookahead), jsY_tokenstring(x)) + +static void semicolon(js_State *J) +{ + if (J->lookahead == ';') { + jsP_next(J); + return; + } + if (J->newline || J->lookahead == '}' || J->lookahead == 0) + return; + jsP_error(J, "unexpected token: %s (expected ';')", jsY_tokenstring(J->lookahead)); +} + +/* Literals */ + +static js_Ast *identifier(js_State *J) +{ + js_Ast *a; + if (J->lookahead == TK_IDENTIFIER) { + a = jsP_newstrnode(J, AST_IDENTIFIER, J->text); + jsP_next(J); + return a; + } + jsP_error(J, "unexpected token: %s (expected identifier)", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *identifieropt(js_State *J) +{ + if (J->lookahead == TK_IDENTIFIER) + return identifier(J); + return NULL; +} + +static js_Ast *identifiername(js_State *J) +{ + if (J->lookahead == TK_IDENTIFIER || J->lookahead >= TK_BREAK) { + js_Ast *a = jsP_newstrnode(J, AST_IDENTIFIER, J->text); + jsP_next(J); + return a; + } + jsP_error(J, "unexpected token: %s (expected identifier or keyword)", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *arrayelement(js_State *J) +{ + int line = J->lexline; + if (J->lookahead == ',') + return EXP0(UNDEF); + return assignment(J, 0); +} + +static js_Ast *arrayliteral(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == ']') + return NULL; + head = tail = LIST(arrayelement(J)); + while (jsP_accept(J, ',')) { + if (J->lookahead != ']') + tail = tail->b = LIST(arrayelement(J)); + } + return jsP_list(head); +} + +static js_Ast *propname(js_State *J) +{ + js_Ast *name; + if (J->lookahead == TK_NUMBER) { + name = jsP_newnumnode(J, EXP_NUMBER, J->number); + jsP_next(J); + } else if (J->lookahead == TK_STRING) { + name = jsP_newstrnode(J, EXP_STRING, J->text); + jsP_next(J); + } else { + name = identifiername(J); + } + return name; +} + +static js_Ast *propassign(js_State *J) +{ + js_Ast *name, *value, *arg, *body; + int line = J->lexline; + + name = propname(J); + + if (J->lookahead != ':' && name->type == AST_IDENTIFIER) { + if (!strcmp(name->string, "get")) { + name = propname(J); + jsP_expect(J, '('); + jsP_expect(J, ')'); + body = funbody(J); + return EXP3(PROP_GET, name, NULL, body); + } + if (!strcmp(name->string, "set")) { + name = propname(J); + jsP_expect(J, '('); + arg = identifier(J); + jsP_expect(J, ')'); + body = funbody(J); + return EXP3(PROP_SET, name, LIST(arg), body); + } + } + + jsP_expect(J, ':'); + value = assignment(J, 0); + return EXP2(PROP_VAL, name, value); +} + +static js_Ast *objectliteral(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == '}') + return NULL; + head = tail = LIST(propassign(J)); + while (jsP_accept(J, ',')) { + if (J->lookahead == '}') + break; + tail = tail->b = LIST(propassign(J)); + } + return jsP_list(head); +} + +/* Functions */ + +static js_Ast *parameters(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == ')') + return NULL; + head = tail = LIST(identifier(J)); + while (jsP_accept(J, ',')) { + tail = tail->b = LIST(identifier(J)); + } + return jsP_list(head); +} + +static js_Ast *fundec(js_State *J, int line) +{ + js_Ast *a, *b, *c; + a = identifier(J); + jsP_expect(J, '('); + b = parameters(J); + jsP_expect(J, ')'); + c = funbody(J); + return jsP_newnode(J, AST_FUNDEC, line, a, b, c, 0); +} + +static js_Ast *funstm(js_State *J, int line) +{ + js_Ast *a, *b, *c; + a = identifier(J); + jsP_expect(J, '('); + b = parameters(J); + jsP_expect(J, ')'); + c = funbody(J); + /* rewrite function statement as "var X = function X() {}" */ + return STM1(VAR, LIST(EXP2(VAR, a, EXP3(FUN, a, b, c)))); +} + +static js_Ast *funexp(js_State *J, int line) +{ + js_Ast *a, *b, *c; + a = identifieropt(J); + jsP_expect(J, '('); + b = parameters(J); + jsP_expect(J, ')'); + c = funbody(J); + return EXP3(FUN, a, b, c); +} + +/* Expressions */ + +static js_Ast *primary(js_State *J) +{ + js_Ast *a; + int line = J->lexline; + + if (J->lookahead == TK_IDENTIFIER) { + a = jsP_newstrnode(J, EXP_IDENTIFIER, J->text); + jsP_next(J); + return a; + } + if (J->lookahead == TK_STRING) { + a = jsP_newstrnode(J, EXP_STRING, J->text); + jsP_next(J); + return a; + } + if (J->lookahead == TK_REGEXP) { + a = jsP_newstrnode(J, EXP_REGEXP, J->text); + a->number = J->number; + jsP_next(J); + return a; + } + if (J->lookahead == TK_NUMBER) { + a = jsP_newnumnode(J, EXP_NUMBER, J->number); + jsP_next(J); + return a; + } + + if (jsP_accept(J, TK_THIS)) return EXP0(THIS); + if (jsP_accept(J, TK_NULL)) return EXP0(NULL); + if (jsP_accept(J, TK_TRUE)) return EXP0(TRUE); + if (jsP_accept(J, TK_FALSE)) return EXP0(FALSE); + if (jsP_accept(J, '{')) { + a = EXP1(OBJECT, objectliteral(J)); + jsP_expect(J, '}'); + return a; + } + if (jsP_accept(J, '[')) { + a = EXP1(ARRAY, arrayliteral(J)); + jsP_expect(J, ']'); + return a; + } + if (jsP_accept(J, '(')) { + a = expression(J, 0); + jsP_expect(J, ')'); + return a; + } + + jsP_error(J, "unexpected token in expression: %s", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *arguments(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == ')') + return NULL; + head = tail = LIST(assignment(J, 0)); + while (jsP_accept(J, ',')) { + tail = tail->b = LIST(assignment(J, 0)); + } + return jsP_list(head); +} + +static js_Ast *newexp(js_State *J) +{ + js_Ast *a, *b; + int line = J->lexline; + + if (jsP_accept(J, TK_NEW)) { + a = memberexp(J); + if (jsP_accept(J, '(')) { + b = arguments(J); + jsP_expect(J, ')'); + return EXP2(NEW, a, b); + } + return EXP1(NEW, a); + } + + if (jsP_accept(J, TK_FUNCTION)) + return funexp(J, line); + + return primary(J); +} + +static js_Ast *memberexp(js_State *J) +{ + js_Ast *a = newexp(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } + if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } + POPREC(); + return a; +} + +static js_Ast *callexp(js_State *J) +{ + js_Ast *a = newexp(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } + if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } + if (jsP_accept(J, '(')) { a = EXP2(CALL, a, arguments(J)); jsP_expect(J, ')'); goto loop; } + POPREC(); + return a; +} + +static js_Ast *postfix(js_State *J) +{ + js_Ast *a = callexp(J); + int line = J->lexline; + if (!J->newline && jsP_accept(J, TK_INC)) return EXP1(POSTINC, a); + if (!J->newline && jsP_accept(J, TK_DEC)) return EXP1(POSTDEC, a); + return a; +} + +static js_Ast *unary(js_State *J) +{ + js_Ast *a; + int line = J->lexline; + INCREC(); + if (jsP_accept(J, TK_DELETE)) a = EXP1(DELETE, unary(J)); + else if (jsP_accept(J, TK_VOID)) a = EXP1(VOID, unary(J)); + else if (jsP_accept(J, TK_TYPEOF)) a = EXP1(TYPEOF, unary(J)); + else if (jsP_accept(J, TK_INC)) a = EXP1(PREINC, unary(J)); + else if (jsP_accept(J, TK_DEC)) a = EXP1(PREDEC, unary(J)); + else if (jsP_accept(J, '+')) a = EXP1(POS, unary(J)); + else if (jsP_accept(J, '-')) a = EXP1(NEG, unary(J)); + else if (jsP_accept(J, '~')) a = EXP1(BITNOT, unary(J)); + else if (jsP_accept(J, '!')) a = EXP1(LOGNOT, unary(J)); + else a = postfix(J); + DECREC(); + return a; +} + +static js_Ast *multiplicative(js_State *J) +{ + js_Ast *a = unary(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '*')) { a = EXP2(MUL, a, unary(J)); goto loop; } + if (jsP_accept(J, '/')) { a = EXP2(DIV, a, unary(J)); goto loop; } + if (jsP_accept(J, '%')) { a = EXP2(MOD, a, unary(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *additive(js_State *J) +{ + js_Ast *a = multiplicative(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '+')) { a = EXP2(ADD, a, multiplicative(J)); goto loop; } + if (jsP_accept(J, '-')) { a = EXP2(SUB, a, multiplicative(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *shift(js_State *J) +{ + js_Ast *a = additive(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, TK_SHL)) { a = EXP2(SHL, a, additive(J)); goto loop; } + if (jsP_accept(J, TK_SHR)) { a = EXP2(SHR, a, additive(J)); goto loop; } + if (jsP_accept(J, TK_USHR)) { a = EXP2(USHR, a, additive(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *relational(js_State *J, int notin) +{ + js_Ast *a = shift(J); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, '<')) { a = EXP2(LT, a, shift(J)); goto loop; } + if (jsP_accept(J, '>')) { a = EXP2(GT, a, shift(J)); goto loop; } + if (jsP_accept(J, TK_LE)) { a = EXP2(LE, a, shift(J)); goto loop; } + if (jsP_accept(J, TK_GE)) { a = EXP2(GE, a, shift(J)); goto loop; } + if (jsP_accept(J, TK_INSTANCEOF)) { a = EXP2(INSTANCEOF, a, shift(J)); goto loop; } + if (!notin && jsP_accept(J, TK_IN)) { a = EXP2(IN, a, shift(J)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *equality(js_State *J, int notin) +{ + js_Ast *a = relational(J, notin); + int line; + SAVEREC(); +loop: + INCREC(); + line = J->lexline; + if (jsP_accept(J, TK_EQ)) { a = EXP2(EQ, a, relational(J, notin)); goto loop; } + if (jsP_accept(J, TK_NE)) { a = EXP2(NE, a, relational(J, notin)); goto loop; } + if (jsP_accept(J, TK_STRICTEQ)) { a = EXP2(STRICTEQ, a, relational(J, notin)); goto loop; } + if (jsP_accept(J, TK_STRICTNE)) { a = EXP2(STRICTNE, a, relational(J, notin)); goto loop; } + POPREC(); + return a; +} + +static js_Ast *bitand(js_State *J, int notin) +{ + js_Ast *a = equality(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, '&')) { + INCREC(); + a = EXP2(BITAND, a, equality(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +static js_Ast *bitxor(js_State *J, int notin) +{ + js_Ast *a = bitand(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, '^')) { + INCREC(); + a = EXP2(BITXOR, a, bitand(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +static js_Ast *bitor(js_State *J, int notin) +{ + js_Ast *a = bitxor(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, '|')) { + INCREC(); + a = EXP2(BITOR, a, bitxor(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +static js_Ast *logand(js_State *J, int notin) +{ + js_Ast *a = bitor(J, notin); + int line = J->lexline; + if (jsP_accept(J, TK_AND)) { + INCREC(); + a = EXP2(LOGAND, a, logand(J, notin)); + DECREC(); + } + return a; +} + +static js_Ast *logor(js_State *J, int notin) +{ + js_Ast *a = logand(J, notin); + int line = J->lexline; + if (jsP_accept(J, TK_OR)) { + INCREC(); + a = EXP2(LOGOR, a, logor(J, notin)); + DECREC(); + } + return a; +} + +static js_Ast *conditional(js_State *J, int notin) +{ + js_Ast *a = logor(J, notin); + int line = J->lexline; + if (jsP_accept(J, '?')) { + js_Ast *b, *c; + INCREC(); + b = assignment(J, 0); + jsP_expect(J, ':'); + c = assignment(J, notin); + DECREC(); + return EXP3(COND, a, b, c); + } + return a; +} + +static js_Ast *assignment(js_State *J, int notin) +{ + js_Ast *a = conditional(J, notin); + int line = J->lexline; + INCREC(); + if (jsP_accept(J, '=')) a = EXP2(ASS, a, assignment(J, notin)); + else if (jsP_accept(J, TK_MUL_ASS)) a = EXP2(ASS_MUL, a, assignment(J, notin)); + else if (jsP_accept(J, TK_DIV_ASS)) a = EXP2(ASS_DIV, a, assignment(J, notin)); + else if (jsP_accept(J, TK_MOD_ASS)) a = EXP2(ASS_MOD, a, assignment(J, notin)); + else if (jsP_accept(J, TK_ADD_ASS)) a = EXP2(ASS_ADD, a, assignment(J, notin)); + else if (jsP_accept(J, TK_SUB_ASS)) a = EXP2(ASS_SUB, a, assignment(J, notin)); + else if (jsP_accept(J, TK_SHL_ASS)) a = EXP2(ASS_SHL, a, assignment(J, notin)); + else if (jsP_accept(J, TK_SHR_ASS)) a = EXP2(ASS_SHR, a, assignment(J, notin)); + else if (jsP_accept(J, TK_USHR_ASS)) a = EXP2(ASS_USHR, a, assignment(J, notin)); + else if (jsP_accept(J, TK_AND_ASS)) a = EXP2(ASS_BITAND, a, assignment(J, notin)); + else if (jsP_accept(J, TK_XOR_ASS)) a = EXP2(ASS_BITXOR, a, assignment(J, notin)); + else if (jsP_accept(J, TK_OR_ASS)) a = EXP2(ASS_BITOR, a, assignment(J, notin)); + DECREC(); + return a; +} + +static js_Ast *expression(js_State *J, int notin) +{ + js_Ast *a = assignment(J, notin); + SAVEREC(); + int line = J->lexline; + while (jsP_accept(J, ',')) { + INCREC(); + a = EXP2(COMMA, a, assignment(J, notin)); + line = J->lexline; + } + POPREC(); + return a; +} + +/* Statements */ + +static js_Ast *vardec(js_State *J, int notin) +{ + js_Ast *a = identifier(J); + int line = J->lexline; + if (jsP_accept(J, '=')) + return EXP2(VAR, a, assignment(J, notin)); + return EXP1(VAR, a); +} + +static js_Ast *vardeclist(js_State *J, int notin) +{ + js_Ast *head, *tail; + head = tail = LIST(vardec(J, notin)); + while (jsP_accept(J, ',')) + tail = tail->b = LIST(vardec(J, notin)); + return jsP_list(head); +} + +static js_Ast *statementlist(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == '}' || J->lookahead == TK_CASE || J->lookahead == TK_DEFAULT) + return NULL; + head = tail = LIST(statement(J)); + while (J->lookahead != '}' && J->lookahead != TK_CASE && J->lookahead != TK_DEFAULT) + tail = tail->b = LIST(statement(J)); + return jsP_list(head); +} + +static js_Ast *caseclause(js_State *J) +{ + js_Ast *a, *b; + int line = J->lexline; + + if (jsP_accept(J, TK_CASE)) { + a = expression(J, 0); + jsP_expect(J, ':'); + b = statementlist(J); + return STM2(CASE, a, b); + } + + if (jsP_accept(J, TK_DEFAULT)) { + jsP_expect(J, ':'); + a = statementlist(J); + return STM1(DEFAULT, a); + } + + jsP_error(J, "unexpected token in switch: %s (expected 'case' or 'default')", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *caselist(js_State *J) +{ + js_Ast *head, *tail; + if (J->lookahead == '}') + return NULL; + head = tail = LIST(caseclause(J)); + while (J->lookahead != '}') + tail = tail->b = LIST(caseclause(J)); + return jsP_list(head); +} + +static js_Ast *block(js_State *J) +{ + js_Ast *a; + int line = J->lexline; + jsP_expect(J, '{'); + a = statementlist(J); + jsP_expect(J, '}'); + return STM1(BLOCK, a); +} + +static js_Ast *forexpression(js_State *J, int end) +{ + js_Ast *a = NULL; + if (J->lookahead != end) + a = expression(J, 0); + jsP_expect(J, end); + return a; +} + +static js_Ast *forstatement(js_State *J, int line) +{ + js_Ast *a, *b, *c, *d; + jsP_expect(J, '('); + if (jsP_accept(J, TK_VAR)) { + a = vardeclist(J, 1); + if (jsP_accept(J, ';')) { + b = forexpression(J, ';'); + c = forexpression(J, ')'); + d = statement(J); + return STM4(FOR_VAR, a, b, c, d); + } + if (jsP_accept(J, TK_IN)) { + b = expression(J, 0); + jsP_expect(J, ')'); + c = statement(J); + return STM3(FOR_IN_VAR, a, b, c); + } + jsP_error(J, "unexpected token in for-var-statement: %s", jsY_tokenstring(J->lookahead)); + } + + if (J->lookahead != ';') + a = expression(J, 1); + else + a = NULL; + if (jsP_accept(J, ';')) { + b = forexpression(J, ';'); + c = forexpression(J, ')'); + d = statement(J); + return STM4(FOR, a, b, c, d); + } + if (jsP_accept(J, TK_IN)) { + b = expression(J, 0); + jsP_expect(J, ')'); + c = statement(J); + return STM3(FOR_IN, a, b, c); + } + jsP_error(J, "unexpected token in for-statement: %s", jsY_tokenstring(J->lookahead)); +} + +static js_Ast *statement(js_State *J) +{ + js_Ast *a, *b, *c, *d; + js_Ast *stm; + int line = J->lexline; + + INCREC(); + + if (J->lookahead == '{') { + stm = block(J); + } + + else if (jsP_accept(J, TK_VAR)) { + a = vardeclist(J, 0); + semicolon(J); + stm = STM1(VAR, a); + } + + /* empty statement */ + else if (jsP_accept(J, ';')) { + stm = STM0(EMPTY); + } + + else if (jsP_accept(J, TK_IF)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + b = statement(J); + if (jsP_accept(J, TK_ELSE)) + c = statement(J); + else + c = NULL; + stm = STM3(IF, a, b, c); + } + + else if (jsP_accept(J, TK_DO)) { + a = statement(J); + jsP_expect(J, TK_WHILE); + jsP_expect(J, '('); + b = expression(J, 0); + jsP_expect(J, ')'); + semicolon(J); + stm = STM2(DO, a, b); + } + + else if (jsP_accept(J, TK_WHILE)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + b = statement(J); + stm = STM2(WHILE, a, b); + } + + else if (jsP_accept(J, TK_FOR)) { + stm = forstatement(J, line); + } + + else if (jsP_accept(J, TK_CONTINUE)) { + a = identifieropt(J); + semicolon(J); + stm = STM1(CONTINUE, a); + } + + else if (jsP_accept(J, TK_BREAK)) { + a = identifieropt(J); + semicolon(J); + stm = STM1(BREAK, a); + } + + else if (jsP_accept(J, TK_RETURN)) { + if (J->lookahead != ';' && J->lookahead != '}' && J->lookahead != 0) + a = expression(J, 0); + else + a = NULL; + semicolon(J); + stm = STM1(RETURN, a); + } + + else if (jsP_accept(J, TK_WITH)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + b = statement(J); + stm = STM2(WITH, a, b); + } + + else if (jsP_accept(J, TK_SWITCH)) { + jsP_expect(J, '('); + a = expression(J, 0); + jsP_expect(J, ')'); + jsP_expect(J, '{'); + b = caselist(J); + jsP_expect(J, '}'); + stm = STM2(SWITCH, a, b); + } + + else if (jsP_accept(J, TK_THROW)) { + a = expression(J, 0); + semicolon(J); + stm = STM1(THROW, a); + } + + else if (jsP_accept(J, TK_TRY)) { + a = block(J); + b = c = d = NULL; + if (jsP_accept(J, TK_CATCH)) { + jsP_expect(J, '('); + b = identifier(J); + jsP_expect(J, ')'); + c = block(J); + } + if (jsP_accept(J, TK_FINALLY)) { + d = block(J); + } + if (!b && !d) + jsP_error(J, "unexpected token in try: %s (expected 'catch' or 'finally')", jsY_tokenstring(J->lookahead)); + stm = STM4(TRY, a, b, c, d); + } + + else if (jsP_accept(J, TK_DEBUGGER)) { + semicolon(J); + stm = STM0(DEBUGGER); + } + + else if (jsP_accept(J, TK_FUNCTION)) { + jsP_warning(J, "function statements are not standard"); + stm = funstm(J, line); + } + + /* labelled statement or expression statement */ + else if (J->lookahead == TK_IDENTIFIER) { + a = expression(J, 0); + if (a->type == EXP_IDENTIFIER && jsP_accept(J, ':')) { + a->type = AST_IDENTIFIER; + b = statement(J); + stm = STM2(LABEL, a, b); + } else { + semicolon(J); + stm = a; + } + } + + /* expression statement */ + else { + stm = expression(J, 0); + semicolon(J); + } + + DECREC(); + return stm; +} + +/* Program */ + +static js_Ast *scriptelement(js_State *J) +{ + int line = J->lexline; + if (jsP_accept(J, TK_FUNCTION)) + return fundec(J, line); + return statement(J); +} + +static js_Ast *script(js_State *J, int terminator) +{ + js_Ast *head, *tail; + if (J->lookahead == terminator) + return NULL; + head = tail = LIST(scriptelement(J)); + while (J->lookahead != terminator) + tail = tail->b = LIST(scriptelement(J)); + return jsP_list(head); +} + +static js_Ast *funbody(js_State *J) +{ + js_Ast *a; + jsP_expect(J, '{'); + a = script(J, '}'); + jsP_expect(J, '}'); + return a; +} + +/* Constant folding */ + +static int toint32(double d) +{ + double two32 = 4294967296.0; + double two31 = 2147483648.0; + + if (!isfinite(d) || d == 0) + return 0; + + d = fmod(d, two32); + d = d >= 0 ? floor(d) : ceil(d) + two32; + if (d >= two31) + return d - two32; + else + return d; +} + +static unsigned int touint32(double d) +{ + return (unsigned int)toint32(d); +} + +static int jsP_setnumnode(js_Ast *node, double x) +{ + node->type = EXP_NUMBER; + node->number = x; + node->a = node->b = node->c = node->d = NULL; + return 1; +} + +static int jsP_foldconst(js_Ast *node) +{ + double x, y; + int a, b; + + if (node->type == AST_LIST) { + while (node) { + jsP_foldconst(node->a); + node = node->b; + } + return 0; + } + + if (node->type == EXP_NUMBER) + return 1; + + a = node->a ? jsP_foldconst(node->a) : 0; + b = node->b ? jsP_foldconst(node->b) : 0; + if (node->c) jsP_foldconst(node->c); + if (node->d) jsP_foldconst(node->d); + + if (a) { + x = node->a->number; + switch (node->type) { + default: break; + case EXP_NEG: return jsP_setnumnode(node, -x); + case EXP_POS: return jsP_setnumnode(node, x); + case EXP_BITNOT: return jsP_setnumnode(node, ~toint32(x)); + } + + if (b) { + y = node->b->number; + switch (node->type) { + default: break; + case EXP_MUL: return jsP_setnumnode(node, x * y); + case EXP_DIV: return jsP_setnumnode(node, x / y); + case EXP_MOD: return jsP_setnumnode(node, fmod(x, y)); + case EXP_ADD: return jsP_setnumnode(node, x + y); + case EXP_SUB: return jsP_setnumnode(node, x - y); + case EXP_SHL: return jsP_setnumnode(node, toint32(x) << (touint32(y) & 0x1F)); + case EXP_SHR: return jsP_setnumnode(node, toint32(x) >> (touint32(y) & 0x1F)); + case EXP_USHR: return jsP_setnumnode(node, touint32(x) >> (touint32(y) & 0x1F)); + case EXP_BITAND: return jsP_setnumnode(node, toint32(x) & toint32(y)); + case EXP_BITXOR: return jsP_setnumnode(node, toint32(x) ^ toint32(y)); + case EXP_BITOR: return jsP_setnumnode(node, toint32(x) | toint32(y)); + } + } + } + + return 0; +} + +/* Main entry point */ + +js_Ast *jsP_parse(js_State *J, const char *filename, const char *source) +{ + js_Ast *p; + + jsY_initlex(J, filename, source); + jsP_next(J); + J->astdepth = 0; + p = script(J, 0); + if (p) + jsP_foldconst(p); + + return p; +} + +js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body) +{ + js_Ast *p = NULL; + int line = 0; + if (params) { + jsY_initlex(J, filename, params); + jsP_next(J); + J->astdepth = 0; + p = parameters(J); + } + return EXP3(FUN, NULL, p, jsP_parse(J, filename, body)); +} diff --git a/programs/develop/kosjs/libmujs/include/jsparse.h b/programs/develop/kosjs/libmujs/jsparse.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/jsparse.h rename to programs/develop/kosjs/libmujs/jsparse.h diff --git a/programs/develop/kosjs/libmujs/jsproperty.c b/programs/develop/kosjs/libmujs/jsproperty.c new file mode 100755 index 0000000000..292e8b5d26 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsproperty.c @@ -0,0 +1,333 @@ +#include "jsi.h" +#include "jsvalue.h" + +/* + Use an AA-tree to quickly look up properties in objects: + + The level of every leaf node is one. + The level of every left child is one less than its parent. + The level of every right child is equal or one less than its parent. + The level of every right grandchild is less than its grandparent. + Every node of level greater than one has two children. + + A link where the child's level is equal to that of its parent is called a horizontal link. + Individual right horizontal links are allowed, but consecutive ones are forbidden. + Left horizontal links are forbidden. + + skew() fixes left horizontal links. + split() fixes consecutive right horizontal links. +*/ + +static js_Property sentinel = { + "", + &sentinel, &sentinel, + 0, 0, + { {0}, {0}, JS_TUNDEFINED }, + NULL, NULL +}; + +static js_Property *newproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Property *node = js_malloc(J, sizeof *node); + node->name = js_intern(J, name); + node->left = node->right = &sentinel; + node->level = 1; + node->atts = 0; + node->value.type = JS_TUNDEFINED; + node->value.u.number = 0; + node->getter = NULL; + node->setter = NULL; + ++obj->count; + ++J->gccounter; + return node; +} + +static js_Property *lookup(js_Property *node, const char *name) +{ + while (node != &sentinel) { + int c = strcmp(name, node->name); + if (c == 0) + return node; + else if (c < 0) + node = node->left; + else + node = node->right; + } + return NULL; +} + +static js_Property *skew(js_Property *node) +{ + if (node->left->level == node->level) { + js_Property *temp = node; + node = node->left; + temp->left = node->right; + node->right = temp; + } + return node; +} + +static js_Property *split(js_Property *node) +{ + if (node->right->right->level == node->level) { + js_Property *temp = node; + node = node->right; + temp->right = node->left; + node->left = temp; + ++node->level; + } + return node; +} + +static js_Property *insert(js_State *J, js_Object *obj, js_Property *node, const char *name, js_Property **result) +{ + if (node != &sentinel) { + int c = strcmp(name, node->name); + if (c < 0) + node->left = insert(J, obj, node->left, name, result); + else if (c > 0) + node->right = insert(J, obj, node->right, name, result); + else + return *result = node; + node = skew(node); + node = split(node); + return node; + } + return *result = newproperty(J, obj, name); +} + +static void freeproperty(js_State *J, js_Object *obj, js_Property *node) +{ + js_free(J, node); + --obj->count; +} + +static js_Property *delete(js_State *J, js_Object *obj, js_Property *node, const char *name) +{ + js_Property *temp, *succ; + + if (node != &sentinel) { + int c = strcmp(name, node->name); + if (c < 0) { + node->left = delete(J, obj, node->left, name); + } else if (c > 0) { + node->right = delete(J, obj, node->right, name); + } else { + if (node->left == &sentinel) { + temp = node; + node = node->right; + freeproperty(J, obj, temp); + } else if (node->right == &sentinel) { + temp = node; + node = node->left; + freeproperty(J, obj, temp); + } else { + succ = node->right; + while (succ->left != &sentinel) + succ = succ->left; + node->name = succ->name; + node->atts = succ->atts; + node->value = succ->value; + node->right = delete(J, obj, node->right, succ->name); + } + } + + if (node->left->level < node->level - 1 || + node->right->level < node->level - 1) + { + if (node->right->level > --node->level) + node->right->level = node->level; + node = skew(node); + node->right = skew(node->right); + node->right->right = skew(node->right->right); + node = split(node); + node->right = split(node->right); + } + } + return node; +} + +js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype) +{ + js_Object *obj = js_malloc(J, sizeof *obj); + memset(obj, 0, sizeof *obj); + obj->gcmark = 0; + obj->gcnext = J->gcobj; + J->gcobj = obj; + ++J->gccounter; + + obj->type = type; + obj->properties = &sentinel; + obj->prototype = prototype; + obj->extensible = 1; + return obj; +} + +js_Property *jsV_getownproperty(js_State *J, js_Object *obj, const char *name) +{ + return lookup(obj->properties, name); +} + +js_Property *jsV_getpropertyx(js_State *J, js_Object *obj, const char *name, int *own) +{ + *own = 1; + do { + js_Property *ref = lookup(obj->properties, name); + if (ref) + return ref; + obj = obj->prototype; + *own = 0; + } while (obj); + return NULL; +} + +js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name) +{ + do { + js_Property *ref = lookup(obj->properties, name); + if (ref) + return ref; + obj = obj->prototype; + } while (obj); + return NULL; +} + +static js_Property *jsV_getenumproperty(js_State *J, js_Object *obj, const char *name) +{ + do { + js_Property *ref = lookup(obj->properties, name); + if (ref && !(ref->atts & JS_DONTENUM)) + return ref; + obj = obj->prototype; + } while (obj); + return NULL; +} + +js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Property *result; + + if (!obj->extensible) { + result = lookup(obj->properties, name); + if (J->strict && !result) + js_typeerror(J, "object is non-extensible"); + return result; + } + + obj->properties = insert(J, obj, obj->properties, name, &result); + + return result; +} + +void jsV_delproperty(js_State *J, js_Object *obj, const char *name) +{ + obj->properties = delete(J, obj, obj->properties, name); +} + +/* Flatten hierarchy of enumerable properties into an iterator object */ + +static js_Iterator *itwalk(js_State *J, js_Iterator *iter, js_Property *prop, js_Object *seen) +{ + if (prop->right != &sentinel) + iter = itwalk(J, iter, prop->right, seen); + if (!(prop->atts & JS_DONTENUM)) { + if (!seen || !jsV_getenumproperty(J, seen, prop->name)) { + js_Iterator *head = js_malloc(J, sizeof *head); + head->name = prop->name; + head->next = iter; + iter = head; + } + } + if (prop->left != &sentinel) + iter = itwalk(J, iter, prop->left, seen); + return iter; +} + +static js_Iterator *itflatten(js_State *J, js_Object *obj) +{ + js_Iterator *iter = NULL; + if (obj->prototype) + iter = itflatten(J, obj->prototype); + if (obj->properties != &sentinel) + iter = itwalk(J, iter, obj->properties, obj->prototype); + return iter; +} + +js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own) +{ + char buf[32]; + int k; + js_Object *io = jsV_newobject(J, JS_CITERATOR, NULL); + io->u.iter.target = obj; + if (own) { + io->u.iter.head = NULL; + if (obj->properties != &sentinel) + io->u.iter.head = itwalk(J, io->u.iter.head, obj->properties, NULL); + } else { + io->u.iter.head = itflatten(J, obj); + } + if (obj->type == JS_CSTRING) { + js_Iterator *tail = io->u.iter.head; + if (tail) + while (tail->next) + tail = tail->next; + for (k = 0; k < obj->u.s.length; ++k) { + js_itoa(buf, k); + if (!jsV_getenumproperty(J, obj, buf)) { + js_Iterator *node = js_malloc(J, sizeof *node); + node->name = js_intern(J, js_itoa(buf, k)); + node->next = NULL; + if (!tail) + io->u.iter.head = tail = node; + else { + tail->next = node; + tail = node; + } + } + } + } + return io; +} + +const char *jsV_nextiterator(js_State *J, js_Object *io) +{ + int k; + if (io->type != JS_CITERATOR) + js_typeerror(J, "not an iterator"); + while (io->u.iter.head) { + js_Iterator *next = io->u.iter.head->next; + const char *name = io->u.iter.head->name; + js_free(J, io->u.iter.head); + io->u.iter.head = next; + if (jsV_getproperty(J, io->u.iter.target, name)) + return name; + if (io->u.iter.target->type == JS_CSTRING) + if (js_isarrayindex(J, name, &k) && k < io->u.iter.target->u.s.length) + return name; + } + return NULL; +} + +/* Walk all the properties and delete them one by one for arrays */ + +void jsV_resizearray(js_State *J, js_Object *obj, int newlen) +{ + char buf[32]; + const char *s; + int k; + if (newlen < obj->u.a.length) { + if (obj->u.a.length > obj->count * 2) { + js_Object *it = jsV_newiterator(J, obj, 1); + while ((s = jsV_nextiterator(J, it))) { + k = jsV_numbertointeger(jsV_stringtonumber(J, s)); + if (k >= newlen && !strcmp(s, jsV_numbertostring(J, buf, k))) + jsV_delproperty(J, obj, s); + } + } else { + for (k = newlen; k < obj->u.a.length; ++k) { + jsV_delproperty(J, obj, js_itoa(buf, k)); + } + } + } + obj->u.a.length = newlen; +} diff --git a/programs/develop/kosjs/libmujs/jsregexp.c b/programs/develop/kosjs/libmujs/jsregexp.c new file mode 100755 index 0000000000..98b2a869c2 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsregexp.c @@ -0,0 +1,205 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" +#include "regexp.h" + +void js_newregexp(js_State *J, const char *pattern, int flags) +{ + const char *error; + js_Object *obj; + Reprog *prog; + int opts; + + obj = jsV_newobject(J, JS_CREGEXP, J->RegExp_prototype); + + opts = 0; + if (flags & JS_REGEXP_I) opts |= REG_ICASE; + if (flags & JS_REGEXP_M) opts |= REG_NEWLINE; + + prog = js_regcompx(J->alloc, J->actx, pattern, opts, &error); + if (!prog) + js_syntaxerror(J, "regular expression: %s", error); + + obj->u.r.prog = prog; + obj->u.r.source = js_strdup(J, pattern); + obj->u.r.flags = flags; + obj->u.r.last = 0; + js_pushobject(J, obj); +} + +void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text) +{ + int result; + int i; + int opts; + Resub m; + + opts = 0; + if (re->flags & JS_REGEXP_G) { + if (re->last > strlen(text)) { + re->last = 0; + js_pushnull(J); + return; + } + if (re->last > 0) { + text += re->last; + opts |= REG_NOTBOL; + } + } + + result = js_regexec(re->prog, text, &m, opts); + if (result < 0) + js_error(J, "regexec failed"); + if (result == 0) { + js_newarray(J); + js_pushstring(J, text); + js_setproperty(J, -2, "input"); + js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp)); + js_setproperty(J, -2, "index"); + for (i = 0; i < m.nsub; ++i) { + js_pushlstring(J, m.sub[i].sp, m.sub[i].ep - m.sub[i].sp); + js_setindex(J, -2, i); + } + if (re->flags & JS_REGEXP_G) + re->last = re->last + (m.sub[0].ep - text); + return; + } + + if (re->flags & JS_REGEXP_G) + re->last = 0; + + js_pushnull(J); +} + +static void Rp_test(js_State *J) +{ + js_Regexp *re; + const char *text; + int result; + int opts; + Resub m; + + re = js_toregexp(J, 0); + text = js_tostring(J, 1); + + opts = 0; + if (re->flags & JS_REGEXP_G) { + if (re->last > strlen(text)) { + re->last = 0; + js_pushboolean(J, 0); + return; + } + if (re->last > 0) { + text += re->last; + opts |= REG_NOTBOL; + } + } + + result = js_regexec(re->prog, text, &m, opts); + if (result < 0) + js_error(J, "regexec failed"); + if (result == 0) { + if (re->flags & JS_REGEXP_G) + re->last = re->last + (m.sub[0].ep - text); + js_pushboolean(J, 1); + return; + } + + if (re->flags & JS_REGEXP_G) + re->last = 0; + + js_pushboolean(J, 0); +} + +static void jsB_new_RegExp(js_State *J) +{ + js_Regexp *old; + const char *pattern; + int flags; + + if (js_isregexp(J, 1)) { + if (js_isdefined(J, 2)) + js_typeerror(J, "cannot supply flags when creating one RegExp from another"); + old = js_toregexp(J, 1); + pattern = old->source; + flags = old->flags; + } else if (js_isundefined(J, 1)) { + pattern = "(?:)"; + flags = 0; + } else { + pattern = js_tostring(J, 1); + flags = 0; + } + + if (strlen(pattern) == 0) + pattern = "(?:)"; + + if (js_isdefined(J, 2)) { + const char *s = js_tostring(J, 2); + int g = 0, i = 0, m = 0; + while (*s) { + if (*s == 'g') ++g; + else if (*s == 'i') ++i; + else if (*s == 'm') ++m; + else js_syntaxerror(J, "invalid regular expression flag: '%c'", *s); + ++s; + } + if (g > 1) js_syntaxerror(J, "invalid regular expression flag: 'g'"); + if (i > 1) js_syntaxerror(J, "invalid regular expression flag: 'i'"); + if (m > 1) js_syntaxerror(J, "invalid regular expression flag: 'm'"); + if (g) flags |= JS_REGEXP_G; + if (i) flags |= JS_REGEXP_I; + if (m) flags |= JS_REGEXP_M; + } + + js_newregexp(J, pattern, flags); +} + +static void jsB_RegExp(js_State *J) +{ + if (js_isregexp(J, 1)) + return; + jsB_new_RegExp(J); +} + +static void Rp_toString(js_State *J) +{ + js_Regexp *re; + char *out; + + re = js_toregexp(J, 0); + + out = js_malloc(J, strlen(re->source) + 6); /* extra space for //gim */ + strcpy(out, "/"); + strcat(out, re->source); + strcat(out, "/"); + if (re->flags & JS_REGEXP_G) strcat(out, "g"); + if (re->flags & JS_REGEXP_I) strcat(out, "i"); + if (re->flags & JS_REGEXP_M) strcat(out, "m"); + + if (js_try(J)) { + js_free(J, out); + js_throw(J); + } + js_pop(J, 0); + js_pushstring(J, out); + js_endtry(J); + js_free(J, out); +} + +static void Rp_exec(js_State *J) +{ + js_RegExp_prototype_exec(J, js_toregexp(J, 0), js_tostring(J, 1)); +} + +void jsB_initregexp(js_State *J) +{ + js_pushobject(J, J->RegExp_prototype); + { + jsB_propf(J, "RegExp.prototype.toString", Rp_toString, 0); + jsB_propf(J, "RegExp.prototype.test", Rp_test, 0); + jsB_propf(J, "RegExp.prototype.exec", Rp_exec, 0); + } + js_newcconstructor(J, jsB_RegExp, jsB_new_RegExp, "RegExp", 1); + js_defglobal(J, "RegExp", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsrepr.c b/programs/develop/kosjs/libmujs/jsrepr.c new file mode 100755 index 0000000000..9074f2a019 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsrepr.c @@ -0,0 +1,289 @@ +#include "jsi.h" +#include "jslex.h" +#include "jsvalue.h" +#include "jsbuiltin.h" +#include "jscompile.h" +#include "utf.h" + +static void reprvalue(js_State *J, js_Buffer **sb); + +static void reprnum(js_State *J, js_Buffer **sb, double n) +{ + char buf[40]; + if (n == 0 && signbit(n)) + js_puts(J, sb, "-0"); + else + js_puts(J, sb, jsV_numbertostring(J, buf, n)); +} + +static void reprstr(js_State *J, js_Buffer **sb, const char *s) +{ + static const char *HEX = "0123456789ABCDEF"; + int i, n; + Rune c; + js_putc(J, sb, '"'); + while (*s) { + n = chartorune(&c, s); + switch (c) { + case '"': js_puts(J, sb, "\\\""); break; + case '\\': js_puts(J, sb, "\\\\"); break; + case '\b': js_puts(J, sb, "\\b"); break; + case '\f': js_puts(J, sb, "\\f"); break; + case '\n': js_puts(J, sb, "\\n"); break; + case '\r': js_puts(J, sb, "\\r"); break; + case '\t': js_puts(J, sb, "\\t"); break; + default: + if (c < ' ') { + js_putc(J, sb, '\\'); + js_putc(J, sb, 'x'); + js_putc(J, sb, HEX[(c>>4)&15]); + js_putc(J, sb, HEX[c&15]); + } else if (c < 128) { + js_putc(J, sb, c); + } else if (c < 0x10000) { + js_putc(J, sb, '\\'); + js_putc(J, sb, 'u'); + js_putc(J, sb, HEX[(c>>12)&15]); + js_putc(J, sb, HEX[(c>>8)&15]); + js_putc(J, sb, HEX[(c>>4)&15]); + js_putc(J, sb, HEX[c&15]); + } else { + for (i = 0; i < n; ++i) + js_putc(J, sb, s[i]); + } + break; + } + s += n; + } + js_putc(J, sb, '"'); +} + +#ifndef isalpha +#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) +#endif +#ifndef isdigit +#define isdigit(c) (c >= '0' && c <= '9') +#endif + +static void reprident(js_State *J, js_Buffer **sb, const char *name) +{ + const char *p = name; + if (isdigit(*p)) + while (isdigit(*p)) + ++p; + else if (isalpha(*p) || *p == '_') + while (isdigit(*p) || isalpha(*p) || *p == '_') + ++p; + if (p > name && *p == 0) + js_puts(J, sb, name); + else + reprstr(J, sb, name); +} + +static void reprobject(js_State *J, js_Buffer **sb) +{ + const char *key; + int i, n; + + n = js_gettop(J) - 1; + for (i = 0; i < n; ++i) { + if (js_isobject(J, i)) { + if (js_toobject(J, i) == js_toobject(J, -1)) { + js_puts(J, sb, "{}"); + return; + } + } + } + + n = 0; + js_putc(J, sb, '{'); + js_pushiterator(J, -1, 1); + while ((key = js_nextiterator(J, -1))) { + if (n++ > 0) + js_puts(J, sb, ", "); + reprident(J, sb, key); + js_puts(J, sb, ": "); + js_getproperty(J, -2, key); + reprvalue(J, sb); + js_pop(J, 1); + } + js_pop(J, 1); + js_putc(J, sb, '}'); +} + +static void reprarray(js_State *J, js_Buffer **sb) +{ + int n, i; + + n = js_gettop(J) - 1; + for (i = 0; i < n; ++i) { + if (js_isobject(J, i)) { + if (js_toobject(J, i) == js_toobject(J, -1)) { + js_puts(J, sb, "[]"); + return; + } + } + } + + js_putc(J, sb, '['); + n = js_getlength(J, -1); + for (i = 0; i < n; ++i) { + if (i > 0) + js_puts(J, sb, ", "); + if (js_hasindex(J, -1, i)) { + reprvalue(J, sb); + js_pop(J, 1); + } + } + js_putc(J, sb, ']'); +} + +static void reprfun(js_State *J, js_Buffer **sb, js_Function *fun) +{ + int i; + js_puts(J, sb, "function "); + js_puts(J, sb, fun->name); + js_putc(J, sb, '('); + for (i = 0; i < fun->numparams; ++i) { + if (i > 0) + js_puts(J, sb, ", "); + js_puts(J, sb, fun->vartab[i]); + } + js_puts(J, sb, ") { [byte code] }"); +} + +static void reprvalue(js_State *J, js_Buffer **sb) +{ + if (js_isundefined(J, -1)) + js_puts(J, sb, "undefined"); + else if (js_isnull(J, -1)) + js_puts(J, sb, "null"); + else if (js_isboolean(J, -1)) + js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false"); + else if (js_isnumber(J, -1)) + reprnum(J, sb, js_tonumber(J, -1)); + else if (js_isstring(J, -1)) + reprstr(J, sb, js_tostring(J, -1)); + else if (js_isobject(J, -1)) { + js_Object *obj = js_toobject(J, -1); + switch (obj->type) { + default: + reprobject(J, sb); + break; + case JS_CARRAY: + reprarray(J, sb); + break; + case JS_CFUNCTION: + case JS_CSCRIPT: + case JS_CEVAL: + reprfun(J, sb, obj->u.f.function); + break; + case JS_CCFUNCTION: + js_puts(J, sb, "function "); + js_puts(J, sb, obj->u.c.name); + js_puts(J, sb, "() { [native code] }"); + break; + case JS_CBOOLEAN: + js_puts(J, sb, "(new Boolean("); + js_puts(J, sb, obj->u.boolean ? "true" : "false"); + js_puts(J, sb, "))"); + break; + case JS_CNUMBER: + js_puts(J, sb, "(new Number("); + reprnum(J, sb, obj->u.number); + js_puts(J, sb, "))"); + break; + case JS_CSTRING: + js_puts(J, sb, "(new String("); + reprstr(J, sb, obj->u.s.string); + js_puts(J, sb, "))"); + break; + case JS_CREGEXP: + js_putc(J, sb, '/'); + js_puts(J, sb, obj->u.r.source); + js_putc(J, sb, '/'); + if (obj->u.r.flags & JS_REGEXP_G) js_putc(J, sb, 'g'); + if (obj->u.r.flags & JS_REGEXP_I) js_putc(J, sb, 'i'); + if (obj->u.r.flags & JS_REGEXP_M) js_putc(J, sb, 'm'); + break; + case JS_CDATE: + { + char buf[40]; + js_puts(J, sb, "(new Date("); + js_puts(J, sb, jsV_numbertostring(J, buf, obj->u.number)); + js_puts(J, sb, "))"); + } + break; + case JS_CERROR: + js_puts(J, sb, "(new "); + js_getproperty(J, -1, "name"); + js_puts(J, sb, js_tostring(J, -1)); + js_pop(J, 1); + js_putc(J, sb, '('); + js_getproperty(J, -1, "message"); + reprstr(J, sb, js_tostring(J, -1)); + js_pop(J, 1); + js_puts(J, sb, "))"); + break; + case JS_CMATH: + js_puts(J, sb, "Math"); + break; + case JS_CJSON: + js_puts(J, sb, "JSON"); + break; + case JS_CITERATOR: + js_puts(J, sb, "[iterator "); + break; + case JS_CUSERDATA: + js_puts(J, sb, "[userdata "); + js_puts(J, sb, obj->u.user.tag); + js_putc(J, sb, ']'); + break; + } + } +} + +void js_repr(js_State *J, int idx) +{ + js_Buffer *sb = NULL; + int savebot; + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + + js_copy(J, idx); + + savebot = J->bot; + J->bot = J->top - 1; + reprvalue(J, &sb); + J->bot = savebot; + + js_pop(J, 1); + + js_putc(J, &sb, 0); + js_pushstring(J, sb ? sb->s : "undefined"); + + js_endtry(J); + js_free(J, sb); +} + +const char *js_torepr(js_State *J, int idx) +{ + js_repr(J, idx); + js_replace(J, idx < 0 ? idx-1 : idx); + return js_tostring(J, idx); +} + +const char *js_tryrepr(js_State *J, int idx, const char *error) +{ + const char *s; + if (js_try(J)) { + js_pop(J, 1); + return error; + } + s = js_torepr(J, idx); + js_endtry(J); + return s; +} diff --git a/programs/develop/kosjs/libmujs/jsrun.c b/programs/develop/kosjs/libmujs/jsrun.c new file mode 100755 index 0000000000..58eaa346cf --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsrun.c @@ -0,0 +1,1811 @@ +#include "jsi.h" +#include "jscompile.h" +#include "jsvalue.h" +#include "jsrun.h" + +#include "utf.h" + +static void jsR_run(js_State *J, js_Function *F); + +/* Push values on stack */ + +#define STACK (J->stack) +#define TOP (J->top) +#define BOT (J->bot) + +static void js_stackoverflow(js_State *J) +{ + STACK[TOP].type = JS_TLITSTR; + STACK[TOP].u.litstr = "stack overflow"; + ++TOP; + js_throw(J); +} + +static void js_outofmemory(js_State *J) +{ + STACK[TOP].type = JS_TLITSTR; + STACK[TOP].u.litstr = "out of memory"; + ++TOP; + js_throw(J); +} + +void *js_malloc(js_State *J, int size) +{ + void *ptr = J->alloc(J->actx, NULL, size); + if (!ptr) + js_outofmemory(J); + return ptr; +} + +void *js_realloc(js_State *J, void *ptr, int size) +{ + ptr = J->alloc(J->actx, ptr, size); + if (!ptr) + js_outofmemory(J); + return ptr; +} + +char *js_strdup(js_State *J, const char *s) +{ + int n = strlen(s) + 1; + char *p = js_malloc(J, n); + memcpy(p, s, n); + return p; +} + +void js_free(js_State *J, void *ptr) +{ + J->alloc(J->actx, ptr, 0); +} + +js_String *jsV_newmemstring(js_State *J, const char *s, int n) +{ + js_String *v = js_malloc(J, soffsetof(js_String, p) + n + 1); + memcpy(v->p, s, n); + v->p[n] = 0; + v->gcmark = 0; + v->gcnext = J->gcstr; + J->gcstr = v; + ++J->gccounter; + return v; +} + +#define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE) js_stackoverflow(J) + +void js_pushvalue(js_State *J, js_Value v) +{ + CHECKSTACK(1); + STACK[TOP] = v; + ++TOP; +} + +void js_pushundefined(js_State *J) +{ + CHECKSTACK(1); + STACK[TOP].type = JS_TUNDEFINED; + ++TOP; +} + +void js_pushnull(js_State *J) +{ + CHECKSTACK(1); + STACK[TOP].type = JS_TNULL; + ++TOP; +} + +void js_pushboolean(js_State *J, int v) +{ + CHECKSTACK(1); + STACK[TOP].type = JS_TBOOLEAN; + STACK[TOP].u.boolean = !!v; + ++TOP; +} + +void js_pushnumber(js_State *J, double v) +{ + CHECKSTACK(1); + STACK[TOP].type = JS_TNUMBER; + STACK[TOP].u.number = v; + ++TOP; +} + +void js_pushstring(js_State *J, const char *v) +{ + int n = strlen(v); + CHECKSTACK(1); + if (n <= soffsetof(js_Value, type)) { + char *s = STACK[TOP].u.shrstr; + while (n--) *s++ = *v++; + *s = 0; + STACK[TOP].type = JS_TSHRSTR; + } else { + STACK[TOP].type = JS_TMEMSTR; + STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); + } + ++TOP; +} + +void js_pushlstring(js_State *J, const char *v, int n) +{ + CHECKSTACK(1); + if (n <= soffsetof(js_Value, type)) { + char *s = STACK[TOP].u.shrstr; + while (n--) *s++ = *v++; + *s = 0; + STACK[TOP].type = JS_TSHRSTR; + } else { + STACK[TOP].type = JS_TMEMSTR; + STACK[TOP].u.memstr = jsV_newmemstring(J, v, n); + } + ++TOP; +} + +void js_pushliteral(js_State *J, const char *v) +{ + CHECKSTACK(1); + STACK[TOP].type = JS_TLITSTR; + STACK[TOP].u.litstr = v; + ++TOP; +} + +void js_pushobject(js_State *J, js_Object *v) +{ + CHECKSTACK(1); + STACK[TOP].type = JS_TOBJECT; + STACK[TOP].u.object = v; + ++TOP; +} + +void js_pushglobal(js_State *J) +{ + js_pushobject(J, J->G); +} + +void js_currentfunction(js_State *J) +{ + CHECKSTACK(1); + STACK[TOP] = STACK[BOT-1]; + ++TOP; +} + +/* Read values from stack */ + +static js_Value *stackidx(js_State *J, int idx) +{ + static js_Value undefined = { {0}, {0}, JS_TUNDEFINED }; + idx = idx < 0 ? TOP + idx : BOT + idx; + if (idx < 0 || idx >= TOP) + return &undefined; + return STACK + idx; +} + +js_Value *js_tovalue(js_State *J, int idx) +{ + return stackidx(J, idx); +} + +int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TUNDEFINED; } +int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TUNDEFINED; } +int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNULL; } +int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TBOOLEAN; } +int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TNUMBER; } +int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; } +int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->type != JS_TOBJECT; } +int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->type == JS_TOBJECT; } +int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->type != JS_TUNDEFINED && v->type != JS_TNULL; } + +int js_iscallable(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + if (v->type == JS_TOBJECT) + return v->u.object->type == JS_CFUNCTION || + v->u.object->type == JS_CSCRIPT || + v->u.object->type == JS_CEVAL || + v->u.object->type == JS_CCFUNCTION; + return 0; +} + +int js_isarray(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + return v->type == JS_TOBJECT && v->u.object->type == JS_CARRAY; +} + +int js_isregexp(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + return v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP; +} + +int js_isuserdata(js_State *J, int idx, const char *tag) +{ + js_Value *v = stackidx(J, idx); + if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) + return !strcmp(tag, v->u.object->u.user.tag); + return 0; +} + +int js_iserror(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + return v->type == JS_TOBJECT && v->u.object->type == JS_CERROR; +} + +const char *js_typeof(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + switch (v->type) { + default: + case JS_TSHRSTR: return "string"; + case JS_TUNDEFINED: return "undefined"; + case JS_TNULL: return "object"; + case JS_TBOOLEAN: return "boolean"; + case JS_TNUMBER: return "number"; + case JS_TLITSTR: return "string"; + case JS_TMEMSTR: return "string"; + case JS_TOBJECT: + if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) + return "function"; + return "object"; + } +} + +int js_toboolean(js_State *J, int idx) +{ + return jsV_toboolean(J, stackidx(J, idx)); +} + +double js_tonumber(js_State *J, int idx) +{ + return jsV_tonumber(J, stackidx(J, idx)); +} + +int js_tointeger(js_State *J, int idx) +{ + return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx))); +} + +int js_toint32(js_State *J, int idx) +{ + return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx))); +} + +unsigned int js_touint32(js_State *J, int idx) +{ + return jsV_numbertouint32(jsV_tonumber(J, stackidx(J, idx))); +} + +short js_toint16(js_State *J, int idx) +{ + return jsV_numbertoint16(jsV_tonumber(J, stackidx(J, idx))); +} + +unsigned short js_touint16(js_State *J, int idx) +{ + return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx))); +} + +const char *js_tostring(js_State *J, int idx) +{ + return jsV_tostring(J, stackidx(J, idx)); +} + +js_Object *js_toobject(js_State *J, int idx) +{ + return jsV_toobject(J, stackidx(J, idx)); +} + +void js_toprimitive(js_State *J, int idx, int hint) +{ + jsV_toprimitive(J, stackidx(J, idx), hint); +} + +js_Regexp *js_toregexp(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + if (v->type == JS_TOBJECT && v->u.object->type == JS_CREGEXP) + return &v->u.object->u.r; + js_typeerror(J, "not a regexp"); +} + +void *js_touserdata(js_State *J, int idx, const char *tag) +{ + js_Value *v = stackidx(J, idx); + if (v->type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA) + if (!strcmp(tag, v->u.object->u.user.tag)) + return v->u.object->u.user.data; + js_typeerror(J, "not a %s", tag); +} + +static js_Object *jsR_tofunction(js_State *J, int idx) +{ + js_Value *v = stackidx(J, idx); + if (v->type == JS_TUNDEFINED || v->type == JS_TNULL) + return NULL; + if (v->type == JS_TOBJECT) + if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION) + return v->u.object; + js_typeerror(J, "not a function"); +} + +/* Stack manipulation */ + +int js_gettop(js_State *J) +{ + return TOP - BOT; +} + +void js_pop(js_State *J, int n) +{ + TOP -= n; + if (TOP < BOT) { + TOP = BOT; + js_error(J, "stack underflow!"); + } +} + +void js_remove(js_State *J, int idx) +{ + idx = idx < 0 ? TOP + idx : BOT + idx; + if (idx < BOT || idx >= TOP) + js_error(J, "stack error!"); + for (;idx < TOP - 1; ++idx) + STACK[idx] = STACK[idx+1]; + --TOP; +} + +void js_insert(js_State *J, int idx) +{ + js_error(J, "not implemented yet"); +} + +void js_replace(js_State* J, int idx) +{ + idx = idx < 0 ? TOP + idx : BOT + idx; + if (idx < BOT || idx >= TOP) + js_error(J, "stack error!"); + STACK[idx] = STACK[--TOP]; +} + +void js_copy(js_State *J, int idx) +{ + CHECKSTACK(1); + STACK[TOP] = *stackidx(J, idx); + ++TOP; +} + +void js_dup(js_State *J) +{ + CHECKSTACK(1); + STACK[TOP] = STACK[TOP-1]; + ++TOP; +} + +void js_dup2(js_State *J) +{ + CHECKSTACK(2); + STACK[TOP] = STACK[TOP-2]; + STACK[TOP+1] = STACK[TOP-1]; + TOP += 2; +} + +void js_rot2(js_State *J) +{ + /* A B -> B A */ + js_Value tmp = STACK[TOP-1]; /* A B (B) */ + STACK[TOP-1] = STACK[TOP-2]; /* A A */ + STACK[TOP-2] = tmp; /* B A */ +} + +void js_rot3(js_State *J) +{ + /* A B C -> C A B */ + js_Value tmp = STACK[TOP-1]; /* A B C (C) */ + STACK[TOP-1] = STACK[TOP-2]; /* A B B */ + STACK[TOP-2] = STACK[TOP-3]; /* A A B */ + STACK[TOP-3] = tmp; /* C A B */ +} + +void js_rot4(js_State *J) +{ + /* A B C D -> D A B C */ + js_Value tmp = STACK[TOP-1]; /* A B C D (D) */ + STACK[TOP-1] = STACK[TOP-2]; /* A B C C */ + STACK[TOP-2] = STACK[TOP-3]; /* A B B C */ + STACK[TOP-3] = STACK[TOP-4]; /* A A B C */ + STACK[TOP-4] = tmp; /* D A B C */ +} + +void js_rot2pop1(js_State *J) +{ + /* A B -> B */ + STACK[TOP-2] = STACK[TOP-1]; + --TOP; +} + +void js_rot3pop2(js_State *J) +{ + /* A B C -> C */ + STACK[TOP-3] = STACK[TOP-1]; + TOP -= 2; +} + +void js_rot(js_State *J, int n) +{ + int i; + js_Value tmp = STACK[TOP-1]; + for (i = 1; i < n; ++i) + STACK[TOP-i] = STACK[TOP-i-1]; + STACK[TOP-i] = tmp; +} + +/* Property access that takes care of attributes and getters/setters */ + +int js_isarrayindex(js_State *J, const char *p, int *idx) +{ + int n = 0; + + /* check for empty string */ + if (p[0] == 0) + return 0; + + /* check for '0' and integers with leading zero */ + if (p[0] == '0') + return (p[1] == 0) ? *idx = 0, 1 : 0; + + while (*p) { + int c = *p++; + if (c >= '0' && c <= '9') { + if (n >= INT_MAX / 10) + return 0; + n = n * 10 + (c - '0'); + } else { + return 0; + } + } + return *idx = n, 1; +} + +static void js_pushrune(js_State *J, Rune rune) +{ + char buf[UTFmax + 1]; + if (rune >= 0) { + buf[runetochar(buf, &rune)] = 0; + js_pushstring(J, buf); + } else { + js_pushundefined(J); + } +} + +static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Property *ref; + int k; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) { + js_pushnumber(J, obj->u.a.length); + return 1; + } + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) { + js_pushnumber(J, obj->u.s.length); + return 1; + } + if (js_isarrayindex(J, name, &k)) { + if (k >= 0 && k < obj->u.s.length) { + js_pushrune(J, js_runeat(J, obj->u.s.string, k)); + return 1; + } + } + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) { + js_pushliteral(J, obj->u.r.source); + return 1; + } + if (!strcmp(name, "global")) { + js_pushboolean(J, obj->u.r.flags & JS_REGEXP_G); + return 1; + } + if (!strcmp(name, "ignoreCase")) { + js_pushboolean(J, obj->u.r.flags & JS_REGEXP_I); + return 1; + } + if (!strcmp(name, "multiline")) { + js_pushboolean(J, obj->u.r.flags & JS_REGEXP_M); + return 1; + } + if (!strcmp(name, "lastIndex")) { + js_pushnumber(J, obj->u.r.last); + return 1; + } + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.has && obj->u.user.has(J, obj->u.user.data, name)) + return 1; + } + + ref = jsV_getproperty(J, obj, name); + if (ref) { + if (ref->getter) { + js_pushobject(J, ref->getter); + js_pushobject(J, obj); + js_call(J, 0); + } else { + js_pushvalue(J, ref->value); + } + return 1; + } + + return 0; +} + +static void jsR_getproperty(js_State *J, js_Object *obj, const char *name) +{ + if (!jsR_hasproperty(J, obj, name)) + js_pushundefined(J); +} + +static void jsR_setproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Value *value = stackidx(J, -1); + js_Property *ref; + int k; + int own; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) { + double rawlen = jsV_tonumber(J, value); + int newlen = jsV_numbertointeger(rawlen); + if (newlen != rawlen || newlen < 0) + js_rangeerror(J, "invalid array length"); + jsV_resizearray(J, obj, newlen); + return; + } + if (js_isarrayindex(J, name, &k)) + if (k >= obj->u.a.length) + obj->u.a.length = k + 1; + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) + goto readonly; + if (js_isarrayindex(J, name, &k)) + if (k >= 0 && k < obj->u.s.length) + goto readonly; + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) goto readonly; + if (!strcmp(name, "global")) goto readonly; + if (!strcmp(name, "ignoreCase")) goto readonly; + if (!strcmp(name, "multiline")) goto readonly; + if (!strcmp(name, "lastIndex")) { + obj->u.r.last = jsV_tointeger(J, value); + return; + } + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name)) + return; + } + + /* First try to find a setter in prototype chain */ + ref = jsV_getpropertyx(J, obj, name, &own); + if (ref) { + if (ref->setter) { + js_pushobject(J, ref->setter); + js_pushobject(J, obj); + js_pushvalue(J, *value); + js_call(J, 1); + js_pop(J, 1); + return; + } else { + if (J->strict) + if (ref->getter) + js_typeerror(J, "setting property '%s' that only has a getter", name); + if (ref->atts & JS_READONLY) + goto readonly; + } + } + + /* Property not found on this object, so create one */ + if (!ref || !own) + ref = jsV_setproperty(J, obj, name); + + if (ref) { + if (!(ref->atts & JS_READONLY)) + ref->value = *value; + else + goto readonly; + } + + return; + +readonly: + if (J->strict) + js_typeerror(J, "'%s' is read-only", name); +} + +static void jsR_defproperty(js_State *J, js_Object *obj, const char *name, + int atts, js_Value *value, js_Object *getter, js_Object *setter) +{ + js_Property *ref; + int k; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) + goto readonly; + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) + goto readonly; + if (js_isarrayindex(J, name, &k)) + if (k >= 0 && k < obj->u.s.length) + goto readonly; + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) goto readonly; + if (!strcmp(name, "global")) goto readonly; + if (!strcmp(name, "ignoreCase")) goto readonly; + if (!strcmp(name, "multiline")) goto readonly; + if (!strcmp(name, "lastIndex")) goto readonly; + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name)) + return; + } + + ref = jsV_setproperty(J, obj, name); + if (ref) { + if (value) { + if (!(ref->atts & JS_READONLY)) + ref->value = *value; + else if (J->strict) + js_typeerror(J, "'%s' is read-only", name); + } + if (getter) { + if (!(ref->atts & JS_DONTCONF)) + ref->getter = getter; + else if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + } + if (setter) { + if (!(ref->atts & JS_DONTCONF)) + ref->setter = setter; + else if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + } + ref->atts |= atts; + } + + return; + +readonly: + if (J->strict) + js_typeerror(J, "'%s' is read-only or non-configurable", name); +} + +static int jsR_delproperty(js_State *J, js_Object *obj, const char *name) +{ + js_Property *ref; + int k; + + if (obj->type == JS_CARRAY) { + if (!strcmp(name, "length")) + goto dontconf; + } + + else if (obj->type == JS_CSTRING) { + if (!strcmp(name, "length")) + goto dontconf; + if (js_isarrayindex(J, name, &k)) + if (k >= 0 && k < obj->u.s.length) + goto dontconf; + } + + else if (obj->type == JS_CREGEXP) { + if (!strcmp(name, "source")) goto dontconf; + if (!strcmp(name, "global")) goto dontconf; + if (!strcmp(name, "ignoreCase")) goto dontconf; + if (!strcmp(name, "multiline")) goto dontconf; + if (!strcmp(name, "lastIndex")) goto dontconf; + } + + else if (obj->type == JS_CUSERDATA) { + if (obj->u.user.delete && obj->u.user.delete(J, obj->u.user.data, name)) + return 1; + } + + ref = jsV_getownproperty(J, obj, name); + if (ref) { + if (ref->atts & JS_DONTCONF) + goto dontconf; + jsV_delproperty(J, obj, name); + } + return 1; + +dontconf: + if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + return 0; +} + +/* Registry, global and object property accessors */ + +const char *js_ref(js_State *J) +{ + js_Value *v = stackidx(J, -1); + const char *s; + char buf[32]; + switch (v->type) { + case JS_TUNDEFINED: s = "_Undefined"; break; + case JS_TNULL: s = "_Null"; break; + case JS_TBOOLEAN: + s = v->u.boolean ? "_True" : "_False"; + break; + case JS_TOBJECT: + sprintf(buf, "%p", (void*)v->u.object); + s = js_intern(J, buf); + break; + default: + sprintf(buf, "%d", J->nextref++); + s = js_intern(J, buf); + break; + } + js_setregistry(J, s); + return s; +} + +void js_unref(js_State *J, const char *ref) +{ + js_delregistry(J, ref); +} + +void js_getregistry(js_State *J, const char *name) +{ + jsR_getproperty(J, J->R, name); +} + +void js_setregistry(js_State *J, const char *name) +{ + jsR_setproperty(J, J->R, name); + js_pop(J, 1); +} + +void js_delregistry(js_State *J, const char *name) +{ + jsR_delproperty(J, J->R, name); +} + +void js_getglobal(js_State *J, const char *name) +{ + jsR_getproperty(J, J->G, name); +} + +void js_setglobal(js_State *J, const char *name) +{ + jsR_setproperty(J, J->G, name); + js_pop(J, 1); +} + +void js_defglobal(js_State *J, const char *name, int atts) +{ + jsR_defproperty(J, J->G, name, atts, stackidx(J, -1), NULL, NULL); + js_pop(J, 1); +} + +void js_delglobal(js_State *J, const char *name) +{ + jsR_delproperty(J, J->G, name); +} + +void js_getproperty(js_State *J, int idx, const char *name) +{ + jsR_getproperty(J, js_toobject(J, idx), name); +} + +void js_setproperty(js_State *J, int idx, const char *name) +{ + jsR_setproperty(J, js_toobject(J, idx), name); + js_pop(J, 1); +} + +void js_defproperty(js_State *J, int idx, const char *name, int atts) +{ + jsR_defproperty(J, js_toobject(J, idx), name, atts, stackidx(J, -1), NULL, NULL); + js_pop(J, 1); +} + +void js_delproperty(js_State *J, int idx, const char *name) +{ + jsR_delproperty(J, js_toobject(J, idx), name); +} + +void js_defaccessor(js_State *J, int idx, const char *name, int atts) +{ + jsR_defproperty(J, js_toobject(J, idx), name, atts, NULL, jsR_tofunction(J, -2), jsR_tofunction(J, -1)); + js_pop(J, 2); +} + +int js_hasproperty(js_State *J, int idx, const char *name) +{ + return jsR_hasproperty(J, js_toobject(J, idx), name); +} + +/* Iterator */ + +void js_pushiterator(js_State *J, int idx, int own) +{ + js_pushobject(J, jsV_newiterator(J, js_toobject(J, idx), own)); +} + +const char *js_nextiterator(js_State *J, int idx) +{ + return jsV_nextiterator(J, js_toobject(J, idx)); +} + +/* Environment records */ + +js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer) +{ + js_Environment *E = js_malloc(J, sizeof *E); + E->gcmark = 0; + E->gcnext = J->gcenv; + J->gcenv = E; + ++J->gccounter; + + E->outer = outer; + E->variables = vars; + return E; +} + +static void js_initvar(js_State *J, const char *name, int idx) +{ + jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, stackidx(J, idx), NULL, NULL); +} + +static int js_hasvar(js_State *J, const char *name) +{ + js_Environment *E = J->E; + do { + js_Property *ref = jsV_getproperty(J, E->variables, name); + if (ref) { + if (ref->getter) { + js_pushobject(J, ref->getter); + js_pushobject(J, E->variables); + js_call(J, 0); + } else { + js_pushvalue(J, ref->value); + } + return 1; + } + E = E->outer; + } while (E); + return 0; +} + +static void js_setvar(js_State *J, const char *name) +{ + js_Environment *E = J->E; + do { + js_Property *ref = jsV_getproperty(J, E->variables, name); + if (ref) { + if (ref->setter) { + js_pushobject(J, ref->setter); + js_pushobject(J, E->variables); + js_copy(J, -3); + js_call(J, 1); + js_pop(J, 1); + return; + } + if (!(ref->atts & JS_READONLY)) + ref->value = *stackidx(J, -1); + else if (J->strict) + js_typeerror(J, "'%s' is read-only", name); + return; + } + E = E->outer; + } while (E); + if (J->strict) + js_referenceerror(J, "assignment to undeclared variable '%s'", name); + jsR_setproperty(J, J->G, name); +} + +static int js_delvar(js_State *J, const char *name) +{ + js_Environment *E = J->E; + do { + js_Property *ref = jsV_getownproperty(J, E->variables, name); + if (ref) { + if (ref->atts & JS_DONTCONF) { + if (J->strict) + js_typeerror(J, "'%s' is non-configurable", name); + return 0; + } + jsV_delproperty(J, E->variables, name); + return 1; + } + E = E->outer; + } while (E); + return jsR_delproperty(J, J->G, name); +} + +/* Function calls */ + +static void jsR_savescope(js_State *J, js_Environment *newE) +{ + if (J->envtop + 1 >= JS_ENVLIMIT) + js_stackoverflow(J); + J->envstack[J->envtop++] = J->E; + J->E = newE; +} + +static void jsR_restorescope(js_State *J) +{ + J->E = J->envstack[--J->envtop]; +} + +static void jsR_calllwfunction(js_State *J, int n, js_Function *F, js_Environment *scope) +{ + js_Value v; + int i; + + jsR_savescope(J, scope); + + if (n > F->numparams) { + js_pop(J, n - F->numparams); + n = F->numparams; + } + + for (i = n; i < F->varlen; ++i) + js_pushundefined(J); + + jsR_run(J, F); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + + jsR_restorescope(J); +} + +static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment *scope) +{ + js_Value v; + int i; + + scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope); + + jsR_savescope(J, scope); + + if (F->arguments) { + js_newarguments(J); + if (!J->strict) { + js_currentfunction(J); + js_defproperty(J, -2, "callee", JS_DONTENUM); + } + js_pushnumber(J, n); + js_defproperty(J, -2, "length", JS_DONTENUM); + for (i = 0; i < n; ++i) { + js_copy(J, i + 1); + js_setindex(J, -2, i); + } + js_initvar(J, "arguments", -1); + js_pop(J, 1); + } + + for (i = 0; i < n && i < F->numparams; ++i) + js_initvar(J, F->vartab[i], i + 1); + js_pop(J, n); + + for (; i < F->varlen; ++i) { + js_pushundefined(J); + js_initvar(J, F->vartab[i], -1); + js_pop(J, 1); + } + + jsR_run(J, F); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + + jsR_restorescope(J); +} + +static void jsR_calleval(js_State *J, int n, js_Function *F, js_Environment *scope) +{ + js_Value v; + int i; + + scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope); + + jsR_savescope(J, scope); + + /* scripts take no arguments */ + js_pop(J, n); + + for (i = 0; i < F->varlen; ++i) { + js_pushundefined(J); + js_initvar(J, F->vartab[i], -1); + js_pop(J, 1); + } + + jsR_run(J, F); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + + jsR_restorescope(J); +} + +static void jsR_callscript(js_State *J, int n, js_Function *F, js_Environment *scope) +{ + js_Value v; + int i; + + if (scope) + jsR_savescope(J, scope); + + /* scripts take no arguments */ + js_pop(J, n); + + for (i = 0; i < F->varlen; ++i) { + js_pushundefined(J); + js_initvar(J, F->vartab[i], -1); + js_pop(J, 1); + } + + jsR_run(J, F); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); + + if (scope) + jsR_restorescope(J); +} + +static void jsR_callcfunction(js_State *J, int n, int min, js_CFunction F) +{ + int i; + js_Value v; + + for (i = n; i < min; ++i) + js_pushundefined(J); + + F(J); + v = *stackidx(J, -1); + TOP = --BOT; /* clear stack */ + js_pushvalue(J, v); +} + +static void jsR_pushtrace(js_State *J, const char *name, const char *file, int line) +{ + if (J->tracetop + 1 == JS_ENVLIMIT) + js_error(J, "call stack overflow"); + ++J->tracetop; + J->trace[J->tracetop].name = name; + J->trace[J->tracetop].file = file; + J->trace[J->tracetop].line = line; +} + +void js_call(js_State *J, int n) +{ + js_Object *obj; + int savebot; + + if (!js_iscallable(J, -n-2)) + js_typeerror(J, "%s is not callable", js_typeof(J, -n-2)); + + obj = js_toobject(J, -n-2); + + savebot = BOT; + BOT = TOP - n - 1; + + if (obj->type == JS_CFUNCTION) { + jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line); + if (obj->u.f.function->lightweight) + jsR_calllwfunction(J, n, obj->u.f.function, obj->u.f.scope); + else + jsR_callfunction(J, n, obj->u.f.function, obj->u.f.scope); + --J->tracetop; + } else if (obj->type == JS_CSCRIPT) { + jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line); + jsR_callscript(J, n, obj->u.f.function, obj->u.f.scope); + --J->tracetop; + } else if (obj->type == JS_CEVAL) { + jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line); + jsR_calleval(J, n, obj->u.f.function, obj->u.f.scope); + --J->tracetop; + } else if (obj->type == JS_CCFUNCTION) { + jsR_pushtrace(J, obj->u.c.name, "native", 0); + jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.function); + --J->tracetop; + } + + BOT = savebot; +} + +void js_construct(js_State *J, int n) +{ + js_Object *obj; + js_Object *prototype; + js_Object *newobj; + + if (!js_iscallable(J, -n-1)) + js_typeerror(J, "%s is not callable", js_typeof(J, -n-1)); + + obj = js_toobject(J, -n-1); + + /* built-in constructors create their own objects, give them a 'null' this */ + if (obj->type == JS_CCFUNCTION && obj->u.c.constructor) { + int savebot = BOT; + js_pushnull(J); + if (n > 0) + js_rot(J, n + 1); + BOT = TOP - n - 1; + + jsR_pushtrace(J, obj->u.c.name, "native", 0); + jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.constructor); + --J->tracetop; + + BOT = savebot; + return; + } + + /* extract the function object's prototype property */ + js_getproperty(J, -n - 1, "prototype"); + if (js_isobject(J, -1)) + prototype = js_toobject(J, -1); + else + prototype = J->Object_prototype; + js_pop(J, 1); + + /* create a new object with above prototype, and shift it into the 'this' slot */ + newobj = jsV_newobject(J, JS_COBJECT, prototype); + js_pushobject(J, newobj); + if (n > 0) + js_rot(J, n + 1); + + /* call the function */ + js_call(J, n); + + /* if result is not an object, return the original object we created */ + if (!js_isobject(J, -1)) { + js_pop(J, 1); + js_pushobject(J, newobj); + } +} + +void js_eval(js_State *J) +{ + if (!js_isstring(J, -1)) + return; + js_loadeval(J, "(eval)", js_tostring(J, -1)); + js_rot2pop1(J); + js_copy(J, 0); /* copy 'this' */ + js_call(J, 0); +} + +int js_pconstruct(js_State *J, int n) +{ + int savetop = TOP - n - 2; + if (js_try(J)) { + /* clean up the stack to only hold the error object */ + STACK[savetop] = STACK[TOP-1]; + TOP = savetop + 1; + return 1; + } + js_construct(J, n); + js_endtry(J); + return 0; +} + +int js_pcall(js_State *J, int n) +{ + int savetop = TOP - n - 2; + if (js_try(J)) { + /* clean up the stack to only hold the error object */ + STACK[savetop] = STACK[TOP-1]; + TOP = savetop + 1; + return 1; + } + js_call(J, n); + js_endtry(J); + return 0; +} + +/* Exceptions */ + +void *js_savetrypc(js_State *J, js_Instruction *pc) +{ + if (J->trytop == JS_TRYLIMIT) + js_error(J, "try: exception stack overflow"); + J->trybuf[J->trytop].E = J->E; + J->trybuf[J->trytop].envtop = J->envtop; + J->trybuf[J->trytop].tracetop = J->tracetop; + J->trybuf[J->trytop].top = J->top; + J->trybuf[J->trytop].bot = J->bot; + J->trybuf[J->trytop].strict = J->strict; + J->trybuf[J->trytop].pc = pc; + return J->trybuf[J->trytop++].buf; +} + +void *js_savetry(js_State *J) +{ + if (J->trytop == JS_TRYLIMIT) + js_error(J, "try: exception stack overflow"); + J->trybuf[J->trytop].E = J->E; + J->trybuf[J->trytop].envtop = J->envtop; + J->trybuf[J->trytop].tracetop = J->tracetop; + J->trybuf[J->trytop].top = J->top; + J->trybuf[J->trytop].bot = J->bot; + J->trybuf[J->trytop].strict = J->strict; + J->trybuf[J->trytop].pc = NULL; + return J->trybuf[J->trytop++].buf; +} + +void js_endtry(js_State *J) +{ + if (J->trytop == 0) + js_error(J, "endtry: exception stack underflow"); + --J->trytop; +} + +void js_throw(js_State *J) +{ + if (J->trytop > 0) { + js_Value v = *stackidx(J, -1); + --J->trytop; + J->E = J->trybuf[J->trytop].E; + J->envtop = J->trybuf[J->trytop].envtop; + J->tracetop = J->trybuf[J->trytop].tracetop; + J->top = J->trybuf[J->trytop].top; + J->bot = J->trybuf[J->trytop].bot; + J->strict = J->trybuf[J->trytop].strict; + js_pushvalue(J, v); + longjmp(J->trybuf[J->trytop].buf, 1); + } + if (J->panic) + J->panic(J); + abort(); +} + +/* Main interpreter loop */ + +static void jsR_dumpstack(js_State *J) +{ + int i; + printf("stack {\n"); + for (i = 0; i < TOP; ++i) { + putchar(i == BOT ? '>' : ' '); + printf("%4d: ", i); + js_dumpvalue(J, STACK[i]); + putchar('\n'); + } + printf("}\n"); +} + +static void jsR_dumpenvironment(js_State *J, js_Environment *E, int d) +{ + printf("scope %d ", d); + js_dumpobject(J, E->variables); + if (E->outer) + jsR_dumpenvironment(J, E->outer, d+1); +} + +void js_stacktrace(js_State *J) +{ + int n; + printf("stack trace:\n"); + for (n = J->tracetop; n >= 0; --n) { + const char *name = J->trace[n].name; + const char *file = J->trace[n].file; + int line = J->trace[n].line; + if (line > 0) { + if (name[0]) + printf("\tat %s (%s:%d)\n", name, file, line); + else + printf("\tat %s:%d\n", file, line); + } else + printf("\tat %s (%s)\n", name, file); + } +} + +void js_trap(js_State *J, int pc) +{ + if (pc > 0) { + js_Function *F = STACK[BOT-1].u.object->u.f.function; + printf("trap at %d in function ", pc); + jsC_dumpfunction(J, F); + } + jsR_dumpstack(J); + jsR_dumpenvironment(J, J->E, 0); + js_stacktrace(J); +} + +static void jsR_run(js_State *J, js_Function *F) +{ + js_Function **FT = F->funtab; + double *NT = F->numtab; + const char **ST = F->strtab; + const char **VT = F->vartab-1; + int lightweight = F->lightweight; + js_Instruction *pcstart = F->code; + js_Instruction *pc = F->code; + enum js_OpCode opcode; + int offset; + int savestrict; + + const char *str; + js_Object *obj; + double x, y; + unsigned int ux, uy; + int ix, iy, okay; + int b; + + savestrict = J->strict; + J->strict = F->strict; + + while (1) { + if (J->gccounter > J->gcthresh) + js_gc(J, 0); + + J->trace[J->tracetop].line = *pc++; + + opcode = *pc++; + + switch (opcode) { + case OP_POP: js_pop(J, 1); break; + case OP_DUP: js_dup(J); break; + case OP_DUP2: js_dup2(J); break; + case OP_ROT2: js_rot2(J); break; + case OP_ROT3: js_rot3(J); break; + case OP_ROT4: js_rot4(J); break; + + case OP_INTEGER: js_pushnumber(J, *pc++ - 32768); break; + case OP_NUMBER: js_pushnumber(J, NT[*pc++]); break; + case OP_STRING: js_pushliteral(J, ST[*pc++]); break; + + case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break; + case OP_NEWOBJECT: js_newobject(J); break; + case OP_NEWARRAY: js_newarray(J); break; + case OP_NEWREGEXP: js_newregexp(J, ST[pc[0]], pc[1]); pc += 2; break; + + case OP_UNDEF: js_pushundefined(J); break; + case OP_NULL: js_pushnull(J); break; + case OP_TRUE: js_pushboolean(J, 1); break; + case OP_FALSE: js_pushboolean(J, 0); break; + + case OP_THIS: + if (J->strict) { + js_copy(J, 0); + } else { + if (js_iscoercible(J, 0)) + js_copy(J, 0); + else + js_pushglobal(J); + } + break; + + case OP_CURRENT: + js_currentfunction(J); + break; + + case OP_GETLOCAL: + if (lightweight) { + CHECKSTACK(1); + STACK[TOP++] = STACK[BOT + *pc++]; + } else { + str = VT[*pc++]; + if (!js_hasvar(J, str)) + js_referenceerror(J, "'%s' is not defined", str); + } + break; + + case OP_SETLOCAL: + if (lightweight) { + STACK[BOT + *pc++] = STACK[TOP-1]; + } else { + js_setvar(J, VT[*pc++]); + } + break; + + case OP_DELLOCAL: + if (lightweight) { + ++pc; + js_pushboolean(J, 0); + } else { + b = js_delvar(J, VT[*pc++]); + js_pushboolean(J, b); + } + break; + + case OP_GETVAR: + str = ST[*pc++]; + if (!js_hasvar(J, str)) + js_referenceerror(J, "'%s' is not defined", str); + break; + + case OP_HASVAR: + if (!js_hasvar(J, ST[*pc++])) + js_pushundefined(J); + break; + + case OP_SETVAR: + js_setvar(J, ST[*pc++]); + break; + + case OP_DELVAR: + b = js_delvar(J, ST[*pc++]); + js_pushboolean(J, b); + break; + + case OP_IN: + str = js_tostring(J, -2); + if (!js_isobject(J, -1)) + js_typeerror(J, "operand to 'in' is not an object"); + b = js_hasproperty(J, -1, str); + js_pop(J, 2 + b); + js_pushboolean(J, b); + break; + + case OP_INITPROP: + obj = js_toobject(J, -3); + str = js_tostring(J, -2); + jsR_setproperty(J, obj, str); + js_pop(J, 2); + break; + + case OP_INITGETTER: + obj = js_toobject(J, -3); + str = js_tostring(J, -2); + jsR_defproperty(J, obj, str, 0, NULL, jsR_tofunction(J, -1), NULL); + js_pop(J, 2); + break; + + case OP_INITSETTER: + obj = js_toobject(J, -3); + str = js_tostring(J, -2); + jsR_defproperty(J, obj, str, 0, NULL, NULL, jsR_tofunction(J, -1)); + js_pop(J, 2); + break; + + case OP_GETPROP: + str = js_tostring(J, -1); + obj = js_toobject(J, -2); + jsR_getproperty(J, obj, str); + js_rot3pop2(J); + break; + + case OP_GETPROP_S: + str = ST[*pc++]; + obj = js_toobject(J, -1); + jsR_getproperty(J, obj, str); + js_rot2pop1(J); + break; + + case OP_SETPROP: + str = js_tostring(J, -2); + obj = js_toobject(J, -3); + jsR_setproperty(J, obj, str); + js_rot3pop2(J); + break; + + case OP_SETPROP_S: + str = ST[*pc++]; + obj = js_toobject(J, -2); + jsR_setproperty(J, obj, str); + js_rot2pop1(J); + break; + + case OP_DELPROP: + str = js_tostring(J, -1); + obj = js_toobject(J, -2); + b = jsR_delproperty(J, obj, str); + js_pop(J, 2); + js_pushboolean(J, b); + break; + + case OP_DELPROP_S: + str = ST[*pc++]; + obj = js_toobject(J, -1); + b = jsR_delproperty(J, obj, str); + js_pop(J, 1); + js_pushboolean(J, b); + break; + + case OP_ITERATOR: + if (js_iscoercible(J, -1)) { + obj = jsV_newiterator(J, js_toobject(J, -1), 0); + js_pop(J, 1); + js_pushobject(J, obj); + } + break; + + case OP_NEXTITER: + if (js_isobject(J, -1)) { + obj = js_toobject(J, -1); + str = jsV_nextiterator(J, obj); + if (str) { + js_pushliteral(J, str); + js_pushboolean(J, 1); + } else { + js_pop(J, 1); + js_pushboolean(J, 0); + } + } else { + js_pop(J, 1); + js_pushboolean(J, 0); + } + break; + + /* Function calls */ + + case OP_EVAL: + js_eval(J); + break; + + case OP_CALL: + js_call(J, *pc++); + break; + + case OP_NEW: + js_construct(J, *pc++); + break; + + /* Unary operators */ + + case OP_TYPEOF: + str = js_typeof(J, -1); + js_pop(J, 1); + js_pushliteral(J, str); + break; + + case OP_POS: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x); + break; + + case OP_NEG: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, -x); + break; + + case OP_BITNOT: + ix = js_toint32(J, -1); + js_pop(J, 1); + js_pushnumber(J, ~ix); + break; + + case OP_LOGNOT: + b = js_toboolean(J, -1); + js_pop(J, 1); + js_pushboolean(J, !b); + break; + + case OP_INC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x + 1); + break; + + case OP_DEC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x - 1); + break; + + case OP_POSTINC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x + 1); + js_pushnumber(J, x); + break; + + case OP_POSTDEC: + x = js_tonumber(J, -1); + js_pop(J, 1); + js_pushnumber(J, x - 1); + js_pushnumber(J, x); + break; + + /* Multiplicative operators */ + + case OP_MUL: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x * y); + break; + + case OP_DIV: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x / y); + break; + + case OP_MOD: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, fmod(x, y)); + break; + + /* Additive operators */ + + case OP_ADD: + js_concat(J); + break; + + case OP_SUB: + x = js_tonumber(J, -2); + y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x - y); + break; + + /* Shift operators */ + + case OP_SHL: + ix = js_toint32(J, -2); + uy = js_touint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix << (uy & 0x1F)); + break; + + case OP_SHR: + ix = js_toint32(J, -2); + uy = js_touint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix >> (uy & 0x1F)); + break; + + case OP_USHR: + ux = js_touint32(J, -2); + uy = js_touint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ux >> (uy & 0x1F)); + break; + + /* Relational operators */ + + case OP_LT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b < 0); break; + case OP_GT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b > 0); break; + case OP_LE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b <= 0); break; + case OP_GE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b >= 0); break; + + case OP_INSTANCEOF: + b = js_instanceof(J); + js_pop(J, 2); + js_pushboolean(J, b); + break; + + /* Equality */ + + case OP_EQ: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, b); break; + case OP_NE: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, !b); break; + case OP_STRICTEQ: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, b); break; + case OP_STRICTNE: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, !b); break; + + case OP_JCASE: + offset = *pc++; + b = js_strictequal(J); + if (b) { + js_pop(J, 2); + pc = pcstart + offset; + } else { + js_pop(J, 1); + } + break; + + /* Binary bitwise operators */ + + case OP_BITAND: + ix = js_toint32(J, -2); + iy = js_toint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix & iy); + break; + + case OP_BITXOR: + ix = js_toint32(J, -2); + iy = js_toint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix ^ iy); + break; + + case OP_BITOR: + ix = js_toint32(J, -2); + iy = js_toint32(J, -1); + js_pop(J, 2); + js_pushnumber(J, ix | iy); + break; + + /* Try and Catch */ + + case OP_THROW: + js_throw(J); + + case OP_TRY: + offset = *pc++; + if (js_trypc(J, pc)) { + pc = J->trybuf[J->trytop].pc; + } else { + pc = pcstart + offset; + } + break; + + case OP_ENDTRY: + js_endtry(J); + break; + + case OP_CATCH: + str = ST[*pc++]; + obj = jsV_newobject(J, JS_COBJECT, NULL); + js_pushobject(J, obj); + js_rot2(J); + js_setproperty(J, -2, str); + J->E = jsR_newenvironment(J, obj, J->E); + js_pop(J, 1); + break; + + case OP_ENDCATCH: + J->E = J->E->outer; + break; + + /* With */ + + case OP_WITH: + obj = js_toobject(J, -1); + J->E = jsR_newenvironment(J, obj, J->E); + js_pop(J, 1); + break; + + case OP_ENDWITH: + J->E = J->E->outer; + break; + + /* Branching */ + + case OP_DEBUGGER: + js_trap(J, (int)(pc - pcstart) - 1); + break; + + case OP_JUMP: + pc = pcstart + *pc; + break; + + case OP_JTRUE: + offset = *pc++; + b = js_toboolean(J, -1); + js_pop(J, 1); + if (b) + pc = pcstart + offset; + break; + + case OP_JFALSE: + offset = *pc++; + b = js_toboolean(J, -1); + js_pop(J, 1); + if (!b) + pc = pcstart + offset; + break; + + case OP_RETURN: + J->strict = savestrict; + return; + } + } +} diff --git a/programs/develop/kosjs/libmujs/include/jsrun.h b/programs/develop/kosjs/libmujs/jsrun.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/jsrun.h rename to programs/develop/kosjs/libmujs/jsrun.h diff --git a/programs/develop/kosjs/libmujs/jsstate.c b/programs/develop/kosjs/libmujs/jsstate.c new file mode 100755 index 0000000000..55302314dd --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsstate.c @@ -0,0 +1,298 @@ +#include "jsi.h" +#include "jsparse.h" +#include "jscompile.h" +#include "jsvalue.h" +#include "jsrun.h" +#include "jsbuiltin.h" + +#include +#include + +static void *js_defaultalloc(void *actx, void *ptr, int size) +{ +#ifndef __has_feature +#define __has_feature(x) 0 +#endif +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) + if (size == 0) { + free(ptr); + return NULL; + } +#endif + return realloc(ptr, (size_t)size); +} + +static void js_defaultreport(js_State *J, const char *message) +{ + fputs(message, stderr); + fputc('\n', stderr); +} + +static void js_defaultpanic(js_State *J) +{ + js_report(J, "uncaught exception"); + /* return to javascript to abort */ +} + +int js_ploadstring(js_State *J, const char *filename, const char *source) +{ + if (js_try(J)) + return 1; + js_loadstring(J, filename, source); + js_endtry(J); + return 0; +} + +int js_ploadfile(js_State *J, const char *filename) +{ + if (js_try(J)) + return 1; + js_loadfile(J, filename); + js_endtry(J); + return 0; +} + +const char *js_trystring(js_State *J, int idx, const char *error) +{ + const char *s; + if (js_try(J)) { + js_pop(J, 1); + return error; + } + s = js_tostring(J, idx); + js_endtry(J); + return s; +} + +double js_trynumber(js_State *J, int idx, double error) +{ + double v; + if (js_try(J)) { + js_pop(J, 1); + return error; + } + v = js_tonumber(J, idx); + js_endtry(J); + return v; +} + +int js_tryinteger(js_State *J, int idx, int error) +{ + int v; + if (js_try(J)) { + js_pop(J, 1); + return error; + } + v = js_tointeger(J, idx); + js_endtry(J); + return v; +} + +int js_tryboolean(js_State *J, int idx, int error) +{ + int v; + if (js_try(J)) { + js_pop(J, 1); + return error; + } + v = js_toboolean(J, idx); + js_endtry(J); + return v; +} + +static void js_loadstringx(js_State *J, const char *filename, const char *source, int iseval) +{ + js_Ast *P; + js_Function *F; + + if (js_try(J)) { + jsP_freeparse(J); + js_throw(J); + } + + P = jsP_parse(J, filename, source); + F = jsC_compilescript(J, P, iseval ? J->strict : J->default_strict); + jsP_freeparse(J); + js_newscript(J, F, iseval ? (J->strict ? J->E : NULL) : J->GE, iseval ? JS_CEVAL : JS_CSCRIPT); + + js_endtry(J); +} + +void js_loadeval(js_State *J, const char *filename, const char *source) +{ + js_loadstringx(J, filename, source, 1); +} + +void js_loadstring(js_State *J, const char *filename, const char *source) +{ + js_loadstringx(J, filename, source, 0); +} + +void js_loadfile(js_State *J, const char *filename) +{ + FILE *f; + char *s, *p; + int n, t; + + f = fopen(filename, "rb"); + if (!f) { + js_error(J, "cannot open file '%s': %s", filename, strerror(errno)); + } + + if (fseek(f, 0, SEEK_END) < 0) { + fclose(f); + js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); + } + + n = ftell(f); + if (n < 0) { + fclose(f); + js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno)); + } + + if (fseek(f, 0, SEEK_SET) < 0) { + fclose(f); + js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno)); + } + + if (js_try(J)) { + fclose(f); + js_throw(J); + } + s = js_malloc(J, n + 1); /* add space for string terminator */ + js_endtry(J); + + t = fread(s, 1, (size_t)n, f); + if (t != n) { + js_free(J, s); + fclose(f); + js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno)); + } + + s[n] = 0; /* zero-terminate string containing file data */ + + if (js_try(J)) { + js_free(J, s); + fclose(f); + js_throw(J); + } + + /* skip first line if it starts with "#!" */ + p = s; + if (p[0] == '#' && p[1] == '!') { + p += 2; + while (*p && *p != '\n') + ++p; + } + + js_loadstring(J, filename, p); + + js_free(J, s); + fclose(f); + js_endtry(J); +} + +int js_dostring(js_State *J, const char *source) +{ + if (js_try(J)) { + js_report(J, js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + js_loadstring(J, "[string]", source); + js_pushundefined(J); + js_call(J, 0); + js_pop(J, 1); + js_endtry(J); + return 0; +} + +int js_dofile(js_State *J, const char *filename) +{ + if (js_try(J)) { + js_report(J, js_trystring(J, -1, "Error")); + js_pop(J, 1); + return 1; + } + js_loadfile(J, filename); + js_pushundefined(J); + js_call(J, 0); + js_pop(J, 1); + js_endtry(J); + return 0; +} + +js_Panic js_atpanic(js_State *J, js_Panic panic) +{ + js_Panic old = J->panic; + J->panic = panic; + return old; +} + +void js_report(js_State *J, const char *message) +{ + if (J->report) + J->report(J, message); +} + +void js_setreport(js_State *J, js_Report report) +{ + J->report = report; +} + +void js_setcontext(js_State *J, void *uctx) +{ + J->uctx = uctx; +} + +void *js_getcontext(js_State *J) +{ + return J->uctx; +} + +js_State *js_newstate(js_Alloc alloc, void *actx, int flags) +{ + js_State *J; + + assert(sizeof(js_Value) == 16); + assert(soffsetof(js_Value, type) == 15); + + if (!alloc) + alloc = js_defaultalloc; + + J = alloc(actx, NULL, sizeof *J); + if (!J) + return NULL; + memset(J, 0, sizeof(*J)); + J->actx = actx; + J->alloc = alloc; + + if (flags & JS_STRICT) + J->strict = J->default_strict = 1; + + J->trace[0].name = "-top-"; + J->trace[0].file = "native"; + J->trace[0].line = 0; + + J->report = js_defaultreport; + J->panic = js_defaultpanic; + + J->stack = alloc(actx, NULL, JS_STACKSIZE * sizeof *J->stack); + if (!J->stack) { + alloc(actx, NULL, 0); + return NULL; + } + + J->gcmark = 1; + J->nextref = 0; + J->gcthresh = 0; /* reaches stability within ~ 2-5 GC cycles */ + + J->R = jsV_newobject(J, JS_COBJECT, NULL); + J->G = jsV_newobject(J, JS_COBJECT, NULL); + J->E = jsR_newenvironment(J, J->G, NULL); + J->GE = J->E; + + jsB_init(J); + + return J; +} diff --git a/programs/develop/kosjs/libmujs/jsstring.c b/programs/develop/kosjs/libmujs/jsstring.c new file mode 100755 index 0000000000..0bb2f223b4 --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsstring.c @@ -0,0 +1,711 @@ +#include "jsi.h" +#include "jsvalue.h" +#include "jsbuiltin.h" +#include "utf.h" +#include "regexp.h" + +static int js_doregexec(js_State *J, Reprog *prog, const char *string, Resub *sub, int eflags) +{ + int result = js_regexec(prog, string, sub, eflags); + if (result < 0) + js_error(J, "regexec failed"); + return result; +} + +static const char *checkstring(js_State *J, int idx) +{ + if (!js_iscoercible(J, idx)) + js_typeerror(J, "string function called on null or undefined"); + return js_tostring(J, idx); +} + +int js_runeat(js_State *J, const char *s, int i) +{ + Rune rune = EOF; + while (i-- >= 0) { + rune = *(unsigned char*)s; + if (rune < Runeself) { + if (rune == 0) + return EOF; + ++s; + } else + s += chartorune(&rune, s); + } + return rune; +} + +const char *js_utfidxtoptr(const char *s, int i) +{ + Rune rune; + while (i-- > 0) { + rune = *(unsigned char*)s; + if (rune < Runeself) { + if (rune == 0) + return NULL; + ++s; + } else + s += chartorune(&rune, s); + } + return s; +} + +int js_utfptrtoidx(const char *s, const char *p) +{ + Rune rune; + int i = 0; + while (s < p) { + if (*(unsigned char *)s < Runeself) + ++s; + else + s += chartorune(&rune, s); + ++i; + } + return i; +} + +static void jsB_new_String(js_State *J) +{ + js_newstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : ""); +} + +static void jsB_String(js_State *J) +{ + js_pushstring(J, js_gettop(J) > 1 ? js_tostring(J, 1) : ""); +} + +static void Sp_toString(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CSTRING) js_typeerror(J, "not a string"); + js_pushliteral(J, self->u.s.string); +} + +static void Sp_valueOf(js_State *J) +{ + js_Object *self = js_toobject(J, 0); + if (self->type != JS_CSTRING) js_typeerror(J, "not a string"); + js_pushliteral(J, self->u.s.string); +} + +static void Sp_charAt(js_State *J) +{ + char buf[UTFmax + 1]; + const char *s = checkstring(J, 0); + int pos = js_tointeger(J, 1); + Rune rune = js_runeat(J, s, pos); + if (rune >= 0) { + buf[runetochar(buf, &rune)] = 0; + js_pushstring(J, buf); + } else { + js_pushliteral(J, ""); + } +} + +static void Sp_charCodeAt(js_State *J) +{ + const char *s = checkstring(J, 0); + int pos = js_tointeger(J, 1); + Rune rune = js_runeat(J, s, pos); + if (rune >= 0) + js_pushnumber(J, rune); + else + js_pushnumber(J, NAN); +} + +static void Sp_concat(js_State *J) +{ + int i, top = js_gettop(J); + int n; + char * volatile out; + const char *s; + + if (top == 1) + return; + + s = checkstring(J, 0); + n = strlen(s); + out = js_malloc(J, n + 1); + strcpy(out, s); + + if (js_try(J)) { + js_free(J, out); + js_throw(J); + } + + for (i = 1; i < top; ++i) { + s = js_tostring(J, i); + n += strlen(s); + out = js_realloc(J, out, n + 1); + strcat(out, s); + } + + js_pushstring(J, out); + js_endtry(J); + js_free(J, out); +} + +static void Sp_indexOf(js_State *J) +{ + const char *haystack = checkstring(J, 0); + const char *needle = js_tostring(J, 1); + int pos = js_tointeger(J, 2); + int len = strlen(needle); + int k = 0; + Rune rune; + while (*haystack) { + if (k >= pos && !strncmp(haystack, needle, len)) { + js_pushnumber(J, k); + return; + } + haystack += chartorune(&rune, haystack); + ++k; + } + js_pushnumber(J, -1); +} + +static void Sp_lastIndexOf(js_State *J) +{ + const char *haystack = checkstring(J, 0); + const char *needle = js_tostring(J, 1); + int pos = js_isdefined(J, 2) ? js_tointeger(J, 2) : (int)strlen(haystack); + int len = strlen(needle); + int k = 0, last = -1; + Rune rune; + while (*haystack && k <= pos) { + if (!strncmp(haystack, needle, len)) + last = k; + haystack += chartorune(&rune, haystack); + ++k; + } + js_pushnumber(J, last); +} + +static void Sp_localeCompare(js_State *J) +{ + const char *a = checkstring(J, 0); + const char *b = js_tostring(J, 1); + js_pushnumber(J, strcmp(a, b)); +} + +static void Sp_slice(js_State *J) +{ + const char *str = checkstring(J, 0); + const char *ss, *ee; + int len = utflen(str); + int s = js_tointeger(J, 1); + int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; + + s = s < 0 ? s + len : s; + e = e < 0 ? e + len : e; + + s = s < 0 ? 0 : s > len ? len : s; + e = e < 0 ? 0 : e > len ? len : e; + + if (s < e) { + ss = js_utfidxtoptr(str, s); + ee = js_utfidxtoptr(ss, e - s); + } else { + ss = js_utfidxtoptr(str, e); + ee = js_utfidxtoptr(ss, s - e); + } + + js_pushlstring(J, ss, ee - ss); +} + +static void Sp_substring(js_State *J) +{ + const char *str = checkstring(J, 0); + const char *ss, *ee; + int len = utflen(str); + int s = js_tointeger(J, 1); + int e = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; + + s = s < 0 ? 0 : s > len ? len : s; + e = e < 0 ? 0 : e > len ? len : e; + + if (s < e) { + ss = js_utfidxtoptr(str, s); + ee = js_utfidxtoptr(ss, e - s); + } else { + ss = js_utfidxtoptr(str, e); + ee = js_utfidxtoptr(ss, s - e); + } + + js_pushlstring(J, ss, ee - ss); +} + +static void Sp_toLowerCase(js_State *J) +{ + const char *src = checkstring(J, 0); + char *dst = js_malloc(J, UTFmax * strlen(src) + 1); + const char *s = src; + char *d = dst; + Rune rune; + while (*s) { + s += chartorune(&rune, s); + rune = tolowerrune(rune); + d += runetochar(d, &rune); + } + *d = 0; + if (js_try(J)) { + js_free(J, dst); + js_throw(J); + } + js_pushstring(J, dst); + js_endtry(J); + js_free(J, dst); +} + +static void Sp_toUpperCase(js_State *J) +{ + const char *src = checkstring(J, 0); + char *dst = js_malloc(J, UTFmax * strlen(src) + 1); + const char *s = src; + char *d = dst; + Rune rune; + while (*s) { + s += chartorune(&rune, s); + rune = toupperrune(rune); + d += runetochar(d, &rune); + } + *d = 0; + if (js_try(J)) { + js_free(J, dst); + js_throw(J); + } + js_pushstring(J, dst); + js_endtry(J); + js_free(J, dst); +} + +static int istrim(int c) +{ + return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF || + c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; +} + +static void Sp_trim(js_State *J) +{ + const char *s, *e; + s = checkstring(J, 0); + while (istrim(*s)) + ++s; + e = s + strlen(s); + while (e > s && istrim(e[-1])) + --e; + js_pushlstring(J, s, e - s); +} + +static void S_fromCharCode(js_State *J) +{ + int i, top = js_gettop(J); + Rune c; + char *s, *p; + + s = p = js_malloc(J, (top-1) * UTFmax + 1); + + if (js_try(J)) { + js_free(J, s); + js_throw(J); + } + + for (i = 1; i < top; ++i) { + c = js_touint32(J, i); + p += runetochar(p, &c); + } + *p = 0; + js_pushstring(J, s); + + js_endtry(J); + js_free(J, s); +} + +static void Sp_match(js_State *J) +{ + js_Regexp *re; + const char *text; + int len; + const char *a, *b, *c, *e; + Resub m; + + text = checkstring(J, 0); + + if (js_isregexp(J, 1)) + js_copy(J, 1); + else if (js_isundefined(J, 1)) + js_newregexp(J, "", 0); + else + js_newregexp(J, js_tostring(J, 1), 0); + + re = js_toregexp(J, -1); + if (!(re->flags & JS_REGEXP_G)) { + js_RegExp_prototype_exec(J, re, text); + return; + } + + re->last = 0; + + js_newarray(J); + + len = 0; + a = text; + e = text + strlen(text); + while (a <= e) { + if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0)) + break; + + b = m.sub[0].sp; + c = m.sub[0].ep; + + js_pushlstring(J, b, c - b); + js_setindex(J, -2, len++); + + a = c; + if (c - b == 0) + ++a; + } + + if (len == 0) { + js_pop(J, 1); + js_pushnull(J); + } +} + +static void Sp_search(js_State *J) +{ + js_Regexp *re; + const char *text; + Resub m; + + text = checkstring(J, 0); + + if (js_isregexp(J, 1)) + js_copy(J, 1); + else if (js_isundefined(J, 1)) + js_newregexp(J, "", 0); + else + js_newregexp(J, js_tostring(J, 1), 0); + + re = js_toregexp(J, -1); + + if (!js_doregexec(J, re->prog, text, &m, 0)) + js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp)); + else + js_pushnumber(J, -1); +} + +static void Sp_replace_regexp(js_State *J) +{ + js_Regexp *re; + const char *source, *s, *r; + js_Buffer *sb = NULL; + int n, x; + Resub m; + + source = checkstring(J, 0); + re = js_toregexp(J, 1); + + if (js_doregexec(J, re->prog, source, &m, 0)) { + js_copy(J, 0); + return; + } + + re->last = 0; + +loop: + s = m.sub[0].sp; + n = m.sub[0].ep - m.sub[0].sp; + + if (js_iscallable(J, 2)) { + js_copy(J, 2); + js_pushundefined(J); + for (x = 0; m.sub[x].sp; ++x) /* arg 0..x: substring and subexps that matched */ + js_pushlstring(J, m.sub[x].sp, m.sub[x].ep - m.sub[x].sp); + js_pushnumber(J, s - source); /* arg x+2: offset within search string */ + js_copy(J, 0); /* arg x+3: search string */ + js_call(J, 2 + x); + r = js_tostring(J, -1); + js_putm(J, &sb, source, s); + js_puts(J, &sb, r); + js_pop(J, 1); + } else { + r = js_tostring(J, 2); + js_putm(J, &sb, source, s); + while (*r) { + if (*r == '$') { + switch (*(++r)) { + case 0: --r; /* end of string; back up */ + /* fallthrough */ + case '$': js_putc(J, &sb, '$'); break; + case '`': js_putm(J, &sb, source, s); break; + case '\'': js_puts(J, &sb, s + n); break; + case '&': + js_putm(J, &sb, s, s + n); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + x = *r - '0'; + if (r[1] >= '0' && r[1] <= '9') + x = x * 10 + *(++r) - '0'; + if (x > 0 && x < m.nsub) { + js_putm(J, &sb, m.sub[x].sp, m.sub[x].ep); + } else { + js_putc(J, &sb, '$'); + if (x > 10) { + js_putc(J, &sb, '0' + x / 10); + js_putc(J, &sb, '0' + x % 10); + } else { + js_putc(J, &sb, '0' + x); + } + } + break; + default: + js_putc(J, &sb, '$'); + js_putc(J, &sb, *r); + break; + } + ++r; + } else { + js_putc(J, &sb, *r++); + } + } + } + + if (re->flags & JS_REGEXP_G) { + source = m.sub[0].ep; + if (n == 0) { + if (*source) + js_putc(J, &sb, *source++); + else + goto end; + } + if (!js_doregexec(J, re->prog, source, &m, REG_NOTBOL)) + goto loop; + } + +end: + js_puts(J, &sb, s + n); + js_putc(J, &sb, 0); + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +static void Sp_replace_string(js_State *J) +{ + const char *source, *needle, *s, *r; + js_Buffer *sb = NULL; + int n; + + source = checkstring(J, 0); + needle = js_tostring(J, 1); + + s = strstr(source, needle); + if (!s) { + js_copy(J, 0); + return; + } + n = strlen(needle); + + if (js_iscallable(J, 2)) { + js_copy(J, 2); + js_pushundefined(J); + js_pushlstring(J, s, n); /* arg 1: substring that matched */ + js_pushnumber(J, s - source); /* arg 2: offset within search string */ + js_copy(J, 0); /* arg 3: search string */ + js_call(J, 3); + r = js_tostring(J, -1); + js_putm(J, &sb, source, s); + js_puts(J, &sb, r); + js_puts(J, &sb, s + n); + js_putc(J, &sb, 0); + js_pop(J, 1); + } else { + r = js_tostring(J, 2); + js_putm(J, &sb, source, s); + while (*r) { + if (*r == '$') { + switch (*(++r)) { + case 0: --r; /* end of string; back up */ + /* fallthrough */ + case '$': js_putc(J, &sb, '$'); break; + case '&': js_putm(J, &sb, s, s + n); break; + case '`': js_putm(J, &sb, source, s); break; + case '\'': js_puts(J, &sb, s + n); break; + default: js_putc(J, &sb, '$'); js_putc(J, &sb, *r); break; + } + ++r; + } else { + js_putc(J, &sb, *r++); + } + } + js_puts(J, &sb, s + n); + js_putc(J, &sb, 0); + } + + if (js_try(J)) { + js_free(J, sb); + js_throw(J); + } + js_pushstring(J, sb ? sb->s : ""); + js_endtry(J); + js_free(J, sb); +} + +static void Sp_replace(js_State *J) +{ + if (js_isregexp(J, 1)) + Sp_replace_regexp(J); + else + Sp_replace_string(J); +} + +static void Sp_split_regexp(js_State *J) +{ + js_Regexp *re; + const char *text; + int limit, len, k; + const char *p, *a, *b, *c, *e; + Resub m; + + text = checkstring(J, 0); + re = js_toregexp(J, 1); + limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30; + + js_newarray(J); + len = 0; + + e = text + strlen(text); + + /* splitting the empty string */ + if (e == text) { + if (js_doregexec(J, re->prog, text, &m, 0)) { + if (len == limit) return; + js_pushliteral(J, ""); + js_setindex(J, -2, 0); + } + return; + } + + p = a = text; + while (a < e) { + if (js_doregexec(J, re->prog, a, &m, a > text ? REG_NOTBOL : 0)) + break; /* no match */ + + b = m.sub[0].sp; + c = m.sub[0].ep; + + /* empty string at end of last match */ + if (b == p) { + ++a; + continue; + } + + if (len == limit) return; + js_pushlstring(J, p, b - p); + js_setindex(J, -2, len++); + + for (k = 1; k < m.nsub; ++k) { + if (len == limit) return; + js_pushlstring(J, m.sub[k].sp, m.sub[k].ep - m.sub[k].sp); + js_setindex(J, -2, len++); + } + + a = p = c; + } + + if (len == limit) return; + js_pushstring(J, p); + js_setindex(J, -2, len); +} + +static void Sp_split_string(js_State *J) +{ + const char *str = checkstring(J, 0); + const char *sep = js_tostring(J, 1); + int limit = js_isdefined(J, 2) ? js_tointeger(J, 2) : 1 << 30; + int i, n; + + js_newarray(J); + + n = strlen(sep); + + /* empty string */ + if (n == 0) { + Rune rune; + for (i = 0; *str && i < limit; ++i) { + n = chartorune(&rune, str); + js_pushlstring(J, str, n); + js_setindex(J, -2, i); + str += n; + } + return; + } + + for (i = 0; str && i < limit; ++i) { + const char *s = strstr(str, sep); + if (s) { + js_pushlstring(J, str, s-str); + js_setindex(J, -2, i); + str = s + n; + } else { + js_pushstring(J, str); + js_setindex(J, -2, i); + str = NULL; + } + } +} + +static void Sp_split(js_State *J) +{ + if (js_isundefined(J, 1)) { + js_newarray(J); + js_copy(J, 0); + js_setindex(J, -2, 0); + } else if (js_isregexp(J, 1)) { + Sp_split_regexp(J); + } else { + Sp_split_string(J); + } +} + +void jsB_initstring(js_State *J) +{ + J->String_prototype->u.s.string = ""; + J->String_prototype->u.s.length = 0; + + js_pushobject(J, J->String_prototype); + { + jsB_propf(J, "String.prototype.toString", Sp_toString, 0); + jsB_propf(J, "String.prototype.valueOf", Sp_valueOf, 0); + jsB_propf(J, "String.prototype.charAt", Sp_charAt, 1); + jsB_propf(J, "String.prototype.charCodeAt", Sp_charCodeAt, 1); + jsB_propf(J, "String.prototype.concat", Sp_concat, 0); /* 1 */ + jsB_propf(J, "String.prototype.indexOf", Sp_indexOf, 1); + jsB_propf(J, "String.prototype.lastIndexOf", Sp_lastIndexOf, 1); + jsB_propf(J, "String.prototype.localeCompare", Sp_localeCompare, 1); + jsB_propf(J, "String.prototype.match", Sp_match, 1); + jsB_propf(J, "String.prototype.replace", Sp_replace, 2); + jsB_propf(J, "String.prototype.search", Sp_search, 1); + jsB_propf(J, "String.prototype.slice", Sp_slice, 2); + jsB_propf(J, "String.prototype.split", Sp_split, 2); + jsB_propf(J, "String.prototype.substring", Sp_substring, 2); + jsB_propf(J, "String.prototype.toLowerCase", Sp_toLowerCase, 0); + jsB_propf(J, "String.prototype.toLocaleLowerCase", Sp_toLowerCase, 0); + jsB_propf(J, "String.prototype.toUpperCase", Sp_toUpperCase, 0); + jsB_propf(J, "String.prototype.toLocaleUpperCase", Sp_toUpperCase, 0); + + /* ES5 */ + jsB_propf(J, "String.prototype.trim", Sp_trim, 0); + } + js_newcconstructor(J, jsB_String, jsB_new_String, "String", 0); /* 1 */ + { + jsB_propf(J, "String.fromCharCode", S_fromCharCode, 0); /* 1 */ + } + js_defglobal(J, "String", JS_DONTENUM); +} diff --git a/programs/develop/kosjs/libmujs/jsvalue.c b/programs/develop/kosjs/libmujs/jsvalue.c new file mode 100755 index 0000000000..5537ec6f5a --- /dev/null +++ b/programs/develop/kosjs/libmujs/jsvalue.c @@ -0,0 +1,630 @@ +#include "jsi.h" +#include "jslex.h" +#include "jscompile.h" +#include "jsvalue.h" +#include "utf.h" + +#define JSV_ISSTRING(v) (v->type==JS_TSHRSTR || v->type==JS_TMEMSTR || v->type==JS_TLITSTR) +#define JSV_TOSTRING(v) (v->type==JS_TSHRSTR ? v->u.shrstr : v->type==JS_TLITSTR ? v->u.litstr : v->type==JS_TMEMSTR ? v->u.memstr->p : "") + +int jsV_numbertointeger(double n) +{ + if (n == 0) return 0; + if (isnan(n)) return 0; + n = (n < 0) ? -floor(-n) : floor(n); + if (n < INT_MIN) return INT_MIN; + if (n > INT_MAX) return INT_MAX; + return (int)n; +} + +int jsV_numbertoint32(double n) +{ + double two32 = 4294967296.0; + double two31 = 2147483648.0; + + if (!isfinite(n) || n == 0) + return 0; + + n = fmod(n, two32); + n = n >= 0 ? floor(n) : ceil(n) + two32; + if (n >= two31) + return n - two32; + else + return n; +} + +unsigned int jsV_numbertouint32(double n) +{ + return (unsigned int)jsV_numbertoint32(n); +} + +short jsV_numbertoint16(double n) +{ + return jsV_numbertoint32(n); +} + +unsigned short jsV_numbertouint16(double n) +{ + return jsV_numbertoint32(n); +} + +/* obj.toString() */ +static int jsV_toString(js_State *J, js_Object *obj) +{ + js_pushobject(J, obj); + js_getproperty(J, -1, "toString"); + if (js_iscallable(J, -1)) { + js_rot2(J); + js_call(J, 0); + if (js_isprimitive(J, -1)) + return 1; + js_pop(J, 1); + return 0; + } + js_pop(J, 2); + return 0; +} + +/* obj.valueOf() */ +static int jsV_valueOf(js_State *J, js_Object *obj) +{ + js_pushobject(J, obj); + js_getproperty(J, -1, "valueOf"); + if (js_iscallable(J, -1)) { + js_rot2(J); + js_call(J, 0); + if (js_isprimitive(J, -1)) + return 1; + js_pop(J, 1); + return 0; + } + js_pop(J, 2); + return 0; +} + +/* ToPrimitive() on a value */ +void jsV_toprimitive(js_State *J, js_Value *v, int preferred) +{ + js_Object *obj; + + if (v->type != JS_TOBJECT) + return; + + obj = v->u.object; + + if (preferred == JS_HNONE) + preferred = obj->type == JS_CDATE ? JS_HSTRING : JS_HNUMBER; + + if (preferred == JS_HSTRING) { + if (jsV_toString(J, obj) || jsV_valueOf(J, obj)) { + *v = *js_tovalue(J, -1); + js_pop(J, 1); + return; + } + } else { + if (jsV_valueOf(J, obj) || jsV_toString(J, obj)) { + *v = *js_tovalue(J, -1); + js_pop(J, 1); + return; + } + } + + if (J->strict) + js_typeerror(J, "cannot convert object to primitive"); + + v->type = JS_TLITSTR; + v->u.litstr = "[object]"; + return; +} + +/* ToBoolean() on a value */ +int jsV_toboolean(js_State *J, js_Value *v) +{ + switch (v->type) { + default: + case JS_TSHRSTR: return v->u.shrstr[0] != 0; + case JS_TUNDEFINED: return 0; + case JS_TNULL: return 0; + case JS_TBOOLEAN: return v->u.boolean; + case JS_TNUMBER: return v->u.number != 0 && !isnan(v->u.number); + case JS_TLITSTR: return v->u.litstr[0] != 0; + case JS_TMEMSTR: return v->u.memstr->p[0] != 0; + case JS_TOBJECT: return 1; + } +} + +const char *js_itoa(char *out, int v) +{ + char buf[32], *s = out; + unsigned int a; + int i = 0; + if (v < 0) { + a = -v; + *s++ = '-'; + } else { + a = v; + } + while (a) { + buf[i++] = (a % 10) + '0'; + a /= 10; + } + if (i == 0) + buf[i++] = '0'; + while (i > 0) + *s++ = buf[--i]; + *s = 0; + return out; +} + +double js_stringtofloat(const char *s, char **ep) +{ + char *end; + double n; + const char *e = s; + int isflt = 0; + if (*e == '+' || *e == '-') ++e; + while (*e >= '0' && *e <= '9') ++e; + if (*e == '.') { ++e; isflt = 1; } + while (*e >= '0' && *e <= '9') ++e; + if (*e == 'e' || *e == 'E') { + ++e; + if (*e == '+' || *e == '-') ++e; + while (*e >= '0' && *e <= '9') ++e; + isflt = 1; + } + if (isflt || e - s > 9) + n = js_strtod(s, &end); + else + n = strtol(s, &end, 10); + if (end == e) { + *ep = (char*)e; + return n; + } + *ep = (char*)s; + return 0; +} + +/* ToNumber() on a string */ +double jsV_stringtonumber(js_State *J, const char *s) +{ + char *e; + double n; + while (jsY_iswhite(*s) || jsY_isnewline(*s)) ++s; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && s[2] != 0) + n = strtol(s + 2, &e, 16); + else if (!strncmp(s, "Infinity", 8)) + n = INFINITY, e = (char*)s + 8; + else if (!strncmp(s, "+Infinity", 9)) + n = INFINITY, e = (char*)s + 9; + else if (!strncmp(s, "-Infinity", 9)) + n = -INFINITY, e = (char*)s + 9; + else + n = js_stringtofloat(s, &e); + while (jsY_iswhite(*e) || jsY_isnewline(*e)) ++e; + if (*e) return NAN; + return n; +} + +/* ToNumber() on a value */ +double jsV_tonumber(js_State *J, js_Value *v) +{ + switch (v->type) { + default: + case JS_TSHRSTR: return jsV_stringtonumber(J, v->u.shrstr); + case JS_TUNDEFINED: return NAN; + case JS_TNULL: return 0; + case JS_TBOOLEAN: return v->u.boolean; + case JS_TNUMBER: return v->u.number; + case JS_TLITSTR: return jsV_stringtonumber(J, v->u.litstr); + case JS_TMEMSTR: return jsV_stringtonumber(J, v->u.memstr->p); + case JS_TOBJECT: + jsV_toprimitive(J, v, JS_HNUMBER); + return jsV_tonumber(J, v); + } +} + +double jsV_tointeger(js_State *J, js_Value *v) +{ + return jsV_numbertointeger(jsV_tonumber(J, v)); +} + +/* ToString() on a number */ +const char *jsV_numbertostring(js_State *J, char buf[32], double f) +{ + char digits[32], *p = buf, *s = digits; + int exp, ndigits, point; + + if (f == 0) return "0"; + if (isnan(f)) return "NaN"; + if (isinf(f)) return f < 0 ? "-Infinity" : "Infinity"; + + /* Fast case for integers. This only works assuming all integers can be + * exactly represented by a float. This is true for 32-bit integers and + * 64-bit floats. */ + if (f >= INT_MIN && f <= INT_MAX) { + int i = (int)f; + if ((double)i == f) + return js_itoa(buf, i); + } + + ndigits = js_grisu2(f, digits, &exp); + point = ndigits + exp; + + if (signbit(f)) + *p++ = '-'; + + if (point < -5 || point > 21) { + *p++ = *s++; + if (ndigits > 1) { + int n = ndigits - 1; + *p++ = '.'; + while (n--) + *p++ = *s++; + } + js_fmtexp(p, point - 1); + } + + else if (point <= 0) { + *p++ = '0'; + *p++ = '.'; + while (point++ < 0) + *p++ = '0'; + while (ndigits-- > 0) + *p++ = *s++; + *p = 0; + } + + else { + while (ndigits-- > 0) { + *p++ = *s++; + if (--point == 0 && ndigits > 0) + *p++ = '.'; + } + while (point-- > 0) + *p++ = '0'; + *p = 0; + } + + return buf; +} + +/* ToString() on a value */ +const char *jsV_tostring(js_State *J, js_Value *v) +{ + char buf[32]; + const char *p; + switch (v->type) { + default: + case JS_TSHRSTR: return v->u.shrstr; + case JS_TUNDEFINED: return "undefined"; + case JS_TNULL: return "null"; + case JS_TBOOLEAN: return v->u.boolean ? "true" : "false"; + case JS_TLITSTR: return v->u.litstr; + case JS_TMEMSTR: return v->u.memstr->p; + case JS_TNUMBER: + p = jsV_numbertostring(J, buf, v->u.number); + if (p == buf) { + int n = strlen(p); + if (n <= soffsetof(js_Value, type)) { + char *s = v->u.shrstr; + while (n--) *s++ = *p++; + *s = 0; + v->type = JS_TSHRSTR; + return v->u.shrstr; + } else { + v->u.memstr = jsV_newmemstring(J, p, n); + v->type = JS_TMEMSTR; + return v->u.memstr->p; + } + } + return p; + case JS_TOBJECT: + jsV_toprimitive(J, v, JS_HSTRING); + return jsV_tostring(J, v); + } +} + +/* Objects */ + +static js_Object *jsV_newboolean(js_State *J, int v) +{ + js_Object *obj = jsV_newobject(J, JS_CBOOLEAN, J->Boolean_prototype); + obj->u.boolean = v; + return obj; +} + +static js_Object *jsV_newnumber(js_State *J, double v) +{ + js_Object *obj = jsV_newobject(J, JS_CNUMBER, J->Number_prototype); + obj->u.number = v; + return obj; +} + +static js_Object *jsV_newstring(js_State *J, const char *v) +{ + js_Object *obj = jsV_newobject(J, JS_CSTRING, J->String_prototype); + obj->u.s.string = js_intern(J, v); /* TODO: js_String */ + obj->u.s.length = utflen(v); + return obj; +} + +/* ToObject() on a value */ +js_Object *jsV_toobject(js_State *J, js_Value *v) +{ + switch (v->type) { + default: + case JS_TSHRSTR: return jsV_newstring(J, v->u.shrstr); + case JS_TUNDEFINED: js_typeerror(J, "cannot convert undefined to object"); + case JS_TNULL: js_typeerror(J, "cannot convert null to object"); + case JS_TBOOLEAN: return jsV_newboolean(J, v->u.boolean); + case JS_TNUMBER: return jsV_newnumber(J, v->u.number); + case JS_TLITSTR: return jsV_newstring(J, v->u.litstr); + case JS_TMEMSTR: return jsV_newstring(J, v->u.memstr->p); + case JS_TOBJECT: return v->u.object; + } +} + +void js_newobjectx(js_State *J) +{ + js_Object *prototype = NULL; + if (js_isobject(J, -1)) + prototype = js_toobject(J, -1); + js_pop(J, 1); + js_pushobject(J, jsV_newobject(J, JS_COBJECT, prototype)); +} + +void js_newobject(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, JS_COBJECT, J->Object_prototype)); +} + +void js_newarguments(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, JS_CARGUMENTS, J->Object_prototype)); +} + +void js_newarray(js_State *J) +{ + js_pushobject(J, jsV_newobject(J, JS_CARRAY, J->Array_prototype)); +} + +void js_newboolean(js_State *J, int v) +{ + js_pushobject(J, jsV_newboolean(J, v)); +} + +void js_newnumber(js_State *J, double v) +{ + js_pushobject(J, jsV_newnumber(J, v)); +} + +void js_newstring(js_State *J, const char *v) +{ + js_pushobject(J, jsV_newstring(J, v)); +} + +void js_newfunction(js_State *J, js_Function *fun, js_Environment *scope) +{ + js_Object *obj = jsV_newobject(J, JS_CFUNCTION, J->Function_prototype); + obj->u.f.function = fun; + obj->u.f.scope = scope; + js_pushobject(J, obj); + { + js_pushnumber(J, fun->numparams); + js_defproperty(J, -2, "length", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + js_newobject(J); + { + js_copy(J, -2); + js_defproperty(J, -2, "constructor", JS_DONTENUM); + } + js_defproperty(J, -2, "prototype", JS_DONTENUM | JS_DONTCONF); + } +} + +void js_newscript(js_State *J, js_Function *fun, js_Environment *scope, int type) +{ + js_Object *obj = jsV_newobject(J, type, NULL); + obj->u.f.function = fun; + obj->u.f.scope = scope; + js_pushobject(J, obj); +} + +void js_newcfunction(js_State *J, js_CFunction cfun, const char *name, int length) +{ + js_Object *obj = jsV_newobject(J, JS_CCFUNCTION, J->Function_prototype); + obj->u.c.name = name; + obj->u.c.function = cfun; + obj->u.c.constructor = NULL; + obj->u.c.length = length; + js_pushobject(J, obj); + { + js_pushnumber(J, length); + js_defproperty(J, -2, "length", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + js_newobject(J); + { + js_copy(J, -2); + js_defproperty(J, -2, "constructor", JS_DONTENUM); + } + js_defproperty(J, -2, "prototype", JS_DONTENUM | JS_DONTCONF); + } +} + +/* prototype -- constructor */ +void js_newcconstructor(js_State *J, js_CFunction cfun, js_CFunction ccon, const char *name, int length) +{ + js_Object *obj = jsV_newobject(J, JS_CCFUNCTION, J->Function_prototype); + obj->u.c.name = name; + obj->u.c.function = cfun; + obj->u.c.constructor = ccon; + obj->u.c.length = length; + js_pushobject(J, obj); /* proto obj */ + { + js_pushnumber(J, length); + js_defproperty(J, -2, "length", JS_READONLY | JS_DONTENUM | JS_DONTCONF); + js_rot2(J); /* obj proto */ + js_copy(J, -2); /* obj proto obj */ + js_defproperty(J, -2, "constructor", JS_DONTENUM); + js_defproperty(J, -2, "prototype", JS_DONTENUM | JS_DONTCONF); + } +} + +void js_newuserdatax(js_State *J, const char *tag, void *data, js_HasProperty has, js_Put put, js_Delete delete, js_Finalize finalize) +{ + js_Object *prototype = NULL; + js_Object *obj; + + if (js_isobject(J, -1)) + prototype = js_toobject(J, -1); + js_pop(J, 1); + + obj = jsV_newobject(J, JS_CUSERDATA, prototype); + obj->u.user.tag = tag; + obj->u.user.data = data; + obj->u.user.has = has; + obj->u.user.put = put; + obj->u.user.delete = delete; + obj->u.user.finalize = finalize; + js_pushobject(J, obj); +} + +void js_newuserdata(js_State *J, const char *tag, void *data, js_Finalize finalize) +{ + js_newuserdatax(J, tag, data, NULL, NULL, NULL, finalize); +} + +/* Non-trivial operations on values. These are implemented using the stack. */ + +int js_instanceof(js_State *J) +{ + js_Object *O, *V; + + if (!js_iscallable(J, -1)) + js_typeerror(J, "instanceof: invalid operand"); + + if (!js_isobject(J, -2)) + return 0; + + js_getproperty(J, -1, "prototype"); + if (!js_isobject(J, -1)) + js_typeerror(J, "instanceof: 'prototype' property is not an object"); + O = js_toobject(J, -1); + js_pop(J, 1); + + V = js_toobject(J, -2); + while (V) { + V = V->prototype; + if (O == V) + return 1; + } + + return 0; +} + +void js_concat(js_State *J) +{ + js_toprimitive(J, -2, JS_HNONE); + js_toprimitive(J, -1, JS_HNONE); + + if (js_isstring(J, -2) || js_isstring(J, -1)) { + const char *sa = js_tostring(J, -2); + const char *sb = js_tostring(J, -1); + /* TODO: create js_String directly */ + char *sab = js_malloc(J, strlen(sa) + strlen(sb) + 1); + strcpy(sab, sa); + strcat(sab, sb); + if (js_try(J)) { + js_free(J, sab); + js_throw(J); + } + js_pop(J, 2); + js_pushstring(J, sab); + js_endtry(J); + js_free(J, sab); + } else { + double x = js_tonumber(J, -2); + double y = js_tonumber(J, -1); + js_pop(J, 2); + js_pushnumber(J, x + y); + } +} + +int js_compare(js_State *J, int *okay) +{ + js_toprimitive(J, -2, JS_HNUMBER); + js_toprimitive(J, -1, JS_HNUMBER); + + *okay = 1; + if (js_isstring(J, -2) && js_isstring(J, -1)) { + return strcmp(js_tostring(J, -2), js_tostring(J, -1)); + } else { + double x = js_tonumber(J, -2); + double y = js_tonumber(J, -1); + if (isnan(x) || isnan(y)) + *okay = 0; + return x < y ? -1 : x > y ? 1 : 0; + } +} + +int js_equal(js_State *J) +{ + js_Value *x = js_tovalue(J, -2); + js_Value *y = js_tovalue(J, -1); + +retry: + if (JSV_ISSTRING(x) && JSV_ISSTRING(y)) + return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y)); + if (x->type == y->type) { + if (x->type == JS_TUNDEFINED) return 1; + if (x->type == JS_TNULL) return 1; + if (x->type == JS_TNUMBER) return x->u.number == y->u.number; + if (x->type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean; + if (x->type == JS_TOBJECT) return x->u.object == y->u.object; + return 0; + } + + if (x->type == JS_TNULL && y->type == JS_TUNDEFINED) return 1; + if (x->type == JS_TUNDEFINED && y->type == JS_TNULL) return 1; + + if (x->type == JS_TNUMBER && JSV_ISSTRING(y)) + return x->u.number == jsV_tonumber(J, y); + if (JSV_ISSTRING(x) && y->type == JS_TNUMBER) + return jsV_tonumber(J, x) == y->u.number; + + if (x->type == JS_TBOOLEAN) { + x->type = JS_TNUMBER; + x->u.number = x->u.boolean ? 1 : 0; + goto retry; + } + if (y->type == JS_TBOOLEAN) { + y->type = JS_TNUMBER; + y->u.number = y->u.boolean ? 1 : 0; + goto retry; + } + if ((JSV_ISSTRING(x) || x->type == JS_TNUMBER) && y->type == JS_TOBJECT) { + jsV_toprimitive(J, y, JS_HNONE); + goto retry; + } + if (x->type == JS_TOBJECT && (JSV_ISSTRING(y) || y->type == JS_TNUMBER)) { + jsV_toprimitive(J, x, JS_HNONE); + goto retry; + } + + return 0; +} + +int js_strictequal(js_State *J) +{ + js_Value *x = js_tovalue(J, -2); + js_Value *y = js_tovalue(J, -1); + + if (JSV_ISSTRING(x) && JSV_ISSTRING(y)) + return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y)); + + if (x->type != y->type) return 0; + if (x->type == JS_TUNDEFINED) return 1; + if (x->type == JS_TNULL) return 1; + if (x->type == JS_TNUMBER) return x->u.number == y->u.number; + if (x->type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean; + if (x->type == JS_TOBJECT) return x->u.object == y->u.object; + return 0; +} diff --git a/programs/develop/kosjs/libmujs/include/jsvalue.h b/programs/develop/kosjs/libmujs/jsvalue.h similarity index 98% rename from programs/develop/kosjs/libmujs/include/jsvalue.h rename to programs/develop/kosjs/libmujs/jsvalue.h index adfc6f9df8..697c8b42cc 100755 --- a/programs/develop/kosjs/libmujs/include/jsvalue.h +++ b/programs/develop/kosjs/libmujs/jsvalue.h @@ -119,7 +119,8 @@ struct js_Object js_Finalize finalize; } user; } u; - js_Object *gcnext; + js_Object *gcnext; /* allocation list */ + js_Object *gcroot; /* scan list */ int gcmark; }; diff --git a/programs/develop/kosjs/libmujs/lib/libmujs.a b/programs/develop/kosjs/libmujs/lib/libmujs.a deleted file mode 100755 index 2f8430f3cc90fbfd33580eba34385ae31ea413ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 326416 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

+sSSt+fDW@vVCOF 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 + +#include "jsi.h" +#include "jsparse.h" + +static void js_ppstring(js_State *J, const char *filename, const char *source, int minify) +{ + js_Ast *P; + if (js_try(J)) { + jsP_freeparse(J); + js_throw(J); + } + P = jsP_parse(J, filename, source); + if (minify > 2) + jsP_dumplist(J, P); + else + jsP_dumpsyntax(J, P, minify); + jsP_freeparse(J); + js_endtry(J); +} + +void js_ppfile(js_State *J, const char *filename, int minify) +{ + FILE *f; + char *s; + int n, t; + + f = fopen(filename, "rb"); + if (!f) { + js_error(J, "cannot open file: '%s'", filename); + } + + if (fseek(f, 0, SEEK_END) < 0) { + fclose(f); + js_error(J, "cannot seek in file: '%s'", filename); + } + + n = ftell(f); + if (n < 0) { + fclose(f); + js_error(J, "cannot tell in file: '%s'", filename); + } + + if (fseek(f, 0, SEEK_SET) < 0) { + fclose(f); + js_error(J, "cannot seek in file: '%s'", filename); + } + + s = js_malloc(J, n + 1); /* add space for string terminator */ + if (!s) { + fclose(f); + js_error(J, "cannot allocate storage for file contents: '%s'", filename); + } + + t = fread(s, 1, (size_t)n, f); + if (t != n) { + js_free(J, s); + fclose(f); + js_error(J, "cannot read data from file: '%s'", filename); + } + + s[n] = 0; /* zero-terminate string containing file data */ + + if (js_try(J)) { + js_free(J, s); + fclose(f); + js_throw(J); + } + + js_ppstring(J, filename, s, minify); + + js_free(J, s); + fclose(f); + js_endtry(J); +} + +int +main(int argc, char **argv) +{ + js_State *J; + int minify = 0; + int i; + + J = js_newstate(NULL, NULL, 0); + + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-m")) + minify = 1; + else if (!strcmp(argv[i], "-mm")) + minify = 2; + else if (!strcmp(argv[i], "-s")) + minify = 3; + else { + if (js_try(J)) { + js_report(J, js_trystring(J, -1, "Error")); + js_pop(J, 1); + continue; + } + js_ppfile(J, argv[i], minify); + js_endtry(J); + } + } + + js_gc(J, 0); + js_freestate(J); + + return 0; +} diff --git a/programs/develop/kosjs/libmujs/regexp.c b/programs/develop/kosjs/libmujs/regexp.c new file mode 100755 index 0000000000..66c518de61 --- /dev/null +++ b/programs/develop/kosjs/libmujs/regexp.c @@ -0,0 +1,1204 @@ +#include +#include +#include +#include +#include + +#include "regexp.h" +#include "utf.h" + +#define emit regemit +#define next regnext +#define accept regaccept + +#define nelem(a) (int)(sizeof (a) / sizeof (a)[0]) + +#define REPINF 255 +#ifndef REG_MAXPROG +#define REG_MAXPROG (32 << 10) +#endif +#ifndef REG_MAXREC +#define REG_MAXREC 1024 +#endif +#ifndef REG_MAXSPAN +#define REG_MAXSPAN 64 +#endif +#ifndef REG_MAXCLASS +#define REG_MAXCLASS 16 +#endif + +typedef struct Reclass Reclass; +typedef struct Renode Renode; +typedef struct Reinst Reinst; +typedef struct Rethread Rethread; + +struct Reclass { + Rune *end; + Rune spans[REG_MAXSPAN]; +}; + +struct Reprog { + Reinst *start, *end; + int flags; + int nsub; + Reclass cclass[REG_MAXCLASS]; +}; + +struct cstate { + Reprog *prog; + Renode *pstart, *pend; + + const char *source; + int ncclass; + int nsub; + Renode *sub[REG_MAXSUB]; + + int lookahead; + Rune yychar; + Reclass *yycc; + int yymin, yymax; + + const char *error; + jmp_buf kaboom; +}; + +static void die(struct cstate *g, const char *message) +{ + g->error = message; + longjmp(g->kaboom, 1); +} + +static int canon(Rune c) +{ + Rune u = toupperrune(c); + if (c >= 128 && u < 128) + return c; + return u; +} + +/* Scan */ + +enum { + L_CHAR = 256, + L_CCLASS, /* character class */ + L_NCCLASS, /* negative character class */ + L_NC, /* "(?:" no capture */ + L_PLA, /* "(?=" positive lookahead */ + L_NLA, /* "(?!" negative lookahead */ + L_WORD, /* "\b" word boundary */ + L_NWORD, /* "\B" non-word boundary */ + L_REF, /* "\1" back-reference */ + L_COUNT, /* {M,N} */ +}; + +static int hex(struct cstate *g, int c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; + if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; + die(g, "invalid escape sequence"); + return 0; +} + +static int dec(struct cstate *g, int c) +{ + if (c >= '0' && c <= '9') return c - '0'; + die(g, "invalid quantifier"); + return 0; +} + +#define ESCAPES "BbDdSsWw^$\\.*+?()[]{}|0123456789" + +static int isunicodeletter(int c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || isalpharune(c); +} + +static int nextrune(struct cstate *g) +{ + if (!*g->source) { + g->yychar = EOF; + return 0; + } + g->source += chartorune(&g->yychar, g->source); + if (g->yychar == '\\') { + if (!*g->source) + die(g, "unterminated escape sequence"); + g->source += chartorune(&g->yychar, g->source); + switch (g->yychar) { + case 'f': g->yychar = '\f'; return 0; + case 'n': g->yychar = '\n'; return 0; + case 'r': g->yychar = '\r'; return 0; + case 't': g->yychar = '\t'; return 0; + case 'v': g->yychar = '\v'; return 0; + case 'c': + if (!g->source[0]) + die(g, "unterminated escape sequence"); + g->yychar = (*g->source++) & 31; + return 0; + case 'x': + if (!g->source[0] || !g->source[1]) + die(g, "unterminated escape sequence"); + g->yychar = hex(g, *g->source++) << 4; + g->yychar += hex(g, *g->source++); + if (g->yychar == 0) { + g->yychar = '0'; + return 1; + } + return 0; + case 'u': + if (!g->source[0] || !g->source[1] || !g->source[2] || !g->source[3]) + die(g, "unterminated escape sequence"); + g->yychar = hex(g, *g->source++) << 12; + g->yychar += hex(g, *g->source++) << 8; + g->yychar += hex(g, *g->source++) << 4; + g->yychar += hex(g, *g->source++); + if (g->yychar == 0) { + g->yychar = '0'; + return 1; + } + return 0; + case 0: + g->yychar = '0'; + return 1; + } + if (strchr(ESCAPES, g->yychar)) + return 1; + if (isunicodeletter(g->yychar) || g->yychar == '_') /* check identity escape */ + die(g, "invalid escape character"); + return 0; + } + return 0; +} + +static int lexcount(struct cstate *g) +{ + g->yychar = *g->source++; + + g->yymin = dec(g, g->yychar); + g->yychar = *g->source++; + while (g->yychar != ',' && g->yychar != '}') { + g->yymin = g->yymin * 10 + dec(g, g->yychar); + g->yychar = *g->source++; + if (g->yymin >= REPINF) + die(g, "numeric overflow"); + } + + if (g->yychar == ',') { + g->yychar = *g->source++; + if (g->yychar == '}') { + g->yymax = REPINF; + } else { + g->yymax = dec(g, g->yychar); + g->yychar = *g->source++; + while (g->yychar != '}') { + g->yymax = g->yymax * 10 + dec(g, g->yychar); + g->yychar = *g->source++; + if (g->yymax >= REPINF) + die(g, "numeric overflow"); + } + } + } else { + g->yymax = g->yymin; + } + + return L_COUNT; +} + +static void newcclass(struct cstate *g) +{ + if (g->ncclass >= nelem(g->prog->cclass)) + die(g, "too many character classes"); + g->yycc = g->prog->cclass + g->ncclass++; + g->yycc->end = g->yycc->spans; +} + +static void addrange(struct cstate *g, Rune a, Rune b) +{ + if (a > b) + die(g, "invalid character class range"); + if (g->yycc->end + 2 >= g->yycc->spans + nelem(g->yycc->spans)) + die(g, "too many character class ranges"); + *g->yycc->end++ = a; + *g->yycc->end++ = b; +} + +static void addranges_d(struct cstate *g) +{ + addrange(g, '0', '9'); +} + +static void addranges_D(struct cstate *g) +{ + addrange(g, 0, '0'-1); + addrange(g, '9'+1, 0xFFFF); +} + +static void addranges_s(struct cstate *g) +{ + addrange(g, 0x9, 0xD); + addrange(g, 0x20, 0x20); + addrange(g, 0xA0, 0xA0); + addrange(g, 0x2028, 0x2029); + addrange(g, 0xFEFF, 0xFEFF); +} + +static void addranges_S(struct cstate *g) +{ + addrange(g, 0, 0x9-1); + addrange(g, 0xD+1, 0x20-1); + addrange(g, 0x20+1, 0xA0-1); + addrange(g, 0xA0+1, 0x2028-1); + addrange(g, 0x2029+1, 0xFEFF-1); + addrange(g, 0xFEFF+1, 0xFFFF); +} + +static void addranges_w(struct cstate *g) +{ + addrange(g, '0', '9'); + addrange(g, 'A', 'Z'); + addrange(g, '_', '_'); + addrange(g, 'a', 'z'); +} + +static void addranges_W(struct cstate *g) +{ + addrange(g, 0, '0'-1); + addrange(g, '9'+1, 'A'-1); + addrange(g, 'Z'+1, '_'-1); + addrange(g, '_'+1, 'a'-1); + addrange(g, 'z'+1, 0xFFFF); +} + +static int lexclass(struct cstate *g) +{ + int type = L_CCLASS; + int quoted, havesave, havedash; + Rune save = 0; + + newcclass(g); + + quoted = nextrune(g); + if (!quoted && g->yychar == '^') { + type = L_NCCLASS; + quoted = nextrune(g); + } + + havesave = havedash = 0; + for (;;) { + if (g->yychar == EOF) + die(g, "unterminated character class"); + if (!quoted && g->yychar == ']') + break; + + if (!quoted && g->yychar == '-') { + if (havesave) { + if (havedash) { + addrange(g, save, '-'); + havesave = havedash = 0; + } else { + havedash = 1; + } + } else { + save = '-'; + havesave = 1; + } + } else if (quoted && strchr("DSWdsw", g->yychar)) { + if (havesave) { + addrange(g, save, save); + if (havedash) + addrange(g, '-', '-'); + } + switch (g->yychar) { + case 'd': addranges_d(g); break; + case 's': addranges_s(g); break; + case 'w': addranges_w(g); break; + case 'D': addranges_D(g); break; + case 'S': addranges_S(g); break; + case 'W': addranges_W(g); break; + } + havesave = havedash = 0; + } else { + if (quoted) { + if (g->yychar == 'b') + g->yychar = '\b'; + else if (g->yychar == '0') + g->yychar = 0; + /* else identity escape */ + } + if (havesave) { + if (havedash) { + addrange(g, save, g->yychar); + havesave = havedash = 0; + } else { + addrange(g, save, save); + save = g->yychar; + } + } else { + save = g->yychar; + havesave = 1; + } + } + + quoted = nextrune(g); + } + + if (havesave) { + addrange(g, save, save); + if (havedash) + addrange(g, '-', '-'); + } + + return type; +} + +static int lex(struct cstate *g) +{ + int quoted = nextrune(g); + if (quoted) { + switch (g->yychar) { + case 'b': return L_WORD; + case 'B': return L_NWORD; + case 'd': newcclass(g); addranges_d(g); return L_CCLASS; + case 's': newcclass(g); addranges_s(g); return L_CCLASS; + case 'w': newcclass(g); addranges_w(g); return L_CCLASS; + case 'D': newcclass(g); addranges_d(g); return L_NCCLASS; + case 'S': newcclass(g); addranges_s(g); return L_NCCLASS; + case 'W': newcclass(g); addranges_w(g); return L_NCCLASS; + case '0': g->yychar = 0; return L_CHAR; + } + if (g->yychar >= '0' && g->yychar <= '9') { + g->yychar -= '0'; + if (*g->source >= '0' && *g->source <= '9') + g->yychar = g->yychar * 10 + *g->source++ - '0'; + return L_REF; + } + return L_CHAR; + } + + switch (g->yychar) { + case EOF: + case '$': case ')': case '*': case '+': + case '.': case '?': case '^': case '|': + return g->yychar; + } + + if (g->yychar == '{') + return lexcount(g); + if (g->yychar == '[') + return lexclass(g); + if (g->yychar == '(') { + if (g->source[0] == '?') { + if (g->source[1] == ':') { + g->source += 2; + return L_NC; + } + if (g->source[1] == '=') { + g->source += 2; + return L_PLA; + } + if (g->source[1] == '!') { + g->source += 2; + return L_NLA; + } + } + return '('; + } + + return L_CHAR; +} + +/* Parse */ + +enum { + P_CAT, P_ALT, P_REP, + P_BOL, P_EOL, P_WORD, P_NWORD, + P_PAR, P_PLA, P_NLA, + P_ANY, P_CHAR, P_CCLASS, P_NCCLASS, + P_REF, +}; + +struct Renode { + unsigned char type; + unsigned char ng, m, n; + Rune c; + Reclass *cc; + Renode *x; + Renode *y; +}; + +static Renode *newnode(struct cstate *g, int type) +{ + Renode *node = g->pend++; + node->type = type; + node->cc = NULL; + node->c = 0; + node->ng = 0; + node->m = 0; + node->n = 0; + node->x = node->y = NULL; + return node; +} + +static int empty(Renode *node) +{ + if (!node) return 1; + switch (node->type) { + default: return 1; + case P_CAT: return empty(node->x) && empty(node->y); + case P_ALT: return empty(node->x) || empty(node->y); + case P_REP: return empty(node->x) || node->m == 0; + case P_PAR: return empty(node->x); + case P_REF: return empty(node->x); + case P_ANY: case P_CHAR: case P_CCLASS: case P_NCCLASS: return 0; + } +} + +static Renode *newrep(struct cstate *g, Renode *atom, int ng, int min, int max) +{ + Renode *rep = newnode(g, P_REP); + if (max == REPINF && empty(atom)) + die(g, "infinite loop matching the empty string"); + rep->ng = ng; + rep->m = min; + rep->n = max; + rep->x = atom; + return rep; +} + +static void next(struct cstate *g) +{ + g->lookahead = lex(g); +} + +static int accept(struct cstate *g, int t) +{ + if (g->lookahead == t) { + next(g); + return 1; + } + return 0; +} + +static Renode *parsealt(struct cstate *g); + +static Renode *parseatom(struct cstate *g) +{ + Renode *atom; + if (g->lookahead == L_CHAR) { + atom = newnode(g, P_CHAR); + atom->c = g->yychar; + next(g); + return atom; + } + if (g->lookahead == L_CCLASS) { + atom = newnode(g, P_CCLASS); + atom->cc = g->yycc; + next(g); + return atom; + } + if (g->lookahead == L_NCCLASS) { + atom = newnode(g, P_NCCLASS); + atom->cc = g->yycc; + next(g); + return atom; + } + if (g->lookahead == L_REF) { + atom = newnode(g, P_REF); + if (g->yychar == 0 || g->yychar >= g->nsub || !g->sub[g->yychar]) + die(g, "invalid back-reference"); + atom->n = g->yychar; + atom->x = g->sub[g->yychar]; + next(g); + return atom; + } + if (accept(g, '.')) + return newnode(g, P_ANY); + if (accept(g, '(')) { + atom = newnode(g, P_PAR); + if (g->nsub == REG_MAXSUB) + die(g, "too many captures"); + atom->n = g->nsub++; + atom->x = parsealt(g); + g->sub[atom->n] = atom; + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + if (accept(g, L_NC)) { + atom = parsealt(g); + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + if (accept(g, L_PLA)) { + atom = newnode(g, P_PLA); + atom->x = parsealt(g); + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + if (accept(g, L_NLA)) { + atom = newnode(g, P_NLA); + atom->x = parsealt(g); + if (!accept(g, ')')) + die(g, "unmatched '('"); + return atom; + } + die(g, "syntax error"); + return NULL; +} + +static Renode *parserep(struct cstate *g) +{ + Renode *atom; + + if (accept(g, '^')) return newnode(g, P_BOL); + if (accept(g, '$')) return newnode(g, P_EOL); + if (accept(g, L_WORD)) return newnode(g, P_WORD); + if (accept(g, L_NWORD)) return newnode(g, P_NWORD); + + atom = parseatom(g); + if (g->lookahead == L_COUNT) { + int min = g->yymin, max = g->yymax; + next(g); + if (max < min) + die(g, "invalid quantifier"); + return newrep(g, atom, accept(g, '?'), min, max); + } + if (accept(g, '*')) return newrep(g, atom, accept(g, '?'), 0, REPINF); + if (accept(g, '+')) return newrep(g, atom, accept(g, '?'), 1, REPINF); + if (accept(g, '?')) return newrep(g, atom, accept(g, '?'), 0, 1); + return atom; +} + +static Renode *parsecat(struct cstate *g) +{ + Renode *cat, *head, **tail; + if (g->lookahead != EOF && g->lookahead != '|' && g->lookahead != ')') { + /* Build a right-leaning tree by splicing in new 'cat' at the tail. */ + head = parserep(g); + tail = &head; + while (g->lookahead != EOF && g->lookahead != '|' && g->lookahead != ')') { + cat = newnode(g, P_CAT); + cat->x = *tail; + cat->y = parserep(g); + *tail = cat; + tail = &cat->y; + } + return head; + } + return NULL; +} + +static Renode *parsealt(struct cstate *g) +{ + Renode *alt, *x; + alt = parsecat(g); + while (accept(g, '|')) { + x = alt; + alt = newnode(g, P_ALT); + alt->x = x; + alt->y = parsecat(g); + } + return alt; +} + +/* Compile */ + +enum { + I_END, I_JUMP, I_SPLIT, I_PLA, I_NLA, + I_ANYNL, I_ANY, I_CHAR, I_CCLASS, I_NCCLASS, I_REF, + I_BOL, I_EOL, I_WORD, I_NWORD, + I_LPAR, I_RPAR +}; + +struct Reinst { + unsigned char opcode; + unsigned char n; + Rune c; + Reclass *cc; + Reinst *x; + Reinst *y; +}; + +static int count(struct cstate *g, Renode *node) +{ + int min, max, n; + if (!node) return 0; + switch (node->type) { + default: return 1; + case P_CAT: return count(g, node->x) + count(g, node->y); + case P_ALT: return count(g, node->x) + count(g, node->y) + 2; + case P_REP: + min = node->m; + max = node->n; + if (min == max) n = count(g, node->x) * min; + else if (max < REPINF) n = count(g, node->x) * max + (max - min); + else n = count(g, node->x) * (min + 1) + 2; + if (n < 0 || n > REG_MAXPROG) die(g, "program too large"); + return n; + case P_PAR: return count(g, node->x) + 2; + case P_PLA: return count(g, node->x) + 2; + case P_NLA: return count(g, node->x) + 2; + } +} + +static Reinst *emit(Reprog *prog, int opcode) +{ + Reinst *inst = prog->end++; + inst->opcode = opcode; + inst->n = 0; + inst->c = 0; + inst->cc = NULL; + inst->x = inst->y = NULL; + return inst; +} + +static void compile(Reprog *prog, Renode *node) +{ + Reinst *inst, *split, *jump; + int i; + +loop: + if (!node) + return; + + switch (node->type) { + case P_CAT: + compile(prog, node->x); + node = node->y; + goto loop; + + case P_ALT: + split = emit(prog, I_SPLIT); + compile(prog, node->x); + jump = emit(prog, I_JUMP); + compile(prog, node->y); + split->x = split + 1; + split->y = jump + 1; + jump->x = prog->end; + break; + + case P_REP: + inst = NULL; /* silence compiler warning. assert(node->m > 0). */ + for (i = 0; i < node->m; ++i) { + inst = prog->end; + compile(prog, node->x); + } + if (node->m == node->n) + break; + if (node->n < REPINF) { + for (i = node->m; i < node->n; ++i) { + split = emit(prog, I_SPLIT); + compile(prog, node->x); + if (node->ng) { + split->y = split + 1; + split->x = prog->end; + } else { + split->x = split + 1; + split->y = prog->end; + } + } + } else if (node->m == 0) { + split = emit(prog, I_SPLIT); + compile(prog, node->x); + jump = emit(prog, I_JUMP); + if (node->ng) { + split->y = split + 1; + split->x = prog->end; + } else { + split->x = split + 1; + split->y = prog->end; + } + jump->x = split; + } else { + split = emit(prog, I_SPLIT); + if (node->ng) { + split->y = inst; + split->x = prog->end; + } else { + split->x = inst; + split->y = prog->end; + } + } + break; + + case P_BOL: emit(prog, I_BOL); break; + case P_EOL: emit(prog, I_EOL); break; + case P_WORD: emit(prog, I_WORD); break; + case P_NWORD: emit(prog, I_NWORD); break; + + case P_PAR: + inst = emit(prog, I_LPAR); + inst->n = node->n; + compile(prog, node->x); + inst = emit(prog, I_RPAR); + inst->n = node->n; + break; + case P_PLA: + split = emit(prog, I_PLA); + compile(prog, node->x); + emit(prog, I_END); + split->x = split + 1; + split->y = prog->end; + break; + case P_NLA: + split = emit(prog, I_NLA); + compile(prog, node->x); + emit(prog, I_END); + split->x = split + 1; + split->y = prog->end; + break; + + case P_ANY: + emit(prog, I_ANY); + break; + case P_CHAR: + inst = emit(prog, I_CHAR); + inst->c = (prog->flags & REG_ICASE) ? canon(node->c) : node->c; + break; + case P_CCLASS: + inst = emit(prog, I_CCLASS); + inst->cc = node->cc; + break; + case P_NCCLASS: + inst = emit(prog, I_NCCLASS); + inst->cc = node->cc; + break; + case P_REF: + inst = emit(prog, I_REF); + inst->n = node->n; + break; + } +} + +#ifdef TEST +static void dumpnode(Renode *node) +{ + Rune *p; + if (!node) { printf("Empty"); return; } + switch (node->type) { + case P_CAT: printf("Cat("); dumpnode(node->x); printf(", "); dumpnode(node->y); printf(")"); break; + case P_ALT: printf("Alt("); dumpnode(node->x); printf(", "); dumpnode(node->y); printf(")"); break; + case P_REP: + printf(node->ng ? "NgRep(%d,%d," : "Rep(%d,%d,", node->m, node->n); + dumpnode(node->x); + printf(")"); + break; + case P_BOL: printf("Bol"); break; + case P_EOL: printf("Eol"); break; + case P_WORD: printf("Word"); break; + case P_NWORD: printf("NotWord"); break; + case P_PAR: printf("Par(%d,", node->n); dumpnode(node->x); printf(")"); break; + case P_PLA: printf("PLA("); dumpnode(node->x); printf(")"); break; + case P_NLA: printf("NLA("); dumpnode(node->x); printf(")"); break; + case P_ANY: printf("Any"); break; + case P_CHAR: printf("Char(%c)", node->c); break; + case P_CCLASS: + printf("Class("); + for (p = node->cc->spans; p < node->cc->end; p += 2) printf("%02X-%02X,", p[0], p[1]); + printf(")"); + break; + case P_NCCLASS: + printf("NotClass("); + for (p = node->cc->spans; p < node->cc->end; p += 2) printf("%02X-%02X,", p[0], p[1]); + printf(")"); + break; + case P_REF: printf("Ref(%d)", node->n); break; + } +} + +static void dumpprog(Reprog *prog) +{ + Reinst *inst; + int i; + for (i = 0, inst = prog->start; inst < prog->end; ++i, ++inst) { + printf("% 5d: ", i); + switch (inst->opcode) { + case I_END: puts("end"); break; + case I_JUMP: printf("jump %d\n", (int)(inst->x - prog->start)); break; + case I_SPLIT: printf("split %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; + case I_PLA: printf("pla %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; + case I_NLA: printf("nla %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; + case I_ANY: puts("any"); break; + case I_ANYNL: puts("anynl"); break; + case I_CHAR: printf(inst->c >= 32 && inst->c < 127 ? "char '%c'\n" : "char U+%04X\n", inst->c); break; + case I_CCLASS: puts("cclass"); break; + case I_NCCLASS: puts("ncclass"); break; + case I_REF: printf("ref %d\n", inst->n); break; + case I_BOL: puts("bol"); break; + case I_EOL: puts("eol"); break; + case I_WORD: puts("word"); break; + case I_NWORD: puts("nword"); break; + case I_LPAR: printf("lpar %d\n", inst->n); break; + case I_RPAR: printf("rpar %d\n", inst->n); break; + } + } +} +#endif + +Reprog *regcompx(void *(*alloc)(void *ctx, void *p, int n), void *ctx, + const char *pattern, int cflags, const char **errorp) +{ + struct cstate g; + Renode *node; + Reinst *split, *jump; + int i, n; + + g.pstart = NULL; + g.prog = NULL; + + if (setjmp(g.kaboom)) { + if (errorp) *errorp = g.error; + alloc(ctx, g.pstart, 0); + alloc(ctx, g.prog, 0); + return NULL; + } + + g.prog = alloc(ctx, NULL, sizeof (Reprog)); + if (!g.prog) + die(&g, "cannot allocate regular expression"); + n = strlen(pattern) * 2; + if (n > REG_MAXPROG) + die(&g, "program too large"); + if (n > 0) { + g.pstart = g.pend = alloc(ctx, NULL, sizeof (Renode) * n); + if (!g.pstart) + die(&g, "cannot allocate regular expression parse list"); + } + + g.source = pattern; + g.ncclass = 0; + g.nsub = 1; + for (i = 0; i < REG_MAXSUB; ++i) + g.sub[i] = 0; + + g.prog->flags = cflags; + + next(&g); + node = parsealt(&g); + if (g.lookahead == ')') + die(&g, "unmatched ')'"); + if (g.lookahead != EOF) + die(&g, "syntax error"); + +#ifdef TEST + dumpnode(node); + putchar('\n'); +#endif + + n = 6 + count(&g, node); + if (n < 0 || n > REG_MAXPROG) + die(&g, "program too large"); + + g.prog->nsub = g.nsub; + g.prog->start = g.prog->end = alloc(ctx, NULL, n * sizeof (Reinst)); + if (!g.prog->start) + die(&g, "cannot allocate regular expression instruction list"); + + split = emit(g.prog, I_SPLIT); + split->x = split + 3; + split->y = split + 1; + emit(g.prog, I_ANYNL); + jump = emit(g.prog, I_JUMP); + jump->x = split; + emit(g.prog, I_LPAR); + compile(g.prog, node); + emit(g.prog, I_RPAR); + emit(g.prog, I_END); + +#ifdef TEST + dumpprog(g.prog); +#endif + + alloc(ctx, g.pstart, 0); + + if (errorp) *errorp = NULL; + return g.prog; +} + +void regfreex(void *(*alloc)(void *ctx, void *p, int n), void *ctx, Reprog *prog) +{ + if (prog) { + alloc(ctx, prog->start, 0); + alloc(ctx, prog, 0); + } +} + +static void *default_alloc(void *ctx, void *p, int n) +{ + return realloc(p, (size_t)n); +} + +Reprog *regcomp(const char *pattern, int cflags, const char **errorp) +{ + return regcompx(default_alloc, NULL, pattern, cflags, errorp); +} + +void regfree(Reprog *prog) +{ + regfreex(default_alloc, NULL, prog); +} + +/* Match */ + +static int isnewline(int c) +{ + return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; +} + +static int iswordchar(int c) +{ + return c == '_' || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9'); +} + +static int incclass(Reclass *cc, Rune c) +{ + Rune *p; + for (p = cc->spans; p < cc->end; p += 2) + if (p[0] <= c && c <= p[1]) + return 1; + return 0; +} + +static int incclasscanon(Reclass *cc, Rune c) +{ + Rune *p, r; + for (p = cc->spans; p < cc->end; p += 2) + for (r = p[0]; r <= p[1]; ++r) + if (c == canon(r)) + return 1; + return 0; +} + +static int strncmpcanon(const char *a, const char *b, int n) +{ + Rune ra, rb; + int c; + while (n--) { + if (!*a) return -1; + if (!*b) return 1; + a += chartorune(&ra, a); + b += chartorune(&rb, b); + c = canon(ra) - canon(rb); + if (c) + return c; + } + return 0; +} + +static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out, int depth) +{ + Resub scratch; + int result; + int i; + Rune c; + + /* stack overflow */ + if (depth > REG_MAXREC) + return -1; + + for (;;) { + switch (pc->opcode) { + case I_END: + return 0; + case I_JUMP: + pc = pc->x; + break; + case I_SPLIT: + scratch = *out; + result = match(pc->x, sp, bol, flags, &scratch, depth+1); + if (result == -1) + return -1; + if (result == 0) { + *out = scratch; + return 0; + } + pc = pc->y; + break; + + case I_PLA: + result = match(pc->x, sp, bol, flags, out, depth+1); + if (result == -1) + return -1; + if (result == 1) + return 1; + pc = pc->y; + break; + case I_NLA: + scratch = *out; + result = match(pc->x, sp, bol, flags, &scratch, depth+1); + if (result == -1) + return -1; + if (result == 0) + return 1; + pc = pc->y; + break; + + case I_ANYNL: + if (!*sp) return 1; + sp += chartorune(&c, sp); + pc = pc + 1; + break; + case I_ANY: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (isnewline(c)) + return 1; + pc = pc + 1; + break; + case I_CHAR: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (flags & REG_ICASE) + c = canon(c); + if (c != pc->c) + return 1; + pc = pc + 1; + break; + case I_CCLASS: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (flags & REG_ICASE) { + if (!incclasscanon(pc->cc, canon(c))) + return 1; + } else { + if (!incclass(pc->cc, c)) + return 1; + } + pc = pc + 1; + break; + case I_NCCLASS: + if (!*sp) return 1; + sp += chartorune(&c, sp); + if (flags & REG_ICASE) { + if (incclasscanon(pc->cc, canon(c))) + return 1; + } else { + if (incclass(pc->cc, c)) + return 1; + } + pc = pc + 1; + break; + case I_REF: + i = out->sub[pc->n].ep - out->sub[pc->n].sp; + if (flags & REG_ICASE) { + if (strncmpcanon(sp, out->sub[pc->n].sp, i)) + return 1; + } else { + if (strncmp(sp, out->sub[pc->n].sp, i)) + return 1; + } + if (i > 0) + sp += i; + pc = pc + 1; + break; + + case I_BOL: + if (sp == bol && !(flags & REG_NOTBOL)) { + pc = pc + 1; + break; + } + if (flags & REG_NEWLINE) { + if (sp > bol && isnewline(sp[-1])) { + pc = pc + 1; + break; + } + } + return 1; + case I_EOL: + if (*sp == 0) { + pc = pc + 1; + break; + } + if (flags & REG_NEWLINE) { + if (isnewline(*sp)) { + pc = pc + 1; + break; + } + } + return 1; + case I_WORD: + i = sp > bol && iswordchar(sp[-1]); + i ^= iswordchar(sp[0]); + if (!i) + return 1; + pc = pc + 1; + break; + case I_NWORD: + i = sp > bol && iswordchar(sp[-1]); + i ^= iswordchar(sp[0]); + if (i) + return 1; + pc = pc + 1; + break; + + case I_LPAR: + out->sub[pc->n].sp = sp; + pc = pc + 1; + break; + case I_RPAR: + out->sub[pc->n].ep = sp; + pc = pc + 1; + break; + default: + return 1; + } + } +} + +int regexec(Reprog *prog, const char *sp, Resub *sub, int eflags) +{ + Resub scratch; + int i; + + if (!sub) + sub = &scratch; + + sub->nsub = prog->nsub; + for (i = 0; i < REG_MAXSUB; ++i) + sub->sub[i].sp = sub->sub[i].ep = NULL; + + return match(prog->start, sp, sp, prog->flags | eflags, sub, 0); +} + +#ifdef TEST +int main(int argc, char **argv) +{ + const char *error; + const char *s; + Reprog *p; + Resub m; + int i; + + if (argc > 1) { + p = regcomp(argv[1], 0, &error); + if (!p) { + fprintf(stderr, "regcomp: %s\n", error); + return 1; + } + + if (argc > 2) { + s = argv[2]; + printf("nsub = %d\n", p->nsub); + if (!regexec(p, s, &m, 0)) { + for (i = 0; i < m.nsub; ++i) { + int n = m.sub[i].ep - m.sub[i].sp; + if (n > 0) + printf("match %d: s=%d e=%d n=%d '%.*s'\n", i, (int)(m.sub[i].sp - s), (int)(m.sub[i].ep - s), n, n, m.sub[i].sp); + else + printf("match %d: n=0 ''\n", i); + } + } else { + printf("no match\n"); + } + } + } + + return 0; +} +#endif diff --git a/programs/develop/kosjs/libmujs/include/regexp.h b/programs/develop/kosjs/libmujs/regexp.h similarity index 100% rename from programs/develop/kosjs/libmujs/include/regexp.h rename to programs/develop/kosjs/libmujs/regexp.h diff --git a/programs/develop/kosjs/libmujs/utf.c b/programs/develop/kosjs/libmujs/utf.c new file mode 100755 index 0000000000..3c97ce392b --- /dev/null +++ b/programs/develop/kosjs/libmujs/utf.c @@ -0,0 +1,212 @@ +/* + * The authors of this software are Rob Pike and Ken Thompson. + * Copyright (c) 2002 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 AUTHORS NOR LUCENT TECHNOLOGIES MAKE + * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ +#include +#include + +#include "utf.h" + +typedef unsigned char uchar; + +enum +{ + Bit1 = 7, + Bitx = 6, + Bit2 = 5, + Bit3 = 4, + Bit4 = 3, + Bit5 = 2, + + T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ + Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ + T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ + T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ + T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */ + + Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */ + Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0000 0000 0111 1111 1111 */ + Rune3 = (1<<(Bit3+2*Bitx))-1, /* 0000 0000 1111 1111 1111 1111 */ + Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */ + + Maskx = (1< T1 + */ + c = *(uchar*)str; + if(c < Tx) { + *rune = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + c1 = *(uchar*)(str+1) ^ Tx; + if(c1 & Testx) + goto bad; + if(c < T3) { + if(c < T2) + goto bad; + l = ((c << Bitx) | c1) & Rune2; + if(l <= Rune1) + goto bad; + *rune = l; + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + c2 = *(uchar*)(str+2) ^ Tx; + if(c2 & Testx) + goto bad; + if(c < T4) { + l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; + if(l <= Rune2) + goto bad; + *rune = l; + return 3; + } + + /* + * four character sequence + * 10000-10FFFF => T4 Tx Tx Tx + */ + if(UTFmax >= 4) { + c3 = *(uchar*)(str+3) ^ Tx; + if(c3 & Testx) + goto bad; + if(c < T5) { + l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4; + if(l <= Rune3) + goto bad; + if(l > Runemax) + goto bad; + *rune = l; + return 4; + } + } + + /* + * bad decoding + */ +bad: + *rune = Bad; + return 1; +} + +int +runetochar(char *str, const Rune *rune) +{ + int c = *rune; + + /* overlong null character */ + if (c == 0) { + str[0] = (char)0xc0; + str[1] = (char)0x80; + return 2; + } + + /* + * one character sequence + * 00000-0007F => 00-7F + */ + if(c <= Rune1) { + str[0] = c; + return 1; + } + + /* + * two character sequence + * 00080-007FF => T2 Tx + */ + if(c <= Rune2) { + str[0] = T2 | (c >> 1*Bitx); + str[1] = Tx | (c & Maskx); + return 2; + } + + /* + * three character sequence + * 00800-0FFFF => T3 Tx Tx + */ + if(c > Runemax) + c = Runeerror; + if(c <= Rune3) { + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; + } + + /* + * four character sequence + * 010000-1FFFFF => T4 Tx Tx Tx + */ + str[0] = T4 | (c >> 3*Bitx); + str[1] = Tx | ((c >> 2*Bitx) & Maskx); + str[2] = Tx | ((c >> 1*Bitx) & Maskx); + str[3] = Tx | (c & Maskx); + return 4; +} + +int +runelen(int c) +{ + Rune rune; + char str[10]; + + rune = c; + return runetochar(str, &rune); +} + +int +utflen(const char *s) +{ + int c; + int n; + Rune rune; + + n = 0; + for(;;) { + c = *(uchar*)s; + if(c < Runeself) { + if(c == 0) + return n; + s++; + } else + s += chartorune(&rune, s); + n++; + } +} diff --git a/programs/develop/kosjs/libmujs/include/utf.h b/programs/develop/kosjs/libmujs/utf.h similarity index 89% rename from programs/develop/kosjs/libmujs/include/utf.h rename to programs/develop/kosjs/libmujs/utf.h index 36b299df9b..04e6bb9b5b 100755 --- a/programs/develop/kosjs/libmujs/include/utf.h +++ b/programs/develop/kosjs/libmujs/utf.h @@ -1,7 +1,7 @@ #ifndef js_utf_h #define js_utf_h -typedef unsigned short Rune; /* 16 bits */ +typedef int Rune; /* 32 bits */ #define chartorune jsU_chartorune #define runetochar jsU_runetochar @@ -19,10 +19,11 @@ typedef unsigned short Rune; /* 16 bits */ enum { - UTFmax = 3, /* maximum bytes per rune */ + UTFmax = 4, /* maximum bytes per rune */ Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ Runeself = 0x80, /* rune and UTF sequences are the same (<) */ Runeerror = 0xFFFD, /* decoding error in UTF */ + Runemax = 0x10FFFF, /* maximum rune value */ }; int chartorune(Rune *rune, const char *str); diff --git a/programs/develop/kosjs/libmujs/utftype.c b/programs/develop/kosjs/libmujs/utftype.c new file mode 100755 index 0000000000..cf30c2d3e7 --- /dev/null +++ b/programs/develop/kosjs/libmujs/utftype.c @@ -0,0 +1,1130 @@ +#include "utf.h" + +#define bsearch jsU_bsearch +#define nelem(a) (int)(sizeof (a) / sizeof (a)[0]) + +/* + * alpha ranges - + * only covers ranges not in lower||upper + */ +static const Rune __alpha2[] = +{ + 0x00d8, 0x00f6, /* Ø - ö */ + 0x00f8, 0x01f5, /* ø - ǵ */ + 0x0250, 0x02a8, /* ɐ - ʨ */ + 0x038e, 0x03a1, /* Ύ - Ρ */ + 0x03a3, 0x03ce, /* Σ - ώ */ + 0x03d0, 0x03d6, /* ϐ - ϖ */ + 0x03e2, 0x03f3, /* Ϣ - ϳ */ + 0x0490, 0x04c4, /* Ґ - ӄ */ + 0x0561, 0x0587, /* ա - և */ + 0x05d0, 0x05ea, /* א - ת */ + 0x05f0, 0x05f2, /* װ - ײ */ + 0x0621, 0x063a, /* ء - غ */ + 0x0640, 0x064a, /* ـ - ي */ + 0x0671, 0x06b7, /* ٱ - ڷ */ + 0x06ba, 0x06be, /* ں - ھ */ + 0x06c0, 0x06ce, /* ۀ - ێ */ + 0x06d0, 0x06d3, /* ې - ۓ */ + 0x0905, 0x0939, /* अ - ह */ + 0x0958, 0x0961, /* क़ - ॡ */ + 0x0985, 0x098c, /* অ - ঌ */ + 0x098f, 0x0990, /* এ - ঐ */ + 0x0993, 0x09a8, /* ও - ন */ + 0x09aa, 0x09b0, /* প - র */ + 0x09b6, 0x09b9, /* শ - হ */ + 0x09dc, 0x09dd, /* ড় - ঢ় */ + 0x09df, 0x09e1, /* য় - ৡ */ + 0x09f0, 0x09f1, /* ৰ - ৱ */ + 0x0a05, 0x0a0a, /* ਅ - ਊ */ + 0x0a0f, 0x0a10, /* ਏ - ਐ */ + 0x0a13, 0x0a28, /* ਓ - ਨ */ + 0x0a2a, 0x0a30, /* ਪ - ਰ */ + 0x0a32, 0x0a33, /* ਲ - ਲ਼ */ + 0x0a35, 0x0a36, /* ਵ - ਸ਼ */ + 0x0a38, 0x0a39, /* ਸ - ਹ */ + 0x0a59, 0x0a5c, /* ਖ਼ - ੜ */ + 0x0a85, 0x0a8b, /* અ - ઋ */ + 0x0a8f, 0x0a91, /* એ - ઑ */ + 0x0a93, 0x0aa8, /* ઓ - ન */ + 0x0aaa, 0x0ab0, /* પ - ર */ + 0x0ab2, 0x0ab3, /* લ - ળ */ + 0x0ab5, 0x0ab9, /* વ - હ */ + 0x0b05, 0x0b0c, /* ଅ - ଌ */ + 0x0b0f, 0x0b10, /* ଏ - ଐ */ + 0x0b13, 0x0b28, /* ଓ - ନ */ + 0x0b2a, 0x0b30, /* ପ - ର */ + 0x0b32, 0x0b33, /* ଲ - ଳ */ + 0x0b36, 0x0b39, /* ଶ - ହ */ + 0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */ + 0x0b5f, 0x0b61, /* ୟ - ୡ */ + 0x0b85, 0x0b8a, /* அ - ஊ */ + 0x0b8e, 0x0b90, /* எ - ஐ */ + 0x0b92, 0x0b95, /* ஒ - க */ + 0x0b99, 0x0b9a, /* ங - ச */ + 0x0b9e, 0x0b9f, /* ஞ - ட */ + 0x0ba3, 0x0ba4, /* ண - த */ + 0x0ba8, 0x0baa, /* ந - ப */ + 0x0bae, 0x0bb5, /* ம - வ */ + 0x0bb7, 0x0bb9, /* ஷ - ஹ */ + 0x0c05, 0x0c0c, /* అ - ఌ */ + 0x0c0e, 0x0c10, /* ఎ - ఐ */ + 0x0c12, 0x0c28, /* ఒ - న */ + 0x0c2a, 0x0c33, /* ప - ళ */ + 0x0c35, 0x0c39, /* వ - హ */ + 0x0c60, 0x0c61, /* ౠ - ౡ */ + 0x0c85, 0x0c8c, /* ಅ - ಌ */ + 0x0c8e, 0x0c90, /* ಎ - ಐ */ + 0x0c92, 0x0ca8, /* ಒ - ನ */ + 0x0caa, 0x0cb3, /* ಪ - ಳ */ + 0x0cb5, 0x0cb9, /* ವ - ಹ */ + 0x0ce0, 0x0ce1, /* ೠ - ೡ */ + 0x0d05, 0x0d0c, /* അ - ഌ */ + 0x0d0e, 0x0d10, /* എ - ഐ */ + 0x0d12, 0x0d28, /* ഒ - ന */ + 0x0d2a, 0x0d39, /* പ - ഹ */ + 0x0d60, 0x0d61, /* ൠ - ൡ */ + 0x0e01, 0x0e30, /* ก - ะ */ + 0x0e32, 0x0e33, /* า - ำ */ + 0x0e40, 0x0e46, /* เ - ๆ */ + 0x0e5a, 0x0e5b, /* ๚ - ๛ */ + 0x0e81, 0x0e82, /* ກ - ຂ */ + 0x0e87, 0x0e88, /* ງ - ຈ */ + 0x0e94, 0x0e97, /* ດ - ທ */ + 0x0e99, 0x0e9f, /* ນ - ຟ */ + 0x0ea1, 0x0ea3, /* ມ - ຣ */ + 0x0eaa, 0x0eab, /* ສ - ຫ */ + 0x0ead, 0x0eae, /* ອ - ຮ */ + 0x0eb2, 0x0eb3, /* າ - ຳ */ + 0x0ec0, 0x0ec4, /* ເ - ໄ */ + 0x0edc, 0x0edd, /* ໜ - ໝ */ + 0x0f18, 0x0f19, /* ༘ - ༙ */ + 0x0f40, 0x0f47, /* ཀ - ཇ */ + 0x0f49, 0x0f69, /* ཉ - ཀྵ */ + 0x10d0, 0x10f6, /* ა - ჶ */ + 0x1100, 0x1159, /* ᄀ - ᅙ */ + 0x115f, 0x11a2, /* ᅟ - ᆢ */ + 0x11a8, 0x11f9, /* ᆨ - ᇹ */ + 0x1e00, 0x1e9b, /* Ḁ - ẛ */ + 0x1f50, 0x1f57, /* ὐ - ὗ */ + 0x1f80, 0x1fb4, /* ᾀ - ᾴ */ + 0x1fb6, 0x1fbc, /* ᾶ - ᾼ */ + 0x1fc2, 0x1fc4, /* ῂ - ῄ */ + 0x1fc6, 0x1fcc, /* ῆ - ῌ */ + 0x1fd0, 0x1fd3, /* ῐ - ΐ */ + 0x1fd6, 0x1fdb, /* ῖ - Ί */ + 0x1fe0, 0x1fec, /* ῠ - Ῥ */ + 0x1ff2, 0x1ff4, /* ῲ - ῴ */ + 0x1ff6, 0x1ffc, /* ῶ - ῼ */ + 0x210a, 0x2113, /* ℊ - ℓ */ + 0x2115, 0x211d, /* ℕ - ℝ */ + 0x2120, 0x2122, /* ℠ - ™ */ + 0x212a, 0x2131, /* K - ℱ */ + 0x2133, 0x2138, /* ℳ - ℸ */ + 0x3041, 0x3094, /* ぁ - ゔ */ + 0x30a1, 0x30fa, /* ァ - ヺ */ + 0x3105, 0x312c, /* ㄅ - ㄬ */ + 0x3131, 0x318e, /* ㄱ - ㆎ */ + 0x3192, 0x319f, /* ㆒ - ㆟ */ + 0x3260, 0x327b, /* ㉠ - ㉻ */ + 0x328a, 0x32b0, /* ㊊ - ㊰ */ + 0x32d0, 0x32fe, /* ㋐ - ㋾ */ + 0x3300, 0x3357, /* ㌀ - ㍗ */ + 0x3371, 0x3376, /* ㍱ - ㍶ */ + 0x337b, 0x3394, /* ㍻ - ㎔ */ + 0x3399, 0x339e, /* ㎙ - ㎞ */ + 0x33a9, 0x33ad, /* ㎩ - ㎭ */ + 0x33b0, 0x33c1, /* ㎰ - ㏁ */ + 0x33c3, 0x33c5, /* ㏃ - ㏅ */ + 0x33c7, 0x33d7, /* ㏇ - ㏗ */ + 0x33d9, 0x33dd, /* ㏙ - ㏝ */ + 0x4e00, 0x9fff, /* 一 - 鿿 */ + 0xac00, 0xd7a3, /* 가 - 힣 */ + 0xf900, 0xfb06, /* 豈 - st */ + 0xfb13, 0xfb17, /* ﬓ - ﬗ */ + 0xfb1f, 0xfb28, /* ײַ - ﬨ */ + 0xfb2a, 0xfb36, /* שׁ - זּ */ + 0xfb38, 0xfb3c, /* טּ - לּ */ + 0xfb40, 0xfb41, /* נּ - סּ */ + 0xfb43, 0xfb44, /* ףּ - פּ */ + 0xfb46, 0xfbb1, /* צּ - ﮱ */ + 0xfbd3, 0xfd3d, /* ﯓ - ﴽ */ + 0xfd50, 0xfd8f, /* ﵐ - ﶏ */ + 0xfd92, 0xfdc7, /* ﶒ - ﷇ */ + 0xfdf0, 0xfdf9, /* ﷰ - ﷹ */ + 0xfe70, 0xfe72, /* ﹰ - ﹲ */ + 0xfe76, 0xfefc, /* ﹶ - ﻼ */ + 0xff66, 0xff6f, /* ヲ - ッ */ + 0xff71, 0xff9d, /* ア - ン */ + 0xffa0, 0xffbe, /* ᅠ - ᄒ */ + 0xffc2, 0xffc7, /* ᅡ - ᅦ */ + 0xffca, 0xffcf, /* ᅧ - ᅬ */ + 0xffd2, 0xffd7, /* ᅭ - ᅲ */ + 0xffda, 0xffdc, /* ᅳ - ᅵ */ +}; + +/* + * alpha singlets - + * only covers ranges not in lower||upper + */ +static const Rune __alpha1[] = +{ + 0x00aa, /* ª */ + 0x00b5, /* µ */ + 0x00ba, /* º */ + 0x03da, /* Ϛ */ + 0x03dc, /* Ϝ */ + 0x03de, /* Ϟ */ + 0x03e0, /* Ϡ */ + 0x06d5, /* ە */ + 0x09b2, /* ল */ + 0x0a5e, /* ਫ਼ */ + 0x0a8d, /* ઍ */ + 0x0ae0, /* ૠ */ + 0x0b9c, /* ஜ */ + 0x0cde, /* ೞ */ + 0x0e4f, /* ๏ */ + 0x0e84, /* ຄ */ + 0x0e8a, /* ຊ */ + 0x0e8d, /* ຍ */ + 0x0ea5, /* ລ */ + 0x0ea7, /* ວ */ + 0x0eb0, /* ະ */ + 0x0ebd, /* ຽ */ + 0x1fbe, /* ι */ + 0x207f, /* ⁿ */ + 0x20a8, /* ₨ */ + 0x2102, /* ℂ */ + 0x2107, /* ℇ */ + 0x2124, /* ℤ */ + 0x2126, /* Ω */ + 0x2128, /* ℨ */ + 0xfb3e, /* מּ */ + 0xfe74, /* ﹴ */ +}; + +/* + * space ranges + */ +static const Rune __space2[] = +{ + 0x0009, 0x000a, /* tab and newline */ + 0x0020, 0x0020, /* space */ + 0x00a0, 0x00a0, /*   */ + 0x2000, 0x200b, /*   - ​ */ + 0x2028, 0x2029, /* 
 - 
 */ + 0x3000, 0x3000, /*   */ + 0xfeff, 0xfeff, /*  */ +}; + +/* + * lower case ranges + * 3rd col is conversion excess 500 + */ +static const Rune __toupper2[] = +{ + 0x0061, 0x007a, 468, /* a-z A-Z */ + 0x00e0, 0x00f6, 468, /* à-ö À-Ö */ + 0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */ + 0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */ + 0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */ + 0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */ + 0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */ + 0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */ + 0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */ + 0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */ + 0x0430, 0x044f, 468, /* а-я А-Я */ + 0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */ + 0x045e, 0x045f, 420, /* ў-џ Ў-Џ */ + 0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */ + 0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */ + 0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */ + 0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */ + 0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */ + 0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */ + 0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */ + 0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */ + 0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */ + 0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */ + 0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */ + 0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */ + 0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */ + 0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */ + 0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */ + 0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */ + 0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */ + 0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */ + 0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */ + 0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */ + 0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */ + 0xff41, 0xff5a, 468, /* a-z A-Z */ +}; + +/* + * lower case singlets + * 2nd col is conversion excess 500 + */ +static const Rune __toupper1[] = +{ + 0x00ff, 621, /* ÿ Ÿ */ + 0x0101, 499, /* ā Ā */ + 0x0103, 499, /* ă Ă */ + 0x0105, 499, /* ą Ą */ + 0x0107, 499, /* ć Ć */ + 0x0109, 499, /* ĉ Ĉ */ + 0x010b, 499, /* ċ Ċ */ + 0x010d, 499, /* č Č */ + 0x010f, 499, /* ď Ď */ + 0x0111, 499, /* đ Đ */ + 0x0113, 499, /* ē Ē */ + 0x0115, 499, /* ĕ Ĕ */ + 0x0117, 499, /* ė Ė */ + 0x0119, 499, /* ę Ę */ + 0x011b, 499, /* ě Ě */ + 0x011d, 499, /* ĝ Ĝ */ + 0x011f, 499, /* ğ Ğ */ + 0x0121, 499, /* ġ Ġ */ + 0x0123, 499, /* ģ Ģ */ + 0x0125, 499, /* ĥ Ĥ */ + 0x0127, 499, /* ħ Ħ */ + 0x0129, 499, /* ĩ Ĩ */ + 0x012b, 499, /* ī Ī */ + 0x012d, 499, /* ĭ Ĭ */ + 0x012f, 499, /* į Į */ + 0x0131, 268, /* ı I */ + 0x0133, 499, /* ij IJ */ + 0x0135, 499, /* ĵ Ĵ */ + 0x0137, 499, /* ķ Ķ */ + 0x013a, 499, /* ĺ Ĺ */ + 0x013c, 499, /* ļ Ļ */ + 0x013e, 499, /* ľ Ľ */ + 0x0140, 499, /* ŀ Ŀ */ + 0x0142, 499, /* ł Ł */ + 0x0144, 499, /* ń Ń */ + 0x0146, 499, /* ņ Ņ */ + 0x0148, 499, /* ň Ň */ + 0x014b, 499, /* ŋ Ŋ */ + 0x014d, 499, /* ō Ō */ + 0x014f, 499, /* ŏ Ŏ */ + 0x0151, 499, /* ő Ő */ + 0x0153, 499, /* œ Œ */ + 0x0155, 499, /* ŕ Ŕ */ + 0x0157, 499, /* ŗ Ŗ */ + 0x0159, 499, /* ř Ř */ + 0x015b, 499, /* ś Ś */ + 0x015d, 499, /* ŝ Ŝ */ + 0x015f, 499, /* ş Ş */ + 0x0161, 499, /* š Š */ + 0x0163, 499, /* ţ Ţ */ + 0x0165, 499, /* ť Ť */ + 0x0167, 499, /* ŧ Ŧ */ + 0x0169, 499, /* ũ Ũ */ + 0x016b, 499, /* ū Ū */ + 0x016d, 499, /* ŭ Ŭ */ + 0x016f, 499, /* ů Ů */ + 0x0171, 499, /* ű Ű */ + 0x0173, 499, /* ų Ų */ + 0x0175, 499, /* ŵ Ŵ */ + 0x0177, 499, /* ŷ Ŷ */ + 0x017a, 499, /* ź Ź */ + 0x017c, 499, /* ż Ż */ + 0x017e, 499, /* ž Ž */ + 0x017f, 200, /* ſ S */ + 0x0183, 499, /* ƃ Ƃ */ + 0x0185, 499, /* ƅ Ƅ */ + 0x0188, 499, /* ƈ Ƈ */ + 0x018c, 499, /* ƌ Ƌ */ + 0x0192, 499, /* ƒ Ƒ */ + 0x0199, 499, /* ƙ Ƙ */ + 0x01a1, 499, /* ơ Ơ */ + 0x01a3, 499, /* ƣ Ƣ */ + 0x01a5, 499, /* ƥ Ƥ */ + 0x01a8, 499, /* ƨ Ƨ */ + 0x01ad, 499, /* ƭ Ƭ */ + 0x01b0, 499, /* ư Ư */ + 0x01b4, 499, /* ƴ Ƴ */ + 0x01b6, 499, /* ƶ Ƶ */ + 0x01b9, 499, /* ƹ Ƹ */ + 0x01bd, 499, /* ƽ Ƽ */ + 0x01c5, 499, /* Dž DŽ */ + 0x01c6, 498, /* dž DŽ */ + 0x01c8, 499, /* Lj LJ */ + 0x01c9, 498, /* lj LJ */ + 0x01cb, 499, /* Nj NJ */ + 0x01cc, 498, /* nj NJ */ + 0x01ce, 499, /* ǎ Ǎ */ + 0x01d0, 499, /* ǐ Ǐ */ + 0x01d2, 499, /* ǒ Ǒ */ + 0x01d4, 499, /* ǔ Ǔ */ + 0x01d6, 499, /* ǖ Ǖ */ + 0x01d8, 499, /* ǘ Ǘ */ + 0x01da, 499, /* ǚ Ǚ */ + 0x01dc, 499, /* ǜ Ǜ */ + 0x01df, 499, /* ǟ Ǟ */ + 0x01e1, 499, /* ǡ Ǡ */ + 0x01e3, 499, /* ǣ Ǣ */ + 0x01e5, 499, /* ǥ Ǥ */ + 0x01e7, 499, /* ǧ Ǧ */ + 0x01e9, 499, /* ǩ Ǩ */ + 0x01eb, 499, /* ǫ Ǫ */ + 0x01ed, 499, /* ǭ Ǭ */ + 0x01ef, 499, /* ǯ Ǯ */ + 0x01f2, 499, /* Dz DZ */ + 0x01f3, 498, /* dz DZ */ + 0x01f5, 499, /* ǵ Ǵ */ + 0x01fb, 499, /* ǻ Ǻ */ + 0x01fd, 499, /* ǽ Ǽ */ + 0x01ff, 499, /* ǿ Ǿ */ + 0x0201, 499, /* ȁ Ȁ */ + 0x0203, 499, /* ȃ Ȃ */ + 0x0205, 499, /* ȅ Ȅ */ + 0x0207, 499, /* ȇ Ȇ */ + 0x0209, 499, /* ȉ Ȉ */ + 0x020b, 499, /* ȋ Ȋ */ + 0x020d, 499, /* ȍ Ȍ */ + 0x020f, 499, /* ȏ Ȏ */ + 0x0211, 499, /* ȑ Ȑ */ + 0x0213, 499, /* ȓ Ȓ */ + 0x0215, 499, /* ȕ Ȕ */ + 0x0217, 499, /* ȗ Ȗ */ + 0x0253, 290, /* ɓ Ɓ */ + 0x0254, 294, /* ɔ Ɔ */ + 0x025b, 297, /* ɛ Ɛ */ + 0x0260, 295, /* ɠ Ɠ */ + 0x0263, 293, /* ɣ Ɣ */ + 0x0268, 291, /* ɨ Ɨ */ + 0x0269, 289, /* ɩ Ɩ */ + 0x026f, 289, /* ɯ Ɯ */ + 0x0272, 287, /* ɲ Ɲ */ + 0x0283, 282, /* ʃ Ʃ */ + 0x0288, 282, /* ʈ Ʈ */ + 0x0292, 281, /* ʒ Ʒ */ + 0x03ac, 462, /* ά Ά */ + 0x03cc, 436, /* ό Ό */ + 0x03d0, 438, /* ϐ Β */ + 0x03d1, 443, /* ϑ Θ */ + 0x03d5, 453, /* ϕ Φ */ + 0x03d6, 446, /* ϖ Π */ + 0x03e3, 499, /* ϣ Ϣ */ + 0x03e5, 499, /* ϥ Ϥ */ + 0x03e7, 499, /* ϧ Ϧ */ + 0x03e9, 499, /* ϩ Ϩ */ + 0x03eb, 499, /* ϫ Ϫ */ + 0x03ed, 499, /* ϭ Ϭ */ + 0x03ef, 499, /* ϯ Ϯ */ + 0x03f0, 414, /* ϰ Κ */ + 0x03f1, 420, /* ϱ Ρ */ + 0x0461, 499, /* ѡ Ѡ */ + 0x0463, 499, /* ѣ Ѣ */ + 0x0465, 499, /* ѥ Ѥ */ + 0x0467, 499, /* ѧ Ѧ */ + 0x0469, 499, /* ѩ Ѩ */ + 0x046b, 499, /* ѫ Ѫ */ + 0x046d, 499, /* ѭ Ѭ */ + 0x046f, 499, /* ѯ Ѯ */ + 0x0471, 499, /* ѱ Ѱ */ + 0x0473, 499, /* ѳ Ѳ */ + 0x0475, 499, /* ѵ Ѵ */ + 0x0477, 499, /* ѷ Ѷ */ + 0x0479, 499, /* ѹ Ѹ */ + 0x047b, 499, /* ѻ Ѻ */ + 0x047d, 499, /* ѽ Ѽ */ + 0x047f, 499, /* ѿ Ѿ */ + 0x0481, 499, /* ҁ Ҁ */ + 0x0491, 499, /* ґ Ґ */ + 0x0493, 499, /* ғ Ғ */ + 0x0495, 499, /* ҕ Ҕ */ + 0x0497, 499, /* җ Җ */ + 0x0499, 499, /* ҙ Ҙ */ + 0x049b, 499, /* қ Қ */ + 0x049d, 499, /* ҝ Ҝ */ + 0x049f, 499, /* ҟ Ҟ */ + 0x04a1, 499, /* ҡ Ҡ */ + 0x04a3, 499, /* ң Ң */ + 0x04a5, 499, /* ҥ Ҥ */ + 0x04a7, 499, /* ҧ Ҧ */ + 0x04a9, 499, /* ҩ Ҩ */ + 0x04ab, 499, /* ҫ Ҫ */ + 0x04ad, 499, /* ҭ Ҭ */ + 0x04af, 499, /* ү Ү */ + 0x04b1, 499, /* ұ Ұ */ + 0x04b3, 499, /* ҳ Ҳ */ + 0x04b5, 499, /* ҵ Ҵ */ + 0x04b7, 499, /* ҷ Ҷ */ + 0x04b9, 499, /* ҹ Ҹ */ + 0x04bb, 499, /* һ Һ */ + 0x04bd, 499, /* ҽ Ҽ */ + 0x04bf, 499, /* ҿ Ҿ */ + 0x04c2, 499, /* ӂ Ӂ */ + 0x04c4, 499, /* ӄ Ӄ */ + 0x04c8, 499, /* ӈ Ӈ */ + 0x04cc, 499, /* ӌ Ӌ */ + 0x04d1, 499, /* ӑ Ӑ */ + 0x04d3, 499, /* ӓ Ӓ */ + 0x04d5, 499, /* ӕ Ӕ */ + 0x04d7, 499, /* ӗ Ӗ */ + 0x04d9, 499, /* ә Ә */ + 0x04db, 499, /* ӛ Ӛ */ + 0x04dd, 499, /* ӝ Ӝ */ + 0x04df, 499, /* ӟ Ӟ */ + 0x04e1, 499, /* ӡ Ӡ */ + 0x04e3, 499, /* ӣ Ӣ */ + 0x04e5, 499, /* ӥ Ӥ */ + 0x04e7, 499, /* ӧ Ӧ */ + 0x04e9, 499, /* ө Ө */ + 0x04eb, 499, /* ӫ Ӫ */ + 0x04ef, 499, /* ӯ Ӯ */ + 0x04f1, 499, /* ӱ Ӱ */ + 0x04f3, 499, /* ӳ Ӳ */ + 0x04f5, 499, /* ӵ Ӵ */ + 0x04f9, 499, /* ӹ Ӹ */ + 0x1e01, 499, /* ḁ Ḁ */ + 0x1e03, 499, /* ḃ Ḃ */ + 0x1e05, 499, /* ḅ Ḅ */ + 0x1e07, 499, /* ḇ Ḇ */ + 0x1e09, 499, /* ḉ Ḉ */ + 0x1e0b, 499, /* ḋ Ḋ */ + 0x1e0d, 499, /* ḍ Ḍ */ + 0x1e0f, 499, /* ḏ Ḏ */ + 0x1e11, 499, /* ḑ Ḑ */ + 0x1e13, 499, /* ḓ Ḓ */ + 0x1e15, 499, /* ḕ Ḕ */ + 0x1e17, 499, /* ḗ Ḗ */ + 0x1e19, 499, /* ḙ Ḙ */ + 0x1e1b, 499, /* ḛ Ḛ */ + 0x1e1d, 499, /* ḝ Ḝ */ + 0x1e1f, 499, /* ḟ Ḟ */ + 0x1e21, 499, /* ḡ Ḡ */ + 0x1e23, 499, /* ḣ Ḣ */ + 0x1e25, 499, /* ḥ Ḥ */ + 0x1e27, 499, /* ḧ Ḧ */ + 0x1e29, 499, /* ḩ Ḩ */ + 0x1e2b, 499, /* ḫ Ḫ */ + 0x1e2d, 499, /* ḭ Ḭ */ + 0x1e2f, 499, /* ḯ Ḯ */ + 0x1e31, 499, /* ḱ Ḱ */ + 0x1e33, 499, /* ḳ Ḳ */ + 0x1e35, 499, /* ḵ Ḵ */ + 0x1e37, 499, /* ḷ Ḷ */ + 0x1e39, 499, /* ḹ Ḹ */ + 0x1e3b, 499, /* ḻ Ḻ */ + 0x1e3d, 499, /* ḽ Ḽ */ + 0x1e3f, 499, /* ḿ Ḿ */ + 0x1e41, 499, /* ṁ Ṁ */ + 0x1e43, 499, /* ṃ Ṃ */ + 0x1e45, 499, /* ṅ Ṅ */ + 0x1e47, 499, /* ṇ Ṇ */ + 0x1e49, 499, /* ṉ Ṉ */ + 0x1e4b, 499, /* ṋ Ṋ */ + 0x1e4d, 499, /* ṍ Ṍ */ + 0x1e4f, 499, /* ṏ Ṏ */ + 0x1e51, 499, /* ṑ Ṑ */ + 0x1e53, 499, /* ṓ Ṓ */ + 0x1e55, 499, /* ṕ Ṕ */ + 0x1e57, 499, /* ṗ Ṗ */ + 0x1e59, 499, /* ṙ Ṙ */ + 0x1e5b, 499, /* ṛ Ṛ */ + 0x1e5d, 499, /* ṝ Ṝ */ + 0x1e5f, 499, /* ṟ Ṟ */ + 0x1e61, 499, /* ṡ Ṡ */ + 0x1e63, 499, /* ṣ Ṣ */ + 0x1e65, 499, /* ṥ Ṥ */ + 0x1e67, 499, /* ṧ Ṧ */ + 0x1e69, 499, /* ṩ Ṩ */ + 0x1e6b, 499, /* ṫ Ṫ */ + 0x1e6d, 499, /* ṭ Ṭ */ + 0x1e6f, 499, /* ṯ Ṯ */ + 0x1e71, 499, /* ṱ Ṱ */ + 0x1e73, 499, /* ṳ Ṳ */ + 0x1e75, 499, /* ṵ Ṵ */ + 0x1e77, 499, /* ṷ Ṷ */ + 0x1e79, 499, /* ṹ Ṹ */ + 0x1e7b, 499, /* ṻ Ṻ */ + 0x1e7d, 499, /* ṽ Ṽ */ + 0x1e7f, 499, /* ṿ Ṿ */ + 0x1e81, 499, /* ẁ Ẁ */ + 0x1e83, 499, /* ẃ Ẃ */ + 0x1e85, 499, /* ẅ Ẅ */ + 0x1e87, 499, /* ẇ Ẇ */ + 0x1e89, 499, /* ẉ Ẉ */ + 0x1e8b, 499, /* ẋ Ẋ */ + 0x1e8d, 499, /* ẍ Ẍ */ + 0x1e8f, 499, /* ẏ Ẏ */ + 0x1e91, 499, /* ẑ Ẑ */ + 0x1e93, 499, /* ẓ Ẓ */ + 0x1e95, 499, /* ẕ Ẕ */ + 0x1ea1, 499, /* ạ Ạ */ + 0x1ea3, 499, /* ả Ả */ + 0x1ea5, 499, /* ấ Ấ */ + 0x1ea7, 499, /* ầ Ầ */ + 0x1ea9, 499, /* ẩ Ẩ */ + 0x1eab, 499, /* ẫ Ẫ */ + 0x1ead, 499, /* ậ Ậ */ + 0x1eaf, 499, /* ắ Ắ */ + 0x1eb1, 499, /* ằ Ằ */ + 0x1eb3, 499, /* ẳ Ẳ */ + 0x1eb5, 499, /* ẵ Ẵ */ + 0x1eb7, 499, /* ặ Ặ */ + 0x1eb9, 499, /* ẹ Ẹ */ + 0x1ebb, 499, /* ẻ Ẻ */ + 0x1ebd, 499, /* ẽ Ẽ */ + 0x1ebf, 499, /* ế Ế */ + 0x1ec1, 499, /* ề Ề */ + 0x1ec3, 499, /* ể Ể */ + 0x1ec5, 499, /* ễ Ễ */ + 0x1ec7, 499, /* ệ Ệ */ + 0x1ec9, 499, /* ỉ Ỉ */ + 0x1ecb, 499, /* ị Ị */ + 0x1ecd, 499, /* ọ Ọ */ + 0x1ecf, 499, /* ỏ Ỏ */ + 0x1ed1, 499, /* ố Ố */ + 0x1ed3, 499, /* ồ Ồ */ + 0x1ed5, 499, /* ổ Ổ */ + 0x1ed7, 499, /* ỗ Ỗ */ + 0x1ed9, 499, /* ộ Ộ */ + 0x1edb, 499, /* ớ Ớ */ + 0x1edd, 499, /* ờ Ờ */ + 0x1edf, 499, /* ở Ở */ + 0x1ee1, 499, /* ỡ Ỡ */ + 0x1ee3, 499, /* ợ Ợ */ + 0x1ee5, 499, /* ụ Ụ */ + 0x1ee7, 499, /* ủ Ủ */ + 0x1ee9, 499, /* ứ Ứ */ + 0x1eeb, 499, /* ừ Ừ */ + 0x1eed, 499, /* ử Ử */ + 0x1eef, 499, /* ữ Ữ */ + 0x1ef1, 499, /* ự Ự */ + 0x1ef3, 499, /* ỳ Ỳ */ + 0x1ef5, 499, /* ỵ Ỵ */ + 0x1ef7, 499, /* ỷ Ỷ */ + 0x1ef9, 499, /* ỹ Ỹ */ + 0x1f51, 508, /* ὑ Ὑ */ + 0x1f53, 508, /* ὓ Ὓ */ + 0x1f55, 508, /* ὕ Ὕ */ + 0x1f57, 508, /* ὗ Ὗ */ + 0x1fb3, 509, /* ᾳ ᾼ */ + 0x1fc3, 509, /* ῃ ῌ */ + 0x1fe5, 507, /* ῥ Ῥ */ + 0x1ff3, 509, /* ῳ ῼ */ +}; + +/* + * upper case ranges + * 3rd col is conversion excess 500 + */ +static const Rune __tolower2[] = +{ + 0x0041, 0x005a, 532, /* A-Z a-z */ + 0x00c0, 0x00d6, 532, /* À-Ö à-ö */ + 0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */ + 0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */ + 0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */ + 0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */ + 0x0388, 0x038a, 537, /* Έ-Ί έ-ί */ + 0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */ + 0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */ + 0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */ + 0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */ + 0x040e, 0x040f, 580, /* Ў-Џ ў-џ */ + 0x0410, 0x042f, 532, /* А-Я а-я */ + 0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */ + 0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */ + 0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */ + 0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */ + 0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */ + 0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */ + 0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */ + 0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */ + 0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */ + 0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */ + 0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */ + 0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */ + 0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */ + 0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */ + 0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */ + 0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */ + 0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */ + 0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */ + 0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */ + 0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */ + 0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */ + 0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */ + 0xff21, 0xff3a, 532, /* A-Z a-z */ +}; + +/* + * upper case singlets + * 2nd col is conversion excess 500 + */ +static const Rune __tolower1[] = +{ + 0x0100, 501, /* Ā ā */ + 0x0102, 501, /* Ă ă */ + 0x0104, 501, /* Ą ą */ + 0x0106, 501, /* Ć ć */ + 0x0108, 501, /* Ĉ ĉ */ + 0x010a, 501, /* Ċ ċ */ + 0x010c, 501, /* Č č */ + 0x010e, 501, /* Ď ď */ + 0x0110, 501, /* Đ đ */ + 0x0112, 501, /* Ē ē */ + 0x0114, 501, /* Ĕ ĕ */ + 0x0116, 501, /* Ė ė */ + 0x0118, 501, /* Ę ę */ + 0x011a, 501, /* Ě ě */ + 0x011c, 501, /* Ĝ ĝ */ + 0x011e, 501, /* Ğ ğ */ + 0x0120, 501, /* Ġ ġ */ + 0x0122, 501, /* Ģ ģ */ + 0x0124, 501, /* Ĥ ĥ */ + 0x0126, 501, /* Ħ ħ */ + 0x0128, 501, /* Ĩ ĩ */ + 0x012a, 501, /* Ī ī */ + 0x012c, 501, /* Ĭ ĭ */ + 0x012e, 501, /* Į į */ + 0x0130, 301, /* İ i */ + 0x0132, 501, /* IJ ij */ + 0x0134, 501, /* Ĵ ĵ */ + 0x0136, 501, /* Ķ ķ */ + 0x0139, 501, /* Ĺ ĺ */ + 0x013b, 501, /* Ļ ļ */ + 0x013d, 501, /* Ľ ľ */ + 0x013f, 501, /* Ŀ ŀ */ + 0x0141, 501, /* Ł ł */ + 0x0143, 501, /* Ń ń */ + 0x0145, 501, /* Ņ ņ */ + 0x0147, 501, /* Ň ň */ + 0x014a, 501, /* Ŋ ŋ */ + 0x014c, 501, /* Ō ō */ + 0x014e, 501, /* Ŏ ŏ */ + 0x0150, 501, /* Ő ő */ + 0x0152, 501, /* Œ œ */ + 0x0154, 501, /* Ŕ ŕ */ + 0x0156, 501, /* Ŗ ŗ */ + 0x0158, 501, /* Ř ř */ + 0x015a, 501, /* Ś ś */ + 0x015c, 501, /* Ŝ ŝ */ + 0x015e, 501, /* Ş ş */ + 0x0160, 501, /* Š š */ + 0x0162, 501, /* Ţ ţ */ + 0x0164, 501, /* Ť ť */ + 0x0166, 501, /* Ŧ ŧ */ + 0x0168, 501, /* Ũ ũ */ + 0x016a, 501, /* Ū ū */ + 0x016c, 501, /* Ŭ ŭ */ + 0x016e, 501, /* Ů ů */ + 0x0170, 501, /* Ű ű */ + 0x0172, 501, /* Ų ų */ + 0x0174, 501, /* Ŵ ŵ */ + 0x0176, 501, /* Ŷ ŷ */ + 0x0178, 379, /* Ÿ ÿ */ + 0x0179, 501, /* Ź ź */ + 0x017b, 501, /* Ż ż */ + 0x017d, 501, /* Ž ž */ + 0x0181, 710, /* Ɓ ɓ */ + 0x0182, 501, /* Ƃ ƃ */ + 0x0184, 501, /* Ƅ ƅ */ + 0x0186, 706, /* Ɔ ɔ */ + 0x0187, 501, /* Ƈ ƈ */ + 0x018b, 501, /* Ƌ ƌ */ + 0x0190, 703, /* Ɛ ɛ */ + 0x0191, 501, /* Ƒ ƒ */ + 0x0193, 705, /* Ɠ ɠ */ + 0x0194, 707, /* Ɣ ɣ */ + 0x0196, 711, /* Ɩ ɩ */ + 0x0197, 709, /* Ɨ ɨ */ + 0x0198, 501, /* Ƙ ƙ */ + 0x019c, 711, /* Ɯ ɯ */ + 0x019d, 713, /* Ɲ ɲ */ + 0x01a0, 501, /* Ơ ơ */ + 0x01a2, 501, /* Ƣ ƣ */ + 0x01a4, 501, /* Ƥ ƥ */ + 0x01a7, 501, /* Ƨ ƨ */ + 0x01a9, 718, /* Ʃ ʃ */ + 0x01ac, 501, /* Ƭ ƭ */ + 0x01ae, 718, /* Ʈ ʈ */ + 0x01af, 501, /* Ư ư */ + 0x01b3, 501, /* Ƴ ƴ */ + 0x01b5, 501, /* Ƶ ƶ */ + 0x01b7, 719, /* Ʒ ʒ */ + 0x01b8, 501, /* Ƹ ƹ */ + 0x01bc, 501, /* Ƽ ƽ */ + 0x01c4, 502, /* DŽ dž */ + 0x01c5, 501, /* Dž dž */ + 0x01c7, 502, /* LJ lj */ + 0x01c8, 501, /* Lj lj */ + 0x01ca, 502, /* NJ nj */ + 0x01cb, 501, /* Nj nj */ + 0x01cd, 501, /* Ǎ ǎ */ + 0x01cf, 501, /* Ǐ ǐ */ + 0x01d1, 501, /* Ǒ ǒ */ + 0x01d3, 501, /* Ǔ ǔ */ + 0x01d5, 501, /* Ǖ ǖ */ + 0x01d7, 501, /* Ǘ ǘ */ + 0x01d9, 501, /* Ǚ ǚ */ + 0x01db, 501, /* Ǜ ǜ */ + 0x01de, 501, /* Ǟ ǟ */ + 0x01e0, 501, /* Ǡ ǡ */ + 0x01e2, 501, /* Ǣ ǣ */ + 0x01e4, 501, /* Ǥ ǥ */ + 0x01e6, 501, /* Ǧ ǧ */ + 0x01e8, 501, /* Ǩ ǩ */ + 0x01ea, 501, /* Ǫ ǫ */ + 0x01ec, 501, /* Ǭ ǭ */ + 0x01ee, 501, /* Ǯ ǯ */ + 0x01f1, 502, /* DZ dz */ + 0x01f2, 501, /* Dz dz */ + 0x01f4, 501, /* Ǵ ǵ */ + 0x01fa, 501, /* Ǻ ǻ */ + 0x01fc, 501, /* Ǽ ǽ */ + 0x01fe, 501, /* Ǿ ǿ */ + 0x0200, 501, /* Ȁ ȁ */ + 0x0202, 501, /* Ȃ ȃ */ + 0x0204, 501, /* Ȅ ȅ */ + 0x0206, 501, /* Ȇ ȇ */ + 0x0208, 501, /* Ȉ ȉ */ + 0x020a, 501, /* Ȋ ȋ */ + 0x020c, 501, /* Ȍ ȍ */ + 0x020e, 501, /* Ȏ ȏ */ + 0x0210, 501, /* Ȑ ȑ */ + 0x0212, 501, /* Ȓ ȓ */ + 0x0214, 501, /* Ȕ ȕ */ + 0x0216, 501, /* Ȗ ȗ */ + 0x0386, 538, /* Ά ά */ + 0x038c, 564, /* Ό ό */ + 0x03e2, 501, /* Ϣ ϣ */ + 0x03e4, 501, /* Ϥ ϥ */ + 0x03e6, 501, /* Ϧ ϧ */ + 0x03e8, 501, /* Ϩ ϩ */ + 0x03ea, 501, /* Ϫ ϫ */ + 0x03ec, 501, /* Ϭ ϭ */ + 0x03ee, 501, /* Ϯ ϯ */ + 0x0460, 501, /* Ѡ ѡ */ + 0x0462, 501, /* Ѣ ѣ */ + 0x0464, 501, /* Ѥ ѥ */ + 0x0466, 501, /* Ѧ ѧ */ + 0x0468, 501, /* Ѩ ѩ */ + 0x046a, 501, /* Ѫ ѫ */ + 0x046c, 501, /* Ѭ ѭ */ + 0x046e, 501, /* Ѯ ѯ */ + 0x0470, 501, /* Ѱ ѱ */ + 0x0472, 501, /* Ѳ ѳ */ + 0x0474, 501, /* Ѵ ѵ */ + 0x0476, 501, /* Ѷ ѷ */ + 0x0478, 501, /* Ѹ ѹ */ + 0x047a, 501, /* Ѻ ѻ */ + 0x047c, 501, /* Ѽ ѽ */ + 0x047e, 501, /* Ѿ ѿ */ + 0x0480, 501, /* Ҁ ҁ */ + 0x0490, 501, /* Ґ ґ */ + 0x0492, 501, /* Ғ ғ */ + 0x0494, 501, /* Ҕ ҕ */ + 0x0496, 501, /* Җ җ */ + 0x0498, 501, /* Ҙ ҙ */ + 0x049a, 501, /* Қ қ */ + 0x049c, 501, /* Ҝ ҝ */ + 0x049e, 501, /* Ҟ ҟ */ + 0x04a0, 501, /* Ҡ ҡ */ + 0x04a2, 501, /* Ң ң */ + 0x04a4, 501, /* Ҥ ҥ */ + 0x04a6, 501, /* Ҧ ҧ */ + 0x04a8, 501, /* Ҩ ҩ */ + 0x04aa, 501, /* Ҫ ҫ */ + 0x04ac, 501, /* Ҭ ҭ */ + 0x04ae, 501, /* Ү ү */ + 0x04b0, 501, /* Ұ ұ */ + 0x04b2, 501, /* Ҳ ҳ */ + 0x04b4, 501, /* Ҵ ҵ */ + 0x04b6, 501, /* Ҷ ҷ */ + 0x04b8, 501, /* Ҹ ҹ */ + 0x04ba, 501, /* Һ һ */ + 0x04bc, 501, /* Ҽ ҽ */ + 0x04be, 501, /* Ҿ ҿ */ + 0x04c1, 501, /* Ӂ ӂ */ + 0x04c3, 501, /* Ӄ ӄ */ + 0x04c7, 501, /* Ӈ ӈ */ + 0x04cb, 501, /* Ӌ ӌ */ + 0x04d0, 501, /* Ӑ ӑ */ + 0x04d2, 501, /* Ӓ ӓ */ + 0x04d4, 501, /* Ӕ ӕ */ + 0x04d6, 501, /* Ӗ ӗ */ + 0x04d8, 501, /* Ә ә */ + 0x04da, 501, /* Ӛ ӛ */ + 0x04dc, 501, /* Ӝ ӝ */ + 0x04de, 501, /* Ӟ ӟ */ + 0x04e0, 501, /* Ӡ ӡ */ + 0x04e2, 501, /* Ӣ ӣ */ + 0x04e4, 501, /* Ӥ ӥ */ + 0x04e6, 501, /* Ӧ ӧ */ + 0x04e8, 501, /* Ө ө */ + 0x04ea, 501, /* Ӫ ӫ */ + 0x04ee, 501, /* Ӯ ӯ */ + 0x04f0, 501, /* Ӱ ӱ */ + 0x04f2, 501, /* Ӳ ӳ */ + 0x04f4, 501, /* Ӵ ӵ */ + 0x04f8, 501, /* Ӹ ӹ */ + 0x1e00, 501, /* Ḁ ḁ */ + 0x1e02, 501, /* Ḃ ḃ */ + 0x1e04, 501, /* Ḅ ḅ */ + 0x1e06, 501, /* Ḇ ḇ */ + 0x1e08, 501, /* Ḉ ḉ */ + 0x1e0a, 501, /* Ḋ ḋ */ + 0x1e0c, 501, /* Ḍ ḍ */ + 0x1e0e, 501, /* Ḏ ḏ */ + 0x1e10, 501, /* Ḑ ḑ */ + 0x1e12, 501, /* Ḓ ḓ */ + 0x1e14, 501, /* Ḕ ḕ */ + 0x1e16, 501, /* Ḗ ḗ */ + 0x1e18, 501, /* Ḙ ḙ */ + 0x1e1a, 501, /* Ḛ ḛ */ + 0x1e1c, 501, /* Ḝ ḝ */ + 0x1e1e, 501, /* Ḟ ḟ */ + 0x1e20, 501, /* Ḡ ḡ */ + 0x1e22, 501, /* Ḣ ḣ */ + 0x1e24, 501, /* Ḥ ḥ */ + 0x1e26, 501, /* Ḧ ḧ */ + 0x1e28, 501, /* Ḩ ḩ */ + 0x1e2a, 501, /* Ḫ ḫ */ + 0x1e2c, 501, /* Ḭ ḭ */ + 0x1e2e, 501, /* Ḯ ḯ */ + 0x1e30, 501, /* Ḱ ḱ */ + 0x1e32, 501, /* Ḳ ḳ */ + 0x1e34, 501, /* Ḵ ḵ */ + 0x1e36, 501, /* Ḷ ḷ */ + 0x1e38, 501, /* Ḹ ḹ */ + 0x1e3a, 501, /* Ḻ ḻ */ + 0x1e3c, 501, /* Ḽ ḽ */ + 0x1e3e, 501, /* Ḿ ḿ */ + 0x1e40, 501, /* Ṁ ṁ */ + 0x1e42, 501, /* Ṃ ṃ */ + 0x1e44, 501, /* Ṅ ṅ */ + 0x1e46, 501, /* Ṇ ṇ */ + 0x1e48, 501, /* Ṉ ṉ */ + 0x1e4a, 501, /* Ṋ ṋ */ + 0x1e4c, 501, /* Ṍ ṍ */ + 0x1e4e, 501, /* Ṏ ṏ */ + 0x1e50, 501, /* Ṑ ṑ */ + 0x1e52, 501, /* Ṓ ṓ */ + 0x1e54, 501, /* Ṕ ṕ */ + 0x1e56, 501, /* Ṗ ṗ */ + 0x1e58, 501, /* Ṙ ṙ */ + 0x1e5a, 501, /* Ṛ ṛ */ + 0x1e5c, 501, /* Ṝ ṝ */ + 0x1e5e, 501, /* Ṟ ṟ */ + 0x1e60, 501, /* Ṡ ṡ */ + 0x1e62, 501, /* Ṣ ṣ */ + 0x1e64, 501, /* Ṥ ṥ */ + 0x1e66, 501, /* Ṧ ṧ */ + 0x1e68, 501, /* Ṩ ṩ */ + 0x1e6a, 501, /* Ṫ ṫ */ + 0x1e6c, 501, /* Ṭ ṭ */ + 0x1e6e, 501, /* Ṯ ṯ */ + 0x1e70, 501, /* Ṱ ṱ */ + 0x1e72, 501, /* Ṳ ṳ */ + 0x1e74, 501, /* Ṵ ṵ */ + 0x1e76, 501, /* Ṷ ṷ */ + 0x1e78, 501, /* Ṹ ṹ */ + 0x1e7a, 501, /* Ṻ ṻ */ + 0x1e7c, 501, /* Ṽ ṽ */ + 0x1e7e, 501, /* Ṿ ṿ */ + 0x1e80, 501, /* Ẁ ẁ */ + 0x1e82, 501, /* Ẃ ẃ */ + 0x1e84, 501, /* Ẅ ẅ */ + 0x1e86, 501, /* Ẇ ẇ */ + 0x1e88, 501, /* Ẉ ẉ */ + 0x1e8a, 501, /* Ẋ ẋ */ + 0x1e8c, 501, /* Ẍ ẍ */ + 0x1e8e, 501, /* Ẏ ẏ */ + 0x1e90, 501, /* Ẑ ẑ */ + 0x1e92, 501, /* Ẓ ẓ */ + 0x1e94, 501, /* Ẕ ẕ */ + 0x1ea0, 501, /* Ạ ạ */ + 0x1ea2, 501, /* Ả ả */ + 0x1ea4, 501, /* Ấ ấ */ + 0x1ea6, 501, /* Ầ ầ */ + 0x1ea8, 501, /* Ẩ ẩ */ + 0x1eaa, 501, /* Ẫ ẫ */ + 0x1eac, 501, /* Ậ ậ */ + 0x1eae, 501, /* Ắ ắ */ + 0x1eb0, 501, /* Ằ ằ */ + 0x1eb2, 501, /* Ẳ ẳ */ + 0x1eb4, 501, /* Ẵ ẵ */ + 0x1eb6, 501, /* Ặ ặ */ + 0x1eb8, 501, /* Ẹ ẹ */ + 0x1eba, 501, /* Ẻ ẻ */ + 0x1ebc, 501, /* Ẽ ẽ */ + 0x1ebe, 501, /* Ế ế */ + 0x1ec0, 501, /* Ề ề */ + 0x1ec2, 501, /* Ể ể */ + 0x1ec4, 501, /* Ễ ễ */ + 0x1ec6, 501, /* Ệ ệ */ + 0x1ec8, 501, /* Ỉ ỉ */ + 0x1eca, 501, /* Ị ị */ + 0x1ecc, 501, /* Ọ ọ */ + 0x1ece, 501, /* Ỏ ỏ */ + 0x1ed0, 501, /* Ố ố */ + 0x1ed2, 501, /* Ồ ồ */ + 0x1ed4, 501, /* Ổ ổ */ + 0x1ed6, 501, /* Ỗ ỗ */ + 0x1ed8, 501, /* Ộ ộ */ + 0x1eda, 501, /* Ớ ớ */ + 0x1edc, 501, /* Ờ ờ */ + 0x1ede, 501, /* Ở ở */ + 0x1ee0, 501, /* Ỡ ỡ */ + 0x1ee2, 501, /* Ợ ợ */ + 0x1ee4, 501, /* Ụ ụ */ + 0x1ee6, 501, /* Ủ ủ */ + 0x1ee8, 501, /* Ứ ứ */ + 0x1eea, 501, /* Ừ ừ */ + 0x1eec, 501, /* Ử ử */ + 0x1eee, 501, /* Ữ ữ */ + 0x1ef0, 501, /* Ự ự */ + 0x1ef2, 501, /* Ỳ ỳ */ + 0x1ef4, 501, /* Ỵ ỵ */ + 0x1ef6, 501, /* Ỷ ỷ */ + 0x1ef8, 501, /* Ỹ ỹ */ + 0x1f59, 492, /* Ὑ ὑ */ + 0x1f5b, 492, /* Ὓ ὓ */ + 0x1f5d, 492, /* Ὕ ὕ */ + 0x1f5f, 492, /* Ὗ ὗ */ + 0x1fbc, 491, /* ᾼ ᾳ */ + 0x1fcc, 491, /* ῌ ῃ */ + 0x1fec, 493, /* Ῥ ῥ */ + 0x1ffc, 491, /* ῼ ῳ */ +}; + +/* + * title characters are those between + * upper and lower case. ie DZ Dz dz + */ +static const Rune __totitle1[] = +{ + 0x01c4, 501, /* DŽ Dž */ + 0x01c6, 499, /* dž Dž */ + 0x01c7, 501, /* LJ Lj */ + 0x01c9, 499, /* lj Lj */ + 0x01ca, 501, /* NJ Nj */ + 0x01cc, 499, /* nj Nj */ + 0x01f1, 501, /* DZ Dz */ + 0x01f3, 499, /* dz Dz */ +}; + +static const Rune * +bsearch(Rune c, const Rune *t, int n, int ne) +{ + const Rune *p; + int m; + + while(n > 1) { + m = n/2; + p = t + m*ne; + if(c >= p[0]) { + t = p; + n = n-m; + } else + n = m; + } + if(n && c >= t[0]) + return t; + return 0; +} + +Rune +tolowerrune(Rune c) +{ + const Rune *p; + + p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 500; + p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2); + if(p && c == p[0]) + return c + p[1] - 500; + return c; +} + +Rune +toupperrune(Rune c) +{ + const Rune *p; + + p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 500; + p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2); + if(p && c == p[0]) + return c + p[1] - 500; + return c; +} + +Rune +totitlerune(Rune c) +{ + const Rune *p; + + p = bsearch(c, __totitle1, nelem(__totitle1)/2, 2); + if(p && c == p[0]) + return c + p[1] - 500; + return c; +} + +int +islowerrune(Rune c) +{ + const Rune *p; + + p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2); + if(p && c == p[0]) + return 1; + return 0; +} + +int +isupperrune(Rune c) +{ + const Rune *p; + + p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2); + if(p && c == p[0]) + return 1; + return 0; +} + +int +isalpharune(Rune c) +{ + const Rune *p; + + if(isupperrune(c) || islowerrune(c)) + return 1; + p = bsearch(c, __alpha2, nelem(__alpha2)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = bsearch(c, __alpha1, nelem(__alpha1), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +int +istitlerune(Rune c) +{ + return isupperrune(c) && islowerrune(c); +} + +int +isspacerune(Rune c) +{ + const Rune *p; + + p = bsearch(c, __space2, nelem(__space2)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + return 0; +}