/programs/develop/kosjs/Makefile |
---|
8,9 → 8,9 |
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 |
/programs/develop/kosjs/kosjs.c |
---|
7,8 → 7,12 |
int main(int argc, char **argv) |
{ |
if (argc == 1) { |
printf("usage: %s [program.js]\n", argv[0]); |
} else { |
import_functions(); |
js_dofile(J, argv[1]); |
js_freestate (J); |
} |
exit(0); |
} |
/programs/develop/kosjs/libmujs/lib/libmujs.a |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
Deleted: svn:mime-type |
-application/octet-stream |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/jsparse.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/jsvalue.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/regexp.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/import.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/astnames.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/utf.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/mujs.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/jsrun.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/opnames.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/jsbuiltin.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/jsi.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/jscompile.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/include/jslex.h |
---|
File deleted |
Property changes: |
Deleted: svn:executable |
-* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/AUTHORS |
---|
0,0 → 1,0 |
Tor Andersson <tor.andersson@artifex.com> |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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. |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 $@ $< |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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. |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/astnames.h |
---|
0,0 → 1,92 |
"list", |
"fundec", |
"identifier", |
"exp_identifier", |
"exp_number", |
"exp_string", |
"exp_regexp", |
"exp_undef", |
"exp_null", |
"exp_true", |
"exp_false", |
"exp_this", |
"exp_array", |
"exp_object", |
"exp_prop_val", |
"exp_prop_get", |
"exp_prop_set", |
"exp_fun", |
"exp_index", |
"exp_member", |
"exp_call", |
"exp_new", |
"exp_postinc", |
"exp_postdec", |
"exp_delete", |
"exp_void", |
"exp_typeof", |
"exp_preinc", |
"exp_predec", |
"exp_pos", |
"exp_neg", |
"exp_bitnot", |
"exp_lognot", |
"exp_mod", |
"exp_div", |
"exp_mul", |
"exp_sub", |
"exp_add", |
"exp_ushr", |
"exp_shr", |
"exp_shl", |
"exp_in", |
"exp_instanceof", |
"exp_ge", |
"exp_le", |
"exp_gt", |
"exp_lt", |
"exp_strictne", |
"exp_stricteq", |
"exp_ne", |
"exp_eq", |
"exp_bitand", |
"exp_bitxor", |
"exp_bitor", |
"exp_logand", |
"exp_logor", |
"exp_cond", |
"exp_ass", |
"exp_ass_mul", |
"exp_ass_div", |
"exp_ass_mod", |
"exp_ass_add", |
"exp_ass_sub", |
"exp_ass_shl", |
"exp_ass_shr", |
"exp_ass_ushr", |
"exp_ass_bitand", |
"exp_ass_bitxor", |
"exp_ass_bitor", |
"exp_comma", |
"exp_var", |
"stm_block", |
"stm_empty", |
"stm_var", |
"stm_if", |
"stm_do", |
"stm_while", |
"stm_for", |
"stm_for_var", |
"stm_for_in", |
"stm_for_in_var", |
"stm_continue", |
"stm_break", |
"stm_return", |
"stm_with", |
"stm_switch", |
"stm_throw", |
"stm_try", |
"stm_debugger", |
"stm_label", |
"stm_case", |
"stm_default", |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/import.h |
---|
0,0 → 1,6 |
#include "mujs.h" |
#define js_toint(J, idx) js_tointeger(J, idx) |
js_State *J; |
void import_functions(); |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jsbuiltin.h |
---|
0,0 → 1,21 |
#ifndef js_builtin_h |
#define js_builtin_h |
void jsB_init(js_State *J); |
void jsB_initobject(js_State *J); |
void jsB_initarray(js_State *J); |
void jsB_initfunction(js_State *J); |
void jsB_initboolean(js_State *J); |
void jsB_initnumber(js_State *J); |
void jsB_initstring(js_State *J); |
void jsB_initregexp(js_State *J); |
void jsB_initerror(js_State *J); |
void jsB_initmath(js_State *J); |
void jsB_initjson(js_State *J); |
void jsB_initdate(js_State *J); |
void jsB_propf(js_State *J, const char *name, js_CFunction cfun, int n); |
void jsB_propn(js_State *J, const char *name, double number); |
void jsB_props(js_State *J, const char *name, const char *string); |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jscompile.h |
---|
0,0 → 1,146 |
#ifndef js_compile_h |
#define js_compile_h |
enum js_OpCode |
{ |
OP_POP, /* A -- */ |
OP_DUP, /* A -- A A */ |
OP_DUP2, /* A B -- A B A B */ |
OP_ROT2, /* A B -- B A */ |
OP_ROT3, /* A B C -- C A B */ |
OP_ROT4, /* A B C D -- D A B C */ |
OP_INTEGER, /* -K- (number-32768) */ |
OP_NUMBER, /* -N- <number> */ |
OP_STRING, /* -S- <string> */ |
OP_CLOSURE, /* -F- <closure> */ |
OP_NEWARRAY, |
OP_NEWOBJECT, |
OP_NEWREGEXP, /* -S,opts- <regexp> */ |
OP_UNDEF, |
OP_NULL, |
OP_TRUE, |
OP_FALSE, |
OP_THIS, |
OP_CURRENT, /* currently executing function object */ |
OP_GETLOCAL, /* -K- <value> */ |
OP_SETLOCAL, /* <value> -K- <value> */ |
OP_DELLOCAL, /* -K- false */ |
OP_HASVAR, /* -S- ( <value> | undefined ) */ |
OP_GETVAR, /* -S- <value> */ |
OP_SETVAR, /* <value> -S- <value> */ |
OP_DELVAR, /* -S- <success> */ |
OP_IN, /* <name> <obj> -- <exists?> */ |
OP_INITPROP, /* <obj> <key> <val> -- <obj> */ |
OP_INITGETTER, /* <obj> <key> <closure> -- <obj> */ |
OP_INITSETTER, /* <obj> <key> <closure> -- <obj> */ |
OP_GETPROP, /* <obj> <name> -- <value> */ |
OP_GETPROP_S, /* <obj> -S- <value> */ |
OP_SETPROP, /* <obj> <name> <value> -- <value> */ |
OP_SETPROP_S, /* <obj> <value> -S- <value> */ |
OP_DELPROP, /* <obj> <name> -- <success> */ |
OP_DELPROP_S, /* <obj> -S- <success> */ |
OP_ITERATOR, /* <obj> -- <iobj> */ |
OP_NEXTITER, /* <iobj> -- ( <iobj> <name> true | false ) */ |
OP_EVAL, /* <args...> -(numargs)- <returnvalue> */ |
OP_CALL, /* <closure> <this> <args...> -(numargs)- <returnvalue> */ |
OP_NEW, /* <closure> <args...> -(numargs)- <returnvalue> */ |
OP_TYPEOF, |
OP_POS, |
OP_NEG, |
OP_BITNOT, |
OP_LOGNOT, |
OP_INC, /* <x> -- ToNumber(x)+1 */ |
OP_DEC, /* <x> -- ToNumber(x)-1 */ |
OP_POSTINC, /* <x> -- ToNumber(x)+1 ToNumber(x) */ |
OP_POSTDEC, /* <x> -- ToNumber(x)-1 ToNumber(x) */ |
OP_MUL, |
OP_DIV, |
OP_MOD, |
OP_ADD, |
OP_SUB, |
OP_SHL, |
OP_SHR, |
OP_USHR, |
OP_LT, |
OP_GT, |
OP_LE, |
OP_GE, |
OP_EQ, |
OP_NE, |
OP_STRICTEQ, |
OP_STRICTNE, |
OP_JCASE, |
OP_BITAND, |
OP_BITXOR, |
OP_BITOR, |
OP_INSTANCEOF, |
OP_THROW, |
OP_TRY, /* -ADDR- /jump/ or -ADDR- <exception> */ |
OP_ENDTRY, |
OP_CATCH, /* push scope chain with exception variable */ |
OP_ENDCATCH, |
OP_WITH, |
OP_ENDWITH, |
OP_DEBUGGER, |
OP_JUMP, |
OP_JTRUE, |
OP_JFALSE, |
OP_RETURN, |
}; |
struct js_Function |
{ |
const char *name; |
int script; |
int lightweight; |
int strict; |
int arguments; |
int numparams; |
js_Instruction *code; |
int codecap, codelen; |
js_Function **funtab; |
int funcap, funlen; |
double *numtab; |
int numcap, numlen; |
const char **strtab; |
int strcap, strlen; |
const char **vartab; |
int varcap, varlen; |
const char *filename; |
int line, lastline; |
js_Function *gcnext; |
int gcmark; |
}; |
js_Function *jsC_compilefunction(js_State *J, js_Ast *prog); |
js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict); |
const char *jsC_opcodestring(enum js_OpCode opcode); |
void jsC_dumpfunction(js_State *J, js_Function *fun); |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jsdate.c |
---|
0,0 → 1,812 |
#include "jsi.h" |
#include "jsvalue.h" |
#include "jsbuiltin.h" |
#include <time.h> |
#if defined(__unix__) || defined(__APPLE__) |
#include <sys/time.h> |
#elif defined(_WIN32) |
#include <sys/timeb.h> |
#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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 <stdint.h> |
#endif |
#include <errno.h> |
#include <assert.h> |
#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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 <assert.h> |
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 "<unknown>"; |
} |
const char *jsC_opcodestring(enum js_OpCode opcode) |
{ |
if (opcode < nelem(opname)-1) |
return opname[opcode]; |
return "<unknown>"; |
} |
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("<UNKNOWN>"); |
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"); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jsi.h |
---|
0,0 → 1,265 |
#ifndef jsi_h |
#define jsi_h |
#include "mujs.h" |
#include <stdio.h> |
#include <stdlib.h> |
#include <stddef.h> |
#include <stdarg.h> |
#include <string.h> |
#include <setjmp.h> |
#include <math.h> |
#include <float.h> |
#include <limits.h> |
/* Microsoft Visual C */ |
#ifdef _MSC_VER |
#pragma warning(disable:4996) /* _CRT_SECURE_NO_WARNINGS */ |
#pragma warning(disable:4244) /* implicit conversion from double to int */ |
#pragma warning(disable:4267) /* implicit conversion of int to smaller int */ |
#define inline __inline |
#if _MSC_VER < 1900 /* MSVC 2015 */ |
#define snprintf jsW_snprintf |
#define vsnprintf jsW_vsnprintf |
static int jsW_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) |
{ |
int n; |
n = _vsnprintf(str, size, fmt, ap); |
str[size-1] = 0; |
return n; |
} |
static int jsW_snprintf(char *str, size_t size, const char *fmt, ...) |
{ |
int n; |
va_list ap; |
va_start(ap, fmt); |
n = jsW_vsnprintf(str, size, fmt, ap); |
va_end(ap); |
return n; |
} |
#endif |
#if _MSC_VER <= 1700 /* <= MSVC 2012 */ |
#define isnan(x) _isnan(x) |
#define isinf(x) (!_finite(x)) |
#define isfinite(x) _finite(x) |
static __inline int signbit(double x) { __int64 i; memcpy(&i, &x, 8); return i>>63; } |
#define INFINITY (DBL_MAX+DBL_MAX) |
#define NAN (INFINITY-INFINITY) |
#endif |
#endif |
#define soffsetof(x,y) ((int)offsetof(x,y)) |
#define nelem(a) (int)(sizeof (a) / sizeof (a)[0]) |
void *js_malloc(js_State *J, int size); |
void *js_realloc(js_State *J, void *ptr, int size); |
void js_free(js_State *J, void *ptr); |
typedef struct js_Regexp js_Regexp; |
typedef struct js_Value js_Value; |
typedef struct js_Object js_Object; |
typedef struct js_String js_String; |
typedef struct js_Ast js_Ast; |
typedef struct js_Function js_Function; |
typedef struct js_Environment js_Environment; |
typedef struct js_StringNode js_StringNode; |
typedef struct js_Jumpbuf js_Jumpbuf; |
typedef struct js_StackTrace js_StackTrace; |
/* Limits */ |
#ifndef JS_STACKSIZE |
#define JS_STACKSIZE 256 /* value stack size */ |
#endif |
#ifndef JS_ENVLIMIT |
#define JS_ENVLIMIT 128 /* environment stack size */ |
#endif |
#ifndef JS_TRYLIMIT |
#define JS_TRYLIMIT 64 /* exception stack size */ |
#endif |
#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 */ |
#endif |
/* instruction size -- change to int if you get integer overflow syntax errors */ |
#ifdef JS_INSTRUCTION |
typedef JS_INSTRUCTION js_Instruction; |
#else |
typedef unsigned short js_Instruction; |
#endif |
/* String interning */ |
char *js_strdup(js_State *J, const char *s); |
const char *js_intern(js_State *J, const char *s); |
void jsS_dumpstrings(js_State *J); |
void jsS_freestrings(js_State *J); |
/* Portable strtod and printf float formatting */ |
void js_fmtexp(char *p, int e); |
int js_grisu2(double v, char *buffer, int *K); |
double js_strtod(const char *as, char **aas); |
/* Private stack functions */ |
void js_newarguments(js_State *J); |
void js_newfunction(js_State *J, js_Function *function, js_Environment *scope); |
void js_newscript(js_State *J, js_Function *fun, js_Environment *scope, int type); |
void js_loadeval(js_State *J, const char *filename, const char *source); |
js_Regexp *js_toregexp(js_State *J, int idx); |
int js_isarrayindex(js_State *J, const char *str, int *idx); |
int js_runeat(js_State *J, const char *s, int i); |
int js_utfptrtoidx(const char *s, const char *p); |
const char *js_utfidxtoptr(const char *s, int i); |
void js_dup(js_State *J); |
void js_dup2(js_State *J); |
void js_rot2(js_State *J); |
void js_rot3(js_State *J); |
void js_rot4(js_State *J); |
void js_rot2pop1(js_State *J); |
void js_rot3pop2(js_State *J); |
void js_dup1rot3(js_State *J); |
void js_dup1rot4(js_State *J); |
void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text); |
void js_trap(js_State *J, int pc); /* dump stack and environment to stdout */ |
struct js_StackTrace |
{ |
const char *name; |
const char *file; |
int line; |
}; |
/* Exception handling */ |
struct js_Jumpbuf |
{ |
jmp_buf buf; |
js_Environment *E; |
int envtop; |
int tracetop; |
int top, bot; |
int strict; |
js_Instruction *pc; |
}; |
void *js_savetrypc(js_State *J, js_Instruction *pc); |
#define js_trypc(J, PC) \ |
setjmp(js_savetrypc(J, PC)) |
/* String buffer */ |
typedef struct js_Buffer { int n, m; char s[64]; } js_Buffer; |
void js_putc(js_State *J, js_Buffer **sbp, int c); |
void js_puts(js_State *J, js_Buffer **sb, const char *s); |
void js_putm(js_State *J, js_Buffer **sb, const char *s, const char *e); |
/* State struct */ |
struct js_State |
{ |
void *actx; |
void *uctx; |
js_Alloc alloc; |
js_Report report; |
js_Panic panic; |
js_StringNode *strings; |
int default_strict; |
int strict; |
/* parser input source */ |
const char *filename; |
const char *source; |
int line; |
/* lexer state */ |
struct { char *text; int len, cap; } lexbuf; |
int lexline; |
int lexchar; |
int lasttoken; |
int newline; |
/* parser state */ |
int astdepth; |
int lookahead; |
const char *text; |
double number; |
js_Ast *gcast; /* list of allocated nodes to free after parsing */ |
/* runtime environment */ |
js_Object *Object_prototype; |
js_Object *Array_prototype; |
js_Object *Function_prototype; |
js_Object *Boolean_prototype; |
js_Object *Number_prototype; |
js_Object *String_prototype; |
js_Object *RegExp_prototype; |
js_Object *Date_prototype; |
js_Object *Error_prototype; |
js_Object *EvalError_prototype; |
js_Object *RangeError_prototype; |
js_Object *ReferenceError_prototype; |
js_Object *SyntaxError_prototype; |
js_Object *TypeError_prototype; |
js_Object *URIError_prototype; |
unsigned int seed; /* Math.random seed */ |
int nextref; /* for js_ref use */ |
js_Object *R; /* registry of hidden values */ |
js_Object *G; /* the global object */ |
js_Environment *E; /* current environment scope */ |
js_Environment *GE; /* global environment scope (at the root) */ |
/* execution stack */ |
int top, bot; |
js_Value *stack; |
/* garbage collector list */ |
int gcpause; |
int gcmark; |
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]; |
/* debug info stack trace */ |
int tracetop; |
js_StackTrace trace[JS_ENVLIMIT]; |
/* exception stack */ |
int trytop; |
js_Jumpbuf trybuf[JS_TRYLIMIT]; |
}; |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 "<unknown>"; |
} |
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); |
} |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jslex.h |
---|
0,0 → 1,81 |
#ifndef js_lex_h |
#define js_lex_h |
enum |
{ |
TK_IDENTIFIER = 256, |
TK_NUMBER, |
TK_STRING, |
TK_REGEXP, |
/* multi-character punctuators */ |
TK_LE, |
TK_GE, |
TK_EQ, |
TK_NE, |
TK_STRICTEQ, |
TK_STRICTNE, |
TK_SHL, |
TK_SHR, |
TK_USHR, |
TK_AND, |
TK_OR, |
TK_ADD_ASS, |
TK_SUB_ASS, |
TK_MUL_ASS, |
TK_DIV_ASS, |
TK_MOD_ASS, |
TK_SHL_ASS, |
TK_SHR_ASS, |
TK_USHR_ASS, |
TK_AND_ASS, |
TK_OR_ASS, |
TK_XOR_ASS, |
TK_INC, |
TK_DEC, |
/* keywords */ |
TK_BREAK, |
TK_CASE, |
TK_CATCH, |
TK_CONTINUE, |
TK_DEBUGGER, |
TK_DEFAULT, |
TK_DELETE, |
TK_DO, |
TK_ELSE, |
TK_FALSE, |
TK_FINALLY, |
TK_FOR, |
TK_FUNCTION, |
TK_IF, |
TK_IN, |
TK_INSTANCEOF, |
TK_NEW, |
TK_NULL, |
TK_RETURN, |
TK_SWITCH, |
TK_THIS, |
TK_THROW, |
TK_TRUE, |
TK_TRY, |
TK_TYPEOF, |
TK_VAR, |
TK_VOID, |
TK_WHILE, |
TK_WITH, |
}; |
int jsY_iswhite(int c); |
int jsY_isnewline(int c); |
int jsY_ishex(int c); |
int jsY_tohex(int c); |
const char *jsY_tokenstring(int token); |
int jsY_findword(const char *s, const char **list, int num); |
void jsY_initlex(js_State *J, const char *filename, const char *source); |
int jsY_lex(js_State *J); |
int jsY_lexjson(js_State *J); |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jsmath.c |
---|
0,0 → 1,192 |
#include "jsi.h" |
#include "jsvalue.h" |
#include "jsbuiltin.h" |
#include <time.h> |
#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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 <stdint.h> |
#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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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)); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jsparse.h |
---|
0,0 → 1,146 |
#ifndef js_parse_h |
#define js_parse_h |
enum js_AstType |
{ |
AST_LIST, |
AST_FUNDEC, |
AST_IDENTIFIER, |
EXP_IDENTIFIER, |
EXP_NUMBER, |
EXP_STRING, |
EXP_REGEXP, |
/* literals */ |
EXP_UNDEF, /* for array elisions */ |
EXP_NULL, |
EXP_TRUE, |
EXP_FALSE, |
EXP_THIS, |
EXP_ARRAY, |
EXP_OBJECT, |
EXP_PROP_VAL, |
EXP_PROP_GET, |
EXP_PROP_SET, |
EXP_FUN, |
/* expressions */ |
EXP_INDEX, |
EXP_MEMBER, |
EXP_CALL, |
EXP_NEW, |
EXP_POSTINC, |
EXP_POSTDEC, |
EXP_DELETE, |
EXP_VOID, |
EXP_TYPEOF, |
EXP_PREINC, |
EXP_PREDEC, |
EXP_POS, |
EXP_NEG, |
EXP_BITNOT, |
EXP_LOGNOT, |
EXP_MOD, |
EXP_DIV, |
EXP_MUL, |
EXP_SUB, |
EXP_ADD, |
EXP_USHR, |
EXP_SHR, |
EXP_SHL, |
EXP_IN, |
EXP_INSTANCEOF, |
EXP_GE, |
EXP_LE, |
EXP_GT, |
EXP_LT, |
EXP_STRICTNE, |
EXP_STRICTEQ, |
EXP_NE, |
EXP_EQ, |
EXP_BITAND, |
EXP_BITXOR, |
EXP_BITOR, |
EXP_LOGAND, |
EXP_LOGOR, |
EXP_COND, |
EXP_ASS, |
EXP_ASS_MUL, |
EXP_ASS_DIV, |
EXP_ASS_MOD, |
EXP_ASS_ADD, |
EXP_ASS_SUB, |
EXP_ASS_SHL, |
EXP_ASS_SHR, |
EXP_ASS_USHR, |
EXP_ASS_BITAND, |
EXP_ASS_BITXOR, |
EXP_ASS_BITOR, |
EXP_COMMA, |
EXP_VAR, /* var initializer */ |
/* statements */ |
STM_BLOCK, |
STM_EMPTY, |
STM_VAR, |
STM_IF, |
STM_DO, |
STM_WHILE, |
STM_FOR, |
STM_FOR_VAR, |
STM_FOR_IN, |
STM_FOR_IN_VAR, |
STM_CONTINUE, |
STM_BREAK, |
STM_RETURN, |
STM_WITH, |
STM_SWITCH, |
STM_THROW, |
STM_TRY, |
STM_DEBUGGER, |
STM_LABEL, |
STM_CASE, |
STM_DEFAULT, |
}; |
typedef struct js_JumpList js_JumpList; |
struct js_JumpList |
{ |
enum js_AstType type; |
int inst; |
js_JumpList *next; |
}; |
struct js_Ast |
{ |
enum js_AstType type; |
int line; |
js_Ast *parent, *a, *b, *c, *d; |
double number; |
const char *string; |
js_JumpList *jumps; /* list of break/continue jumps to patch */ |
int casejump; /* for switch case clauses */ |
js_Ast *gcnext; /* next in alloc list */ |
}; |
js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body); |
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source); |
void jsP_freeparse(js_State *J); |
const char *jsP_aststring(enum js_AstType type); |
void jsP_dumpsyntax(js_State *J, js_Ast *prog, int minify); |
void jsP_dumplist(js_State *J, js_Ast *prog); |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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; |
} |
} |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jsrun.h |
---|
0,0 → 1,15 |
#ifndef js_run_h |
#define js_run_h |
js_Environment *jsR_newenvironment(js_State *J, js_Object *variables, js_Environment *outer); |
struct js_Environment |
{ |
js_Environment *outer; |
js_Object *variables; |
js_Environment *gcnext; |
int gcmark; |
}; |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 <assert.h> |
#include <errno.h> |
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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/jsvalue.h |
---|
0,0 → 1,188 |
#ifndef js_value_h |
#define js_value_h |
typedef struct js_Property js_Property; |
typedef struct js_Iterator js_Iterator; |
/* Hint to ToPrimitive() */ |
enum { |
JS_HNONE, |
JS_HNUMBER, |
JS_HSTRING |
}; |
enum js_Type { |
JS_TSHRSTR, /* type tag doubles as string zero-terminator */ |
JS_TUNDEFINED, |
JS_TNULL, |
JS_TBOOLEAN, |
JS_TNUMBER, |
JS_TLITSTR, |
JS_TMEMSTR, |
JS_TOBJECT, |
}; |
enum js_Class { |
JS_COBJECT, |
JS_CARRAY, |
JS_CFUNCTION, |
JS_CSCRIPT, /* function created from global code */ |
JS_CEVAL, /* function created from eval code */ |
JS_CCFUNCTION, /* built-in function */ |
JS_CERROR, |
JS_CBOOLEAN, |
JS_CNUMBER, |
JS_CSTRING, |
JS_CREGEXP, |
JS_CDATE, |
JS_CMATH, |
JS_CJSON, |
JS_CARGUMENTS, |
JS_CITERATOR, |
JS_CUSERDATA, |
}; |
/* |
Short strings abuse the js_Value struct. By putting the type tag in the |
last byte, and using 0 as the tag for short strings, we can use the |
entire js_Value as string storage by letting the type tag serve double |
purpose as the string zero terminator. |
*/ |
struct js_Value |
{ |
union { |
int boolean; |
double number; |
char shrstr[8]; |
const char *litstr; |
js_String *memstr; |
js_Object *object; |
} u; |
char pad[7]; /* extra storage for shrstr */ |
char type; /* type tag and zero terminator for shrstr */ |
}; |
struct js_String |
{ |
js_String *gcnext; |
char gcmark; |
char p[1]; |
}; |
struct js_Regexp |
{ |
void *prog; |
char *source; |
unsigned short flags; |
unsigned short last; |
}; |
struct js_Object |
{ |
enum js_Class type; |
int extensible; |
js_Property *properties; |
int count; /* number of properties, for array sparseness check */ |
js_Object *prototype; |
union { |
int boolean; |
double number; |
struct { |
const char *string; |
int length; |
} s; |
struct { |
int length; |
} a; |
struct { |
js_Function *function; |
js_Environment *scope; |
} f; |
struct { |
const char *name; |
js_CFunction function; |
js_CFunction constructor; |
int length; |
} c; |
js_Regexp r; |
struct { |
js_Object *target; |
js_Iterator *head; |
} iter; |
struct { |
const char *tag; |
void *data; |
js_HasProperty has; |
js_Put put; |
js_Delete delete; |
js_Finalize finalize; |
} user; |
} u; |
js_Object *gcnext; /* allocation list */ |
js_Object *gcroot; /* scan list */ |
int gcmark; |
}; |
struct js_Property |
{ |
const char *name; |
js_Property *left, *right; |
int level; |
int atts; |
js_Value value; |
js_Object *getter; |
js_Object *setter; |
}; |
struct js_Iterator |
{ |
const char *name; |
js_Iterator *next; |
}; |
/* jsrun.c */ |
js_String *jsV_newmemstring(js_State *J, const char *s, int n); |
js_Value *js_tovalue(js_State *J, int idx); |
void js_toprimitive(js_State *J, int idx, int hint); |
js_Object *js_toobject(js_State *J, int idx); |
void js_pushvalue(js_State *J, js_Value v); |
void js_pushobject(js_State *J, js_Object *v); |
/* jsvalue.c */ |
int jsV_toboolean(js_State *J, js_Value *v); |
double jsV_tonumber(js_State *J, js_Value *v); |
double jsV_tointeger(js_State *J, js_Value *v); |
const char *jsV_tostring(js_State *J, js_Value *v); |
js_Object *jsV_toobject(js_State *J, js_Value *v); |
void jsV_toprimitive(js_State *J, js_Value *v, int preferred); |
const char *js_itoa(char buf[32], int a); |
double js_stringtofloat(const char *s, char **ep); |
int jsV_numbertointeger(double n); |
int jsV_numbertoint32(double n); |
unsigned int jsV_numbertouint32(double n); |
short jsV_numbertoint16(double n); |
unsigned short jsV_numbertouint16(double n); |
const char *jsV_numbertostring(js_State *J, char buf[32], double number); |
double jsV_stringtonumber(js_State *J, const char *string); |
/* jsproperty.c */ |
js_Object *jsV_newobject(js_State *J, enum js_Class type, js_Object *prototype); |
js_Property *jsV_getownproperty(js_State *J, js_Object *obj, const char *name); |
js_Property *jsV_getpropertyx(js_State *J, js_Object *obj, const char *name, int *own); |
js_Property *jsV_getproperty(js_State *J, js_Object *obj, const char *name); |
js_Property *jsV_setproperty(js_State *J, js_Object *obj, const char *name); |
js_Property *jsV_nextproperty(js_State *J, js_Object *obj, const char *name); |
void jsV_delproperty(js_State *J, js_Object *obj, const char *name); |
js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own); |
const char *jsV_nextiterator(js_State *J, js_Object *iter); |
void jsV_resizearray(js_State *J, js_Object *obj, int newlen); |
/* jsdump.c */ |
void js_dumpobject(js_State *J, js_Object *obj); |
void js_dumpvalue(js_State *J, js_Value v); |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/mujs.h |
---|
0,0 → 1,229 |
#ifndef mujs_h |
#define mujs_h |
#include <setjmp.h> /* required for setjmp in fz_try macro */ |
#ifdef __cplusplus |
extern "C" { |
#endif |
/* noreturn is a GCC extension */ |
#ifdef __GNUC__ |
#define JS_NORETURN __attribute__((noreturn)) |
#else |
#ifdef _MSC_VER |
#define JS_NORETURN __declspec(noreturn) |
#else |
#define JS_NORETURN |
#endif |
#endif |
/* GCC can do type checking of printf strings */ |
#ifdef __printflike |
#define JS_PRINTFLIKE __printflike |
#else |
#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 |
#define JS_PRINTFLIKE(fmtarg, firstvararg) \ |
__attribute__((__format__ (__printf__, fmtarg, firstvararg))) |
#else |
#define JS_PRINTFLIKE(fmtarg, firstvararg) |
#endif |
#endif |
typedef struct js_State js_State; |
typedef void *(*js_Alloc)(void *memctx, void *ptr, int size); |
typedef void (*js_Panic)(js_State *J); |
typedef void (*js_CFunction)(js_State *J); |
typedef void (*js_Finalize)(js_State *J, void *p); |
typedef int (*js_HasProperty)(js_State *J, void *p, const char *name); |
typedef int (*js_Put)(js_State *J, void *p, const char *name); |
typedef int (*js_Delete)(js_State *J, void *p, const char *name); |
typedef void (*js_Report)(js_State *J, const char *message); |
/* Basic functions */ |
js_State *js_newstate(js_Alloc alloc, void *actx, int flags); |
void js_setcontext(js_State *J, void *uctx); |
void *js_getcontext(js_State *J); |
void js_setreport(js_State *J, js_Report report); |
js_Panic js_atpanic(js_State *J, js_Panic panic); |
void js_freestate(js_State *J); |
void js_gc(js_State *J, int report); |
int js_dostring(js_State *J, const char *source); |
int js_dofile(js_State *J, const char *filename); |
int js_ploadstring(js_State *J, const char *filename, const char *source); |
int js_ploadfile(js_State *J, const char *filename); |
int js_pcall(js_State *J, int n); |
int js_pconstruct(js_State *J, int n); |
/* Exception handling */ |
void *js_savetry(js_State *J); /* returns a jmp_buf */ |
#define js_try(J) \ |
setjmp(js_savetry(J)) |
void js_endtry(js_State *J); |
/* State constructor flags */ |
enum { |
JS_STRICT = 1, |
}; |
/* RegExp flags */ |
enum { |
JS_REGEXP_G = 1, |
JS_REGEXP_I = 2, |
JS_REGEXP_M = 4, |
}; |
/* Property attribute flags */ |
enum { |
JS_READONLY = 1, |
JS_DONTENUM = 2, |
JS_DONTCONF = 4, |
}; |
void js_report(js_State *J, const char *message); |
void js_newerror(js_State *J, const char *message); |
void js_newevalerror(js_State *J, const char *message); |
void js_newrangeerror(js_State *J, const char *message); |
void js_newreferenceerror(js_State *J, const char *message); |
void js_newsyntaxerror(js_State *J, const char *message); |
void js_newtypeerror(js_State *J, const char *message); |
void js_newurierror(js_State *J, const char *message); |
JS_NORETURN void js_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); |
JS_NORETURN void js_evalerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); |
JS_NORETURN void js_rangeerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); |
JS_NORETURN void js_referenceerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); |
JS_NORETURN void js_syntaxerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); |
JS_NORETURN void js_typeerror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); |
JS_NORETURN void js_urierror(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); |
JS_NORETURN void js_throw(js_State *J); |
void js_loadstring(js_State *J, const char *filename, const char *source); |
void js_loadfile(js_State *J, const char *filename); |
void js_eval(js_State *J); |
void js_call(js_State *J, int n); |
void js_construct(js_State *J, int n); |
const char *js_ref(js_State *J); |
void js_unref(js_State *J, const char *ref); |
void js_getregistry(js_State *J, const char *name); |
void js_setregistry(js_State *J, const char *name); |
void js_delregistry(js_State *J, const char *name); |
void js_getglobal(js_State *J, const char *name); |
void js_setglobal(js_State *J, const char *name); |
void js_defglobal(js_State *J, const char *name, int atts); |
void js_delglobal(js_State *J, const char *name); |
int js_hasproperty(js_State *J, int idx, const char *name); |
void js_getproperty(js_State *J, int idx, const char *name); |
void js_setproperty(js_State *J, int idx, const char *name); |
void js_defproperty(js_State *J, int idx, const char *name, int atts); |
void js_delproperty(js_State *J, int idx, const char *name); |
void js_defaccessor(js_State *J, int idx, const char *name, int atts); |
int js_getlength(js_State *J, int idx); |
void js_setlength(js_State *J, int idx, int len); |
int js_hasindex(js_State *J, int idx, int i); |
void js_getindex(js_State *J, int idx, int i); |
void js_setindex(js_State *J, int idx, int i); |
void js_delindex(js_State *J, int idx, int i); |
void js_currentfunction(js_State *J); |
void js_pushglobal(js_State *J); |
void js_pushundefined(js_State *J); |
void js_pushnull(js_State *J); |
void js_pushboolean(js_State *J, int v); |
void js_pushnumber(js_State *J, double v); |
void js_pushstring(js_State *J, const char *v); |
void js_pushlstring(js_State *J, const char *v, int n); |
void js_pushliteral(js_State *J, const char *v); |
void js_newobjectx(js_State *J); |
void js_newobject(js_State *J); |
void js_newarray(js_State *J); |
void js_newboolean(js_State *J, int v); |
void js_newnumber(js_State *J, double v); |
void js_newstring(js_State *J, const char *v); |
void js_newcfunction(js_State *J, js_CFunction fun, const char *name, int length); |
void js_newcconstructor(js_State *J, js_CFunction fun, js_CFunction con, const char *name, int length); |
void js_newuserdata(js_State *J, const char *tag, void *data, js_Finalize finalize); |
void js_newuserdatax(js_State *J, const char *tag, void *data, js_HasProperty has, js_Put put, js_Delete del, js_Finalize finalize); |
void js_newregexp(js_State *J, const char *pattern, int flags); |
void js_pushiterator(js_State *J, int idx, int own); |
const char *js_nextiterator(js_State *J, int idx); |
int js_isdefined(js_State *J, int idx); |
int js_isundefined(js_State *J, int idx); |
int js_isnull(js_State *J, int idx); |
int js_isboolean(js_State *J, int idx); |
int js_isnumber(js_State *J, int idx); |
int js_isstring(js_State *J, int idx); |
int js_isprimitive(js_State *J, int idx); |
int js_isobject(js_State *J, int idx); |
int js_isarray(js_State *J, int idx); |
int js_isregexp(js_State *J, int idx); |
int js_iscoercible(js_State *J, int idx); |
int js_iscallable(js_State *J, int idx); |
int js_isuserdata(js_State *J, int idx, const char *tag); |
int js_iserror(js_State *J, int idx); |
int js_isnumberobject(js_State *J, int idx); |
int js_isstringobject(js_State *J, int idx); |
int js_toboolean(js_State *J, int idx); |
double js_tonumber(js_State *J, int idx); |
const char *js_tostring(js_State *J, int idx); |
void *js_touserdata(js_State *J, int idx, const char *tag); |
const char *js_trystring(js_State *J, int idx, const char *error); |
double js_trynumber(js_State *J, int idx, double error); |
int js_tryinteger(js_State *J, int idx, int error); |
int js_tryboolean(js_State *J, int idx, int error); |
int js_tointeger(js_State *J, int idx); |
int js_toint32(js_State *J, int idx); |
unsigned int js_touint32(js_State *J, int idx); |
short js_toint16(js_State *J, int idx); |
unsigned short js_touint16(js_State *J, int idx); |
int js_gettop(js_State *J); |
void js_pop(js_State *J, int n); |
void js_rot(js_State *J, int n); |
void js_copy(js_State *J, int idx); |
void js_remove(js_State *J, int idx); |
void js_insert(js_State *J, int idx); |
void js_replace(js_State* J, int idx); |
void js_dup(js_State *J); |
void js_dup2(js_State *J); |
void js_rot2(js_State *J); |
void js_rot3(js_State *J); |
void js_rot4(js_State *J); |
void js_rot2pop1(js_State *J); |
void js_rot3pop2(js_State *J); |
void js_concat(js_State *J); |
int js_compare(js_State *J, int *okay); |
int js_equal(js_State *J); |
int js_strictequal(js_State *J); |
int js_instanceof(js_State *J); |
const char *js_typeof(js_State *J, int idx); |
void js_repr(js_State *J, int idx); |
const char *js_torepr(js_State *J, int idx); |
const char *js_tryrepr(js_State *J, int idx, const char *error); |
#ifdef __cplusplus |
} |
#endif |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/opnames.h |
---|
0,0 → 1,83 |
"pop", |
"dup", |
"dup2", |
"rot2", |
"rot3", |
"rot4", |
"integer", |
"number", |
"string", |
"closure", |
"newarray", |
"newobject", |
"newregexp", |
"undef", |
"null", |
"true", |
"false", |
"this", |
"current", |
"getlocal", |
"setlocal", |
"dellocal", |
"hasvar", |
"getvar", |
"setvar", |
"delvar", |
"in", |
"initprop", |
"initgetter", |
"initsetter", |
"getprop", |
"getprop_s", |
"setprop", |
"setprop_s", |
"delprop", |
"delprop_s", |
"iterator", |
"nextiter", |
"eval", |
"call", |
"new", |
"typeof", |
"pos", |
"neg", |
"bitnot", |
"lognot", |
"inc", |
"dec", |
"postinc", |
"postdec", |
"mul", |
"div", |
"mod", |
"add", |
"sub", |
"shl", |
"shr", |
"ushr", |
"lt", |
"gt", |
"le", |
"ge", |
"eq", |
"ne", |
"stricteq", |
"strictne", |
"jcase", |
"bitand", |
"bitxor", |
"bitor", |
"instanceof", |
"throw", |
"try", |
"endtry", |
"catch", |
"endcatch", |
"with", |
"endwith", |
"debugger", |
"jump", |
"jtrue", |
"jfalse", |
"return", |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/pp.c |
---|
0,0 → 1,115 |
/* Pretty-print input source by emitting parse tree back as syntax. |
* with no flags: pretty-printed source |
* with -m: minified source with line breaks |
* with -mm: minified source without line breaks |
* with -s: s-expression syntax tree |
*/ |
#include <stdio.h> |
#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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/regexp.c |
---|
0,0 → 1,1204 |
#include <stdlib.h> |
#include <stdio.h> |
#include <string.h> |
#include <setjmp.h> |
#include <limits.h> |
#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 |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/regexp.h |
---|
0,0 → 1,46 |
#ifndef regexp_h |
#define regexp_h |
#define regcompx js_regcompx |
#define regfreex js_regfreex |
#define regcomp js_regcomp |
#define regexec js_regexec |
#define regfree js_regfree |
typedef struct Reprog Reprog; |
typedef struct Resub Resub; |
Reprog *regcompx(void *(*alloc)(void *ctx, void *p, int n), void *ctx, |
const char *pattern, int cflags, const char **errorp); |
void regfreex(void *(*alloc)(void *ctx, void *p, int n), void *ctx, |
Reprog *prog); |
Reprog *regcomp(const char *pattern, int cflags, const char **errorp); |
int regexec(Reprog *prog, const char *string, Resub *sub, int eflags); |
void regfree(Reprog *prog); |
enum { |
/* regcomp flags */ |
REG_ICASE = 1, |
REG_NEWLINE = 2, |
/* regexec flags */ |
REG_NOTBOL = 4, |
}; |
/* If you redefine REG_MAXSUB, you must make sure both the calling |
* code and the regexp.c compilation unit use the same value! |
*/ |
#ifndef REG_MAXSUB |
#define REG_MAXSUB 10 |
#endif |
struct Resub { |
int nsub; |
struct { |
const char *sp; |
const char *ep; |
} sub[REG_MAXSUB]; |
}; |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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 <stdlib.h> |
#include <string.h> |
#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<<Bitx)-1, /* 0011 1111 */ |
Testx = Maskx ^ 0xFF, /* 1100 0000 */ |
Bad = Runeerror |
}; |
int |
chartorune(Rune *rune, const char *str) |
{ |
int c, c1, c2, c3; |
int l; |
/* overlong null character */ |
if((uchar)str[0] == 0xc0 && (uchar)str[1] == 0x80) { |
*rune = 0; |
return 2; |
} |
/* |
* one character sequence |
* 00000-0007F => 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++; |
} |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/programs/develop/kosjs/libmujs/utf.h |
---|
0,0 → 1,43 |
#ifndef js_utf_h |
#define js_utf_h |
typedef int Rune; /* 32 bits */ |
#define chartorune jsU_chartorune |
#define runetochar jsU_runetochar |
#define runelen jsU_runelen |
#define utflen jsU_utflen |
#define isalpharune jsU_isalpharune |
#define islowerrune jsU_islowerrune |
#define isspacerune jsU_isspacerune |
#define istitlerune jsU_istitlerune |
#define isupperrune jsU_isupperrune |
#define tolowerrune jsU_tolowerrune |
#define totitlerune jsU_totitlerune |
#define toupperrune jsU_toupperrune |
enum |
{ |
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); |
int runetochar(char *str, const Rune *rune); |
int runelen(int c); |
int utflen(const char *s); |
int isalpharune(Rune c); |
int islowerrune(Rune c); |
int isspacerune(Rune c); |
int istitlerune(Rune c); |
int isupperrune(Rune c); |
Rune tolowerrune(Rune c); |
Rune totitlerune(Rune c); |
Rune toupperrune(Rune c); |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/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; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |