mirror of
https://github.com/ccxvii/mujs.git
synced 2026-02-06 09:51:41 +08:00
Migrate to Codeberg.
This commit is contained in:
16
COPYING
16
COPYING
@@ -1,16 +0,0 @@
|
||||
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.
|
||||
|
||||
172
Makefile
172
Makefile
@@ -1,172 +0,0 @@
|
||||
# Makefile for building MuJS libraries, shell, and pretty-printer.
|
||||
#
|
||||
# Useful targets are: release, install, uninstall.
|
||||
|
||||
default: build/debug/mujs build/debug/mujs-pp
|
||||
|
||||
CFLAGS = -std=c99 -pedantic -Wall -Wextra -Wno-unused-parameter
|
||||
|
||||
OPTIM = -O3
|
||||
|
||||
prefix = /usr/local
|
||||
bindir = $(prefix)/bin
|
||||
incdir = $(prefix)/include
|
||||
libdir = $(prefix)/lib
|
||||
|
||||
ifeq ($(wildcard .git),.git)
|
||||
VERSION = $(shell git describe --tags --always)
|
||||
else
|
||||
VERSION = $(patsubst mujs-%,%,$(notdir $(CURDIR)))
|
||||
endif
|
||||
|
||||
ifeq ($(shell uname),Darwin)
|
||||
SO = dylib
|
||||
else
|
||||
SO = so
|
||||
endif
|
||||
|
||||
ifeq ($(shell uname),FreeBSD)
|
||||
CFLAGS += -I/usr/local/include -L/usr/local/lib
|
||||
endif
|
||||
|
||||
HDRS = mujs.h jsi.h regexp.h utf.h astnames.h opnames.h utfdata.h
|
||||
|
||||
ifneq ($(HAVE_READLINE),no)
|
||||
READLINE_CFLAGS = -DHAVE_READLINE
|
||||
READLINE_LIBS = -lreadline
|
||||
endif
|
||||
|
||||
SRCS = \
|
||||
jsarray.c \
|
||||
jsboolean.c \
|
||||
jsbuiltin.c \
|
||||
jscompile.c \
|
||||
jsdate.c \
|
||||
jsdtoa.c \
|
||||
jserror.c \
|
||||
jsfunction.c \
|
||||
jsgc.c \
|
||||
jsintern.c \
|
||||
jslex.c \
|
||||
jsmath.c \
|
||||
jsnumber.c \
|
||||
jsobject.c \
|
||||
json.c \
|
||||
jsparse.c \
|
||||
jsproperty.c \
|
||||
jsregexp.c \
|
||||
jsrepr.c \
|
||||
jsrun.c \
|
||||
jsstate.c \
|
||||
jsstring.c \
|
||||
jsvalue.c \
|
||||
regexp.c \
|
||||
utf.c
|
||||
|
||||
one.c:
|
||||
for F in $(SRCS); do echo "#include \"$$F\""; done > $@
|
||||
|
||||
astnames.h: jsi.h
|
||||
grep -E '\<(AST|EXP|STM)_' jsi.h | sed 's/^[^A-Z]*\(AST_\)*/"/;s/,.*/",/' | tr A-Z a-z > $@
|
||||
|
||||
opnames.h: jsi.h
|
||||
grep -E '\<OP_' jsi.h | sed 's/^[^A-Z]*OP_/"/;s/,.*/",/' | tr A-Z a-z > $@
|
||||
|
||||
UnicodeData.txt:
|
||||
curl -s -o $@ https://www.unicode.org/Public/16.0.0/ucd/UnicodeData.txt
|
||||
SpecialCasing.txt:
|
||||
curl -s -o $@ https://www.unicode.org/Public/16.0.0/ucd/SpecialCasing.txt
|
||||
|
||||
utfdata.h: genucd.py UnicodeData.txt SpecialCasing.txt
|
||||
python3 genucd.py UnicodeData.txt SpecialCasing.txt >$@
|
||||
|
||||
build/sanitize/mujs: main.c one.c $(SRCS) $(HDRS)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -g -fsanitize=address -fno-omit-frame-pointer -o $@ main.c one.c -lm $(READLINE_CFLAGS) $(READLINE_LIBS)
|
||||
|
||||
build/debug/libmujs.$(SO): one.c $(SRCS) $(HDRS)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -g -fPIC -shared -o $@ one.c -lm
|
||||
build/debug/libmujs.o: one.c $(SRCS) $(HDRS)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -g -c -o $@ one.c
|
||||
build/debug/libmujs.a: build/debug/libmujs.o
|
||||
$(AR) cr $@ $^
|
||||
build/debug/mujs: main.c build/debug/libmujs.o
|
||||
$(CC) $(CFLAGS) -g -o $@ $^ -lm $(READLINE_CFLAGS) $(READLINE_LIBS)
|
||||
build/debug/mujs-pp: pp.c build/debug/libmujs.o
|
||||
$(CC) $(CFLAGS) -g -o $@ $^ -lm
|
||||
|
||||
build/release/libmujs.$(SO): one.c $(SRCS) $(HDRS)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) $(OPTIM) -fPIC -shared -o $@ one.c -lm
|
||||
build/release/libmujs.o: one.c $(SRCS) $(HDRS)
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) $(OPTIM) -c -o $@ one.c
|
||||
build/release/libmujs.a: build/release/libmujs.o
|
||||
$(AR) cr $@ $^
|
||||
build/release/mujs: main.c build/release/libmujs.o
|
||||
$(CC) $(CFLAGS) $(OPTIM) -o $@ $^ -lm $(READLINE_CFLAGS) $(READLINE_LIBS)
|
||||
build/release/mujs-pp: pp.c build/release/libmujs.o
|
||||
$(CC) $(CFLAGS) $(OPTIM) -o $@ $^ -lm
|
||||
|
||||
build/release/mujs.pc:
|
||||
@mkdir -p $(@D)
|
||||
echo > $@ Name: mujs
|
||||
echo >> $@ Description: MuJS embeddable Javascript interpreter
|
||||
echo >> $@ Version: $(VERSION)
|
||||
echo >> $@ Cflags: -I$(incdir)
|
||||
echo >> $@ Libs: -L$(libdir) -lmujs
|
||||
echo >> $@ Libs.private: -lm
|
||||
|
||||
install-common: build/release/mujs build/release/mujs-pp build/release/mujs.pc
|
||||
install -d $(DESTDIR)$(incdir)
|
||||
install -d $(DESTDIR)$(libdir)
|
||||
install -d $(DESTDIR)$(libdir)/pkgconfig
|
||||
install -d $(DESTDIR)$(bindir)
|
||||
install -m 644 mujs.h $(DESTDIR)$(incdir)
|
||||
install -m 644 build/release/mujs.pc $(DESTDIR)$(libdir)/pkgconfig
|
||||
install -m 755 build/release/mujs $(DESTDIR)$(bindir)
|
||||
install -m 755 build/release/mujs-pp $(DESTDIR)$(bindir)
|
||||
|
||||
install-static: install-common build/release/libmujs.a
|
||||
install -m 644 build/release/libmujs.a $(DESTDIR)$(libdir)
|
||||
|
||||
install-shared: install-common build/release/libmujs.$(SO)
|
||||
install -m 755 build/release/libmujs.$(SO) $(DESTDIR)$(libdir)
|
||||
|
||||
install: install-static
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(bindir)/mujs
|
||||
rm -f $(DESTDIR)$(bindir)/mujs-pp
|
||||
rm -f $(DESTDIR)$(incdir)/mujs.h
|
||||
rm -f $(DESTDIR)$(libdir)/pkgconfig/mujs.pc
|
||||
rm -f $(DESTDIR)$(libdir)/libmujs.a
|
||||
rm -f $(DESTDIR)$(libdir)/libmujs.$(SO)
|
||||
|
||||
tarball:
|
||||
git archive --format=zip --prefix=mujs-$(VERSION)/ HEAD > mujs-$(VERSION).zip
|
||||
git archive --format=tar --prefix=mujs-$(VERSION)/ HEAD | gzip > mujs-$(VERSION).tar.gz
|
||||
|
||||
tags: $(SRCS) $(HDRS) main.c pp.c
|
||||
ctags $^
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
nuke: clean
|
||||
rm -f one.c astnames.h opnames.h
|
||||
|
||||
sanitize: build/sanitize/mujs
|
||||
|
||||
debug: build/debug/libmujs.a
|
||||
debug: build/debug/libmujs.$(SO)
|
||||
debug: build/debug/mujs
|
||||
debug: build/debug/mujs-pp
|
||||
|
||||
release: build/release/mujs.pc
|
||||
release: build/release/libmujs.a
|
||||
release: build/release/libmujs.$(SO)
|
||||
release: build/release/mujs
|
||||
release: build/release/mujs-pp
|
||||
50
README
50
README
@@ -1,50 +0,0 @@
|
||||
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/
|
||||
1
README.md
Normal file
1
README.md
Normal file
@@ -0,0 +1 @@
|
||||
This repository has migrated to https://codeberg.org/ccxvii/mujs
|
||||
92
astnames.h
92
astnames.h
@@ -1,92 +0,0 @@
|
||||
"list",
|
||||
"fundec",
|
||||
"identifier",
|
||||
"exp_identifier",
|
||||
"exp_number",
|
||||
"exp_string",
|
||||
"exp_regexp",
|
||||
"exp_elision",
|
||||
"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",
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,224 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href="style.css" rel="stylesheet">
|
||||
<title>MuJS Examples</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>MuJS Examples</h1>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<a href="introduction.html">Introduction</a>
|
||||
<a href="reference.html">Reference</a>
|
||||
<a href="examples.html">Examples</a>
|
||||
<a href="license.html">License</a>
|
||||
<a href="http://git.ghostscript.com/?p=mujs.git;a=summary">Source</a>
|
||||
<a href="https://bugs.ghostscript.com/">Bugs</a>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
|
||||
<h2>A stand-alone interpreter</h2>
|
||||
|
||||
<pre>
|
||||
#include <stdio.h>
|
||||
#include <mujs.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char line[256];
|
||||
js_State *J = js_newstate(NULL, NULL, JS_STRICT);
|
||||
while (fgets(line, sizeof line, stdin))
|
||||
js_dostring(J, line);
|
||||
js_freestate(J);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Hello, world!</h2>
|
||||
|
||||
<pre>
|
||||
#include <stdio.h>
|
||||
#include <mujs.h>
|
||||
|
||||
static void hello(js_State *J)
|
||||
{
|
||||
const char *name = js_tostring(J, 1);
|
||||
printf("Hello, %s!\n", name);
|
||||
js_pushundefined(J);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
js_State *J = js_newstate(NULL, NULL, JS_STRICT);
|
||||
|
||||
js_newcfunction(J, hello, "hello", 1);
|
||||
js_setglobal(J, "hello");
|
||||
|
||||
js_dostring(J, "hello('world');");
|
||||
|
||||
js_freestate(J);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Configuration file</h2>
|
||||
|
||||
<pre>
|
||||
js_dofile(J, "config.js")
|
||||
|
||||
js_getglobal(J, "foo");
|
||||
foo = js_tonumber(J, -1);
|
||||
js_pop(J, 1);
|
||||
</pre>
|
||||
|
||||
<h2>Object manipulation</h2>
|
||||
|
||||
<pre>
|
||||
// t = { foo: 42, bar: true }
|
||||
|
||||
js_newobject(J);
|
||||
{
|
||||
js_pushnumber(J, 42);
|
||||
js_setproperty(J, -2, "foo");
|
||||
js_pushboolean(J, 1);
|
||||
js_setproperty(J, -2, "bar");
|
||||
}
|
||||
js_setglobal(J, "t");
|
||||
</pre>
|
||||
|
||||
<h2>Callbacks from C to JS (by name)</h2>
|
||||
|
||||
<pre>
|
||||
static int call_callback(js_State *J, const char *arg1, int arg2)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Find the function to call. */
|
||||
js_getglobal(J, "my_callback");
|
||||
|
||||
/* Push arguments to function. */
|
||||
js_pushnull(J); /* the 'this' object to use */
|
||||
js_pushstring(J, arg1);
|
||||
js_pushnumber(J, arg2);
|
||||
|
||||
/* Call function and check for exceptions. */
|
||||
if (js_pcall(J, 2)) {
|
||||
fprintf(stderr, "an exception occurred in the javascript callback\n");
|
||||
js_pop(J, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Retrieve return value. */
|
||||
result = js_tonumber(J, -1);
|
||||
js_pop(J, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Callbacks from C to JS</h2>
|
||||
|
||||
<pre>
|
||||
const char *handle = NULL; /* handle to stowed away js function */
|
||||
|
||||
static void set_callback(js_State *J)
|
||||
{
|
||||
if (handle)
|
||||
js_unref(J, handle); /* delete old function */
|
||||
js_copy(J, 1);
|
||||
handle = js_ref(J); /* stow the js function in the registry */
|
||||
}
|
||||
|
||||
static void call_callback(js_State *J, int arg1, int arg2)
|
||||
{
|
||||
js_getregistry(J, handle); /* retrieve the js function from the registry */
|
||||
js_pushnull(J);
|
||||
js_pushnumber(J, arg1);
|
||||
js_pushnumber(J, arg2);
|
||||
js_pcall(J, 2);
|
||||
js_pop(J, 1);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Complete userdata example</h2>
|
||||
|
||||
<pre>
|
||||
#include <stdio.h>
|
||||
#include <mujs.h>
|
||||
|
||||
#define TAG "File"
|
||||
|
||||
static void new_File(js_State *J)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
if (js_isundefined(J, 1)) {
|
||||
file = stdin;
|
||||
} else {
|
||||
const char *filename = js_tostring(J, 1);
|
||||
file = fopen(filename, "r");
|
||||
if (!file)
|
||||
js_error(J, "cannot open file: '%s'", filename);
|
||||
}
|
||||
|
||||
js_currentfunction(J);
|
||||
js_getproperty(J, -1, "prototype");
|
||||
js_newuserdata(J, TAG, file);
|
||||
}
|
||||
|
||||
static void File_prototype_readByte(js_State *J)
|
||||
{
|
||||
FILE *file = js_touserdata(J, 0, TAG);
|
||||
js_pushnumber(J, getc(file));
|
||||
}
|
||||
|
||||
static void File_prototype_readLine(js_State *J)
|
||||
{
|
||||
char line[256], *s;
|
||||
FILE *file = js_touserdata(J, 0, TAG);
|
||||
s = fgets(line, sizeof line, file);
|
||||
if (s)
|
||||
js_pushstring(J, line);
|
||||
else
|
||||
js_pushnull(J);
|
||||
}
|
||||
|
||||
static void File_prototype_close(js_State *J)
|
||||
{
|
||||
FILE *file = js_touserdata(J, 0, TAG);
|
||||
fclose(file);
|
||||
js_pushundefined(J);
|
||||
}
|
||||
|
||||
void initfile(js_State *J)
|
||||
{
|
||||
js_getglobal(J, "Object");
|
||||
js_getproperty(J, -1, "prototype"); // File.prototype.[[Prototype]] = Object.prototype
|
||||
js_newuserdata(J, TAG, stdin); // File.prototype.[[Userdata]] = stdin
|
||||
{
|
||||
js_newcfunction(J, File_prototype_readByte, "File.prototype.readByte", 0);
|
||||
js_defproperty(J, -2, "readByte", JS_DONTENUM);
|
||||
|
||||
js_newcfunction(J, File_prototype_readLine, "File.prototype.readLine", 0);
|
||||
js_defproperty(J, -2, "readLine", JS_DONTENUM);
|
||||
|
||||
js_newcfunction(J, File_prototype_close, "File.prototype.close", 0);
|
||||
js_defproperty(J, -2, "close", JS_DONTENUM);
|
||||
}
|
||||
js_newcconstructor(J, new_File, new_File, "File", 1);
|
||||
js_defglobal(J, "File", JS_DONTENUM);
|
||||
}
|
||||
</pre>
|
||||
|
||||
</article>
|
||||
|
||||
<footer>
|
||||
<a href="http://artifex.com"><img src="artifex-logo.png" align="right"></a>
|
||||
Copyright © 2013-2017 Artifex Software Inc.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,58 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href="style.css" rel="stylesheet">
|
||||
<title>MuJS</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>MuJS</h1>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<a href="introduction.html">Introduction</a>
|
||||
<a href="reference.html">Reference</a>
|
||||
<a href="examples.html">Examples</a>
|
||||
<a href="license.html">License</a>
|
||||
<a href="http://git.ghostscript.com/?p=mujs.git;a=summary">Source</a>
|
||||
<a href="https://bugs.ghostscript.com/">Bugs</a>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
|
||||
<p>
|
||||
MuJS is a lightweight Javascript interpreter designed for embedding in other
|
||||
software to extend them with scripting capabilities.
|
||||
|
||||
<p>
|
||||
MuJS was designed with a focus on small size, correctness, and simplicity.
|
||||
It is written in portable C and implements ECMAScript as specified by ECMA-262.
|
||||
The interface for binding with native code is designed to be as simple as
|
||||
possible to use, and is very similar to Lua. There is no need to interact with
|
||||
byzantine C++ template mechanisms, or worry about marking and unmarking garbage
|
||||
collection roots, or wrestle with obscure build systems.
|
||||
|
||||
<p>
|
||||
MuJS is developed and maintained by Artifex Software.
|
||||
It was originally developed for use with the MuPDF viewer, but is designed to be useful as an independent component.
|
||||
|
||||
<p>
|
||||
The primary meeting place for the MuJS community is the
|
||||
<a href="http://webchat.freenode.net/?channels=mupdf">#mupdf</a>
|
||||
IRC channel on freenode.
|
||||
|
||||
<p>
|
||||
MuJS is free open source software distributed under the
|
||||
<a href="https://opensource.org/licenses/ISC">ISC license</a>.
|
||||
|
||||
</article>
|
||||
|
||||
<footer>
|
||||
<a href="http://artifex.com"><img src="artifex-logo.png" align="right"></a>
|
||||
Copyright © 2013-2017 Artifex Software Inc.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,108 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href="style.css" rel="stylesheet">
|
||||
<title>MuJS Introduction</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>MuJS Introduction</h1>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<a href="introduction.html">Introduction</a>
|
||||
<a href="reference.html">Reference</a>
|
||||
<a href="examples.html">Examples</a>
|
||||
<a href="license.html">License</a>
|
||||
<a href="http://git.ghostscript.com/?p=mujs.git;a=summary">Source</a>
|
||||
<a href="https://bugs.ghostscript.com/">Bugs</a>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
|
||||
<h2>Why choose MuJS?</h2>
|
||||
|
||||
<h3>Javascript is a proven scripting language</h3>
|
||||
|
||||
<p>
|
||||
Javascript is one of the most popular programming languages in the world.
|
||||
It is a powerful extension language, used everywhere on the web — both as
|
||||
a way to add interactivity to web pages in the browser, and on the server side
|
||||
with platforms like node.js.
|
||||
|
||||
<p>
|
||||
With MuJS you can bring this power to your application as well!
|
||||
|
||||
<h3>MuJS is standards compliant</h3>
|
||||
|
||||
<p>
|
||||
MuJS implements ES5.
|
||||
There are no non-standard extensions, so you can remain confident that
|
||||
Javascript code that runs on MuJS will also run on any other standards
|
||||
compliant Javascript implementation.
|
||||
|
||||
<h3>MuJS is portable</h3>
|
||||
|
||||
<p>
|
||||
MuJS is written in portable C and can be built by compiling a single C file using any standard C compiler.
|
||||
There is no need for configuration or fancy build systems.
|
||||
MuJS runs on all flavors of Unix and Windows, on mobile devices (such as Android and iOS),
|
||||
embedded microprocessors (such as the Beagle board and Raspberry Pi), etc.
|
||||
|
||||
<h3>MuJS is embeddable</h3>
|
||||
|
||||
<p>
|
||||
MuJS is a simple language engine with a small footprint that you can easily embed into your application.
|
||||
The API is simple and well documented and allows strong integration with code written in other languages.
|
||||
You don't need to work with byzantine C++ templating mechanisms, or manually manage garbage collection roots.
|
||||
It is easy to extend MuJS with libraries written in other languages.
|
||||
It is also easy to extend programs written in other languages with MuJS.
|
||||
|
||||
<h3>MuJS is small</h3>
|
||||
|
||||
<p>
|
||||
Adding MuJS to an application does not bloat it.
|
||||
The source contains around 15'000 lines of C.
|
||||
Under 64-bit Linux, the compiled library takes 180kB if optimized for size,
|
||||
and 260kB if optimized for speed.
|
||||
|
||||
Compare this with V8, SpiderMonkey or JavaScriptCore,
|
||||
which are all several hundred thousand lines of code,
|
||||
take several megabytes of space,
|
||||
and require the C++ runtime.
|
||||
|
||||
<h3>MuJS is reasonably fast and secure</h3>
|
||||
|
||||
<p>
|
||||
It is a bytecode interpreter with a very fast mechanism to call-out to C.
|
||||
The default build is sandboxed with very restricted access to resources.
|
||||
Due to the nature of bytecode, MuJS is not as fast as JIT compiling
|
||||
implementations but starts up faster and uses fewer resources.
|
||||
If you implement heavy lifting in C code, controlled by Javascript,
|
||||
you can get the best of both worlds.
|
||||
|
||||
<h3>MuJS is free software</h3>
|
||||
|
||||
<p>
|
||||
MuJS is free open source software distributed under the
|
||||
<a href="https://opensource.org/licenses/ISC">ISC license</a>.
|
||||
|
||||
<h3>MuJS is developed by a stable company</h3>
|
||||
|
||||
<p>
|
||||
<a href="http://artifex.com/">Artifex Software</a> has long experience in
|
||||
interpreters and page description languages, and has a history with open source
|
||||
that goes back to 1993 when it was created to facilitate licensing Ghostscript
|
||||
to OEMs.
|
||||
|
||||
</article>
|
||||
|
||||
<footer>
|
||||
<a href="http://artifex.com"><img src="artifex-logo.png" align="right"></a>
|
||||
Copyright © 2013-2017 Artifex Software Inc.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,50 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href="style.css" rel="stylesheet">
|
||||
<title>MuJS License</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>MuJS License</h1>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<a href="introduction.html">Introduction</a>
|
||||
<a href="reference.html">Reference</a>
|
||||
<a href="examples.html">Examples</a>
|
||||
<a href="license.html">License</a>
|
||||
<a href="http://git.ghostscript.com/?p=mujs.git;a=summary">Source</a>
|
||||
<a href="https://bugs.ghostscript.com/">Bugs</a>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
|
||||
<p>
|
||||
MuJS is Copyright © 2013-2017 Artifex Software, Inc.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
<p>
|
||||
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.
|
||||
|
||||
</article>
|
||||
|
||||
<footer>
|
||||
<a href="http://artifex.com"><img src="artifex-logo.png" align="right"></a>
|
||||
Copyright © 2013-2017 Artifex Software Inc.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
47
docs/logo.ps
47
docs/logo.ps
@@ -1,47 +0,0 @@
|
||||
%!
|
||||
<</PageSize[512 512]>>setpagedevice
|
||||
|
||||
% #323330 = 50 51 48
|
||||
% #F0DB4F = 240 219 79
|
||||
% #4386b5 = 67 134 181
|
||||
|
||||
/cG { 50 255 div 51 255 div 48 255 div setrgbcolor } def
|
||||
/cY { 240 255 div 219 255 div 79 255 div setrgbcolor } def
|
||||
/cB { 67 255 div 134 255 div 181 255 div setrgbcolor } def
|
||||
|
||||
% fill background with yellow
|
||||
cY
|
||||
0 0 moveto 512 0 lineto 512 512 lineto 0 512 lineto closepath fill
|
||||
|
||||
% move logo to lower right corner
|
||||
512 0.2 mul 0 translate
|
||||
0.8 0.8 scale
|
||||
|
||||
% center logo
|
||||
0.875 0.875 scale
|
||||
32 32 translate
|
||||
|
||||
% draw electrons and nucleus
|
||||
cG
|
||||
gsave
|
||||
256 256 translate
|
||||
|
||||
16 setlinewidth
|
||||
gsave 0 rotate .5 1 scale 0 0 232 0 360 arc stroke grestore
|
||||
gsave 60 rotate .5 1 scale 0 0 232 0 360 arc stroke grestore
|
||||
gsave 120 rotate .5 1 scale 0 0 232 0 360 arc stroke grestore
|
||||
|
||||
0 0 96 0 360 arc fill
|
||||
grestore
|
||||
|
||||
% draw yellow 'JS' text in center of nucleus
|
||||
cY
|
||||
gsave
|
||||
/SourceSansPro-Bold findfont 128 scalefont setfont
|
||||
256 256 moveto
|
||||
(JS)
|
||||
dup stringwidth pop -2 div -44 rmoveto
|
||||
show
|
||||
grestore
|
||||
|
||||
showpage
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.9 KiB |
File diff suppressed because it is too large
Load Diff
@@ -1,40 +0,0 @@
|
||||
h1, nav, footer { font-family: sans-serif; }
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
h2 { font-size: 1.25rem; }
|
||||
h3 { font-size: 1.12rem; }
|
||||
ul li { list-style-type: circle; }
|
||||
pre, table, ol, dl { margin-left: 2rem; }
|
||||
li { margin: 0; }
|
||||
th, td { text-align: left; vertical-align: top; }
|
||||
|
||||
body { margin: 0; }
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
header{
|
||||
color: white;
|
||||
background: no-repeat;
|
||||
background-color: #36648b;
|
||||
background-image: url("mujs-logo.png");
|
||||
background-position: top right;
|
||||
min-height: 72px;
|
||||
}
|
||||
nav {
|
||||
padding: 0.75rem 2rem;
|
||||
background-color: #ddd;
|
||||
no-text-transform: uppercase;
|
||||
}
|
||||
nav a { color: #303030; padding-right: 2rem; }
|
||||
article {
|
||||
max-width: 50rem;
|
||||
margin: 2rem;
|
||||
}
|
||||
footer {
|
||||
background-color: #ddd;
|
||||
color: #303030;
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
117
genucd.py
117
genucd.py
@@ -1,117 +0,0 @@
|
||||
# Create utfdata.h from UnicodeData.txt and SpecialCasing.txt
|
||||
|
||||
import sys
|
||||
|
||||
tolower = []
|
||||
toupper = []
|
||||
tolower_full = []
|
||||
toupper_full = []
|
||||
isalpha = []
|
||||
|
||||
for line in open(sys.argv[1]).readlines():
|
||||
line = line.split(";")
|
||||
code = int(line[0],16)
|
||||
# if code > 65535: continue # skip non-BMP codepoints
|
||||
if line[2][0] == 'L':
|
||||
isalpha.append(code)
|
||||
if line[12]:
|
||||
toupper.append((code,int(line[12],16)))
|
||||
if line[13]:
|
||||
tolower.append((code,int(line[13],16)))
|
||||
|
||||
for line in open(sys.argv[2]).readlines():
|
||||
# SpecialCasing.txt -- code; lower; title; upper; (condition;)? # comment
|
||||
line = line.strip()
|
||||
if len(line) == 0:
|
||||
continue
|
||||
if line[0] == "#":
|
||||
continue
|
||||
line = line.split(";")
|
||||
code = int(line[0],16)
|
||||
lower = line[1].strip()
|
||||
upper = line[3].strip()
|
||||
if len(lower) == 0 or len(upper) == 0:
|
||||
continue
|
||||
condition = line[4].split("#")[0].strip()
|
||||
if len(condition) > 0:
|
||||
continue
|
||||
lower = list(map(lambda x: int(x,16), lower.split(" ")))
|
||||
upper = list(map(lambda x: int(x,16), upper.split(" ")))
|
||||
if lower[0] != code:
|
||||
tolower_full.append([code] + lower)
|
||||
if upper[0] != code:
|
||||
toupper_full.append([code] + upper)
|
||||
|
||||
tolower_full.sort()
|
||||
toupper_full.sort()
|
||||
|
||||
def dumpalpha():
|
||||
table = []
|
||||
prev = 0
|
||||
start = 0
|
||||
for code in isalpha:
|
||||
if code != prev+1:
|
||||
if start:
|
||||
table.append((start,prev))
|
||||
start = code
|
||||
prev = code
|
||||
table.append((start,prev))
|
||||
|
||||
print("")
|
||||
print("static const Rune ucd_alpha2[] = {")
|
||||
for a, b in table:
|
||||
if b - a > 0:
|
||||
print(hex(a)+","+hex(b)+",")
|
||||
print("};");
|
||||
|
||||
print("")
|
||||
print("static const Rune ucd_alpha1[] = {")
|
||||
for a, b in table:
|
||||
if b - a == 0:
|
||||
print(hex(a)+",")
|
||||
print("};");
|
||||
|
||||
def dumpmap(name, input):
|
||||
table = []
|
||||
prev_a = 0
|
||||
prev_b = 0
|
||||
start_a = 0
|
||||
start_b = 0
|
||||
for a, b in input:
|
||||
if a != prev_a+1 or b != prev_b+1:
|
||||
if start_a:
|
||||
table.append((start_a,prev_a,start_b))
|
||||
start_a = a
|
||||
start_b = b
|
||||
prev_a = a
|
||||
prev_b = b
|
||||
table.append((start_a,prev_a,start_b))
|
||||
|
||||
print("")
|
||||
print("static const Rune " + name + "2[] = {")
|
||||
for a, b, n in table:
|
||||
if b - a > 0:
|
||||
print(hex(a)+","+hex(b)+","+str(n-a)+",")
|
||||
print("};");
|
||||
|
||||
print("")
|
||||
print("static const Rune " + name + "1[] = {")
|
||||
for a, b, n in table:
|
||||
if b - a == 0:
|
||||
print(hex(a)+","+str(n-a)+",")
|
||||
print("};");
|
||||
|
||||
def dumpmultimap(name, table, w):
|
||||
print("")
|
||||
print("static const Rune " + name + "[] = {")
|
||||
for list in table:
|
||||
list += [0] * (w - len(list))
|
||||
print(",".join(map(hex, list)) + ",")
|
||||
print("};")
|
||||
|
||||
print("/* This file was automatically created from " + sys.argv[1] + " */")
|
||||
dumpalpha()
|
||||
dumpmap("ucd_tolower", tolower)
|
||||
dumpmap("ucd_toupper", toupper)
|
||||
dumpmultimap("ucd_tolower_full", tolower_full, 4)
|
||||
dumpmultimap("ucd_toupper_full", toupper_full, 5)
|
||||
38
jsboolean.c
38
jsboolean.c
@@ -1,38 +0,0 @@
|
||||
#include "jsi.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);
|
||||
}
|
||||
249
jsbuiltin.c
249
jsbuiltin.c
@@ -1,249 +0,0 @@
|
||||
#include "jsi.h"
|
||||
#include "regexp.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) : 0;
|
||||
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 = js_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)
|
||||
{
|
||||
/* NOTE: volatile to silence GCC warning about longjmp clobbering a variable */
|
||||
const char * volatile str = str_;
|
||||
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)
|
||||
{
|
||||
/* NOTE: volatile to silence GCC warning about longjmp clobbering a variable */
|
||||
const char * volatile str = str_;
|
||||
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->Date_prototype = jsV_newobject(J, JS_CDATE, J->Object_prototype);
|
||||
|
||||
J->RegExp_prototype = jsV_newobject(J, JS_CREGEXP, J->Object_prototype);
|
||||
J->RegExp_prototype->u.r.prog = js_regcompx(J->alloc, J->actx, "(?:)", 0, NULL);
|
||||
J->RegExp_prototype->u.r.source = js_strdup(J, "(?:)");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
1428
jscompile.c
1428
jscompile.c
File diff suppressed because it is too large
Load Diff
128
jserror.c
128
jserror.c
@@ -1,128 +0,0 @@
|
||||
#include "jsi.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)
|
||||
{
|
||||
js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
|
||||
if (js_isdefined(J, 1)) {
|
||||
js_pushstring(J, js_tostring(J, 1));
|
||||
js_defproperty(J, -2, "message", JS_DONTENUM);
|
||||
}
|
||||
if (jsB_stacktrace(J, 1))
|
||||
js_defproperty(J, -2, "stack", 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, "stack");
|
||||
}
|
||||
|
||||
#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_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
|
||||
}
|
||||
231
jsfunction.c
231
jsfunction.c
@@ -1,231 +0,0 @@
|
||||
#include "jsi.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) {
|
||||
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);
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
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);
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
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);
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
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);
|
||||
}
|
||||
284
jsgc.c
284
jsgc.c
@@ -1,284 +0,0 @@
|
||||
#include "jsi.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->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_CSTRING) {
|
||||
if (obj->u.s.string != obj->u.s.shrstr)
|
||||
js_free(J, obj->u.s.string);
|
||||
}
|
||||
if (obj->type == JS_CARRAY && obj->u.a.simple)
|
||||
js_free(J, obj->u.a.array);
|
||||
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);
|
||||
if (obj->type == JS_CCFUNCTION && obj->u.c.finalize)
|
||||
obj->u.c.finalize(J, obj->u.c.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.t.type == JS_TMEMSTR && node->value.u.memstr->gcmark != mark)
|
||||
node->value.u.memstr->gcmark = mark;
|
||||
if (node->value.t.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_CARRAY && obj->u.a.simple) {
|
||||
int i;
|
||||
for (i = 0; i < obj->u.a.flat_length; ++i) {
|
||||
js_Value *v = &obj->u.a.array[i];
|
||||
if (v->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
|
||||
v->u.memstr->gcmark = mark;
|
||||
if (v->t.type == JS_TOBJECT && v->u.object->gcmark != mark)
|
||||
jsG_markobject(J, mark, v->u.object);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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->t.type == JS_TMEMSTR && v->u.memstr->gcmark != mark)
|
||||
v->u.memstr->gcmark = mark;
|
||||
if (v->t.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;
|
||||
|
||||
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);
|
||||
}
|
||||
137
jsintern.c
137
jsintern.c
@@ -1,137 +0,0 @@
|
||||
#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)
|
||||
{
|
||||
size_t n = strlen(string);
|
||||
if (n > JS_STRLIMIT)
|
||||
js_rangeerror(J, "invalid string length");
|
||||
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;
|
||||
}
|
||||
194
jsmath.c
194
jsmath.c
@@ -1,194 +0,0 @@
|
||||
#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 <time.h>
|
||||
|
||||
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)
|
||||
{
|
||||
/* Lehmer generator with a=48271 and m=2^31-1 */
|
||||
/* Park & Miller (1988). Random Number Generators: Good ones are hard to find. */
|
||||
J->seed = (uint64_t) J->seed * 48271 % 0x7fffffff;
|
||||
js_pushnumber(J, (double) J->seed / 0x7fffffff);
|
||||
}
|
||||
|
||||
static void Math_init_random(js_State *J)
|
||||
{
|
||||
/* Pick initial seed by scrambling current time with Xorshift. */
|
||||
/* Marsaglia (2003). Xorshift RNGs. */
|
||||
J->seed = time(0) + 123;
|
||||
J->seed ^= J->seed << 13;
|
||||
J->seed ^= J->seed >> 17;
|
||||
J->seed ^= J->seed << 5;
|
||||
J->seed %= 0x7fffffff;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Math_init_random(J);
|
||||
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);
|
||||
}
|
||||
198
jsnumber.c
198
jsnumber.c
@@ -1,198 +0,0 @@
|
||||
#include "jsi.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);
|
||||
double x = 0;
|
||||
if (self->type != JS_CNUMBER)
|
||||
js_typeerror(J, "not a number");
|
||||
x = self->u.number;
|
||||
if (radix == 10) {
|
||||
js_pushstring(J, jsV_numbertostring(J, buf, x));
|
||||
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 = x;
|
||||
int sign = x < 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, x);
|
||||
}
|
||||
|
||||
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, x);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
560
jsobject.c
560
jsobject.c
File diff suppressed because it is too large
Load Diff
422
json.c
422
json.c
@@ -1,422 +0,0 @@
|
||||
#include "jsi.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;
|
||||
}
|
||||
|
||||
int js_isbooleanobject(js_State *J, int idx)
|
||||
{
|
||||
return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CBOOLEAN;
|
||||
}
|
||||
|
||||
int js_isdateobject(js_State *J, int idx)
|
||||
{
|
||||
return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CDATE;
|
||||
}
|
||||
|
||||
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 < ' ' || (c >= 0xd800 && c <= 0xdfff)) {
|
||||
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];
|
||||
/* NOTE: volatile to silence GCC warning about longjmp clobbering a variable */
|
||||
const char * volatile gap;
|
||||
const char *s;
|
||||
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);
|
||||
}
|
||||
341
jsproperty.c
341
jsproperty.c
@@ -1,341 +0,0 @@
|
||||
#include "jsi.h"
|
||||
|
||||
#include <assert.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}, JS_TUNDEFINED } },
|
||||
NULL, NULL, ""
|
||||
};
|
||||
|
||||
static js_Property *newproperty(js_State *J, js_Object *obj, const char *name)
|
||||
{
|
||||
int n = strlen(name) + 1;
|
||||
js_Property *node = js_malloc(J, offsetof(js_Property, name) + n);
|
||||
node->left = node->right = &sentinel;
|
||||
node->level = 1;
|
||||
node->atts = 0;
|
||||
node->value.t.type = JS_TUNDEFINED;
|
||||
node->value.u.number = 0;
|
||||
node->getter = NULL;
|
||||
node->setter = NULL;
|
||||
memcpy(node->name, name, n);
|
||||
++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 *unlinkproperty(js_Property *node, const char *name, js_Property **garbage)
|
||||
{
|
||||
js_Property *temp, *a, *b;
|
||||
if (node != &sentinel) {
|
||||
int c = strcmp(name, node->name);
|
||||
if (c < 0) {
|
||||
node->left = unlinkproperty(node->left, name, garbage);
|
||||
} else if (c > 0) {
|
||||
node->right = unlinkproperty(node->right, name, garbage);
|
||||
} else {
|
||||
*garbage = node;
|
||||
if (node->left == &sentinel && node->right == &sentinel) {
|
||||
return &sentinel;
|
||||
}
|
||||
else if (node->left == &sentinel) {
|
||||
a = node->right;
|
||||
while (a->left != &sentinel)
|
||||
a = a->left;
|
||||
b = unlinkproperty(node->right, a->name, &temp);
|
||||
temp->level = node->level;
|
||||
temp->left = node->left;
|
||||
temp->right = b;
|
||||
node = temp;
|
||||
}
|
||||
else {
|
||||
a = node->left;
|
||||
while (a->right != &sentinel)
|
||||
a = a->right;
|
||||
b = unlinkproperty(node->left, a->name, &temp);
|
||||
temp->level = node->level;
|
||||
temp->left = b;
|
||||
temp->right = node->right;
|
||||
node = temp;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static js_Property *deleteproperty(js_State *J, js_Object *obj, js_Property *tree, const char *name)
|
||||
{
|
||||
js_Property *garbage = &sentinel;
|
||||
tree = unlinkproperty(tree, name, &garbage);
|
||||
if (garbage != &sentinel)
|
||||
freeproperty(J, obj, garbage);
|
||||
return tree;
|
||||
}
|
||||
|
||||
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 = deleteproperty(J, obj, obj->properties, name);
|
||||
}
|
||||
|
||||
/* Flatten hierarchy of enumerable properties into an iterator object */
|
||||
|
||||
static js_Iterator *itnewnode(js_State *J, const char *name, js_Iterator *next) {
|
||||
int n = strlen(name) + 1;
|
||||
js_Iterator *node = js_malloc(J, offsetof(js_Iterator, name) + n);
|
||||
node->next = next;
|
||||
memcpy(node->name, name, n);
|
||||
return node;
|
||||
}
|
||||
|
||||
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)) {
|
||||
iter = itnewnode(J, prop->name, iter);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
js_Object *io = jsV_newobject(J, JS_CITERATOR, NULL);
|
||||
io->u.iter.target = obj;
|
||||
io->u.iter.i = 0;
|
||||
io->u.iter.n = 0;
|
||||
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);
|
||||
}
|
||||
io->u.iter.current = io->u.iter.head;
|
||||
|
||||
if (obj->type == JS_CSTRING)
|
||||
io->u.iter.n = obj->u.s.length;
|
||||
|
||||
if (obj->type == JS_CARRAY && obj->u.a.simple)
|
||||
io->u.iter.n = obj->u.a.flat_length;
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
const char *jsV_nextiterator(js_State *J, js_Object *io)
|
||||
{
|
||||
if (io->type != JS_CITERATOR)
|
||||
js_typeerror(J, "not an iterator");
|
||||
if (io->u.iter.i < io->u.iter.n) {
|
||||
js_itoa(J->scratch, io->u.iter.i);
|
||||
io->u.iter.i++;
|
||||
return J->scratch;
|
||||
}
|
||||
while (io->u.iter.current) {
|
||||
const char *name = io->u.iter.current->name;
|
||||
io->u.iter.current = io->u.iter.current->next;
|
||||
if (jsV_getproperty(J, io->u.iter.target, name))
|
||||
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;
|
||||
assert(!obj->u.a.simple);
|
||||
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;
|
||||
}
|
||||
232
jsregexp.c
232
jsregexp.c
@@ -1,232 +0,0 @@
|
||||
#include "jsi.h"
|
||||
#include "regexp.h"
|
||||
|
||||
static char *escaperegexp(js_State *J, const char *pattern) {
|
||||
char *copy, *p;
|
||||
const char *s;
|
||||
int n = 0;
|
||||
for (s = pattern; *s; ++s) {
|
||||
if (*s == '/')
|
||||
++n;
|
||||
++n;
|
||||
}
|
||||
copy = p = js_malloc(J, n+1);
|
||||
for (s = pattern; *s; ++s) {
|
||||
if (*s == '/')
|
||||
*p++ = '\\';
|
||||
*p++ = *s;
|
||||
}
|
||||
*p = 0;
|
||||
return copy;
|
||||
}
|
||||
|
||||
static void js_newregexpx(js_State *J, const char *pattern, int flags, int is_clone)
|
||||
{
|
||||
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 = is_clone ? js_strdup(J, pattern) : escaperegexp(J, pattern);
|
||||
obj->u.r.flags = flags;
|
||||
obj->u.r.last = 0;
|
||||
js_pushobject(J, obj);
|
||||
}
|
||||
|
||||
void js_newregexp(js_State *J, const char *pattern, int flags)
|
||||
{
|
||||
js_newregexpx(J, pattern, flags, 0);
|
||||
}
|
||||
|
||||
void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text)
|
||||
{
|
||||
const char *haystack;
|
||||
int result;
|
||||
int i;
|
||||
int opts;
|
||||
Resub m;
|
||||
|
||||
haystack = text;
|
||||
opts = 0;
|
||||
if (re->flags & JS_REGEXP_G) {
|
||||
if (re->last > strlen(haystack)) {
|
||||
re->last = 0;
|
||||
js_pushnull(J);
|
||||
return;
|
||||
}
|
||||
if (re->last > 0) {
|
||||
haystack = text + re->last;
|
||||
opts |= REG_NOTBOL;
|
||||
}
|
||||
}
|
||||
|
||||
result = js_regexec(re->prog, haystack, &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 = 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;
|
||||
int is_clone = 0;
|
||||
|
||||
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;
|
||||
is_clone = 1;
|
||||
} 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_newregexpx(J, pattern, flags, is_clone);
|
||||
}
|
||||
|
||||
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 * volatile out = NULL;
|
||||
|
||||
re = js_toregexp(J, 0);
|
||||
|
||||
if (js_try(J)) {
|
||||
js_free(J, out);
|
||||
js_throw(J);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
}
|
||||
285
jsrepr.c
285
jsrepr.c
@@ -1,285 +0,0 @@
|
||||
#include "jsi.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:
|
||||
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, '(');
|
||||
if (js_hasproperty(J, -1, "message")) {
|
||||
reprvalue(J, sb);
|
||||
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;
|
||||
}
|
||||
334
jsstate.c
334
jsstate.c
@@ -1,334 +0,0 @@
|
||||
#include "jsi.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
static int js_ptry(js_State *J) {
|
||||
if (J->trytop == JS_TRYLIMIT) {
|
||||
J->stack[J->top].t.type = JS_TLITSTR;
|
||||
J->stack[J->top].u.litstr = "exception stack overflow";
|
||||
++J->top;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *js_defaultalloc(void *actx, void *ptr, int size)
|
||||
{
|
||||
if (size == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
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_ptry(J))
|
||||
return 1;
|
||||
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_ptry(J))
|
||||
return 1;
|
||||
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_ptry(J)) {
|
||||
js_pop(J, 1);
|
||||
return error;
|
||||
}
|
||||
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_ptry(J)) {
|
||||
js_pop(J, 1);
|
||||
return error;
|
||||
}
|
||||
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_ptry(J)) {
|
||||
js_pop(J, 1);
|
||||
return error;
|
||||
}
|
||||
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_ptry(J)) {
|
||||
js_pop(J, 1);
|
||||
return error;
|
||||
}
|
||||
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);
|
||||
|
||||
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_ptry(J)) {
|
||||
js_report(J, "exception stack overflow");
|
||||
js_pop(J, 1);
|
||||
return 1;
|
||||
}
|
||||
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_ptry(J)) {
|
||||
js_report(J, "exception stack overflow");
|
||||
js_pop(J, 1);
|
||||
return 1;
|
||||
}
|
||||
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, t.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, J, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
J->gcmark = 1;
|
||||
J->nextref = 0;
|
||||
J->gcthresh = 0; /* reaches stability within ~ 2-5 GC cycles */
|
||||
|
||||
if (js_try(J)) {
|
||||
js_freestate(J);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
js_endtry(J);
|
||||
return J;
|
||||
}
|
||||
852
jsstring.c
852
jsstring.c
File diff suppressed because it is too large
Load Diff
394
main.c
394
main.c
@@ -1,394 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "mujs.h"
|
||||
|
||||
static char *xoptarg; /* Global argument pointer. */
|
||||
static int xoptind = 0; /* Global argv index. */
|
||||
static int xgetopt(int argc, char *argv[], char *optstring)
|
||||
{
|
||||
static char *scan = NULL; /* Private scan pointer. */
|
||||
|
||||
char c;
|
||||
char *place;
|
||||
|
||||
xoptarg = NULL;
|
||||
|
||||
if (!scan || *scan == '\0') {
|
||||
if (xoptind == 0)
|
||||
xoptind++;
|
||||
|
||||
if (xoptind >= argc || argv[xoptind][0] != '-' || argv[xoptind][1] == '\0')
|
||||
return EOF;
|
||||
if (argv[xoptind][1] == '-' && argv[xoptind][2] == '\0') {
|
||||
xoptind++;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
scan = argv[xoptind]+1;
|
||||
xoptind++;
|
||||
}
|
||||
|
||||
c = *scan++;
|
||||
place = strchr(optstring, c);
|
||||
|
||||
if (!place || c == ':') {
|
||||
fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
|
||||
return '?';
|
||||
}
|
||||
|
||||
place++;
|
||||
if (*place == ':') {
|
||||
if (*scan != '\0') {
|
||||
xoptarg = scan;
|
||||
scan = NULL;
|
||||
} else if (xoptind < argc) {
|
||||
xoptarg = argv[xoptind];
|
||||
xoptind++;
|
||||
} else {
|
||||
fprintf(stderr, "%s: option requires argument -%c\n", argv[0], c);
|
||||
return ':';
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#else
|
||||
void using_history(void) { }
|
||||
void add_history(const char *string) { }
|
||||
void rl_bind_key(int key, void (*fun)(void)) { }
|
||||
void rl_insert(void) { }
|
||||
char *readline(const char *prompt)
|
||||
{
|
||||
static char line[500], *p;
|
||||
int n;
|
||||
fputs(prompt, stdout);
|
||||
p = fgets(line, sizeof line, stdin);
|
||||
if (p) {
|
||||
n = strlen(line);
|
||||
if (n > 0 && line[n-1] == '\n')
|
||||
line[--n] = 0;
|
||||
p = malloc(n+1);
|
||||
memcpy(p, line, n+1);
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PS1 "> "
|
||||
|
||||
static void jsB_gc(js_State *J)
|
||||
{
|
||||
int report = js_toboolean(J, 1);
|
||||
js_gc(J, report);
|
||||
js_pushundefined(J);
|
||||
}
|
||||
|
||||
static void jsB_load(js_State *J)
|
||||
{
|
||||
int i, n = js_gettop(J);
|
||||
for (i = 1; i < n; ++i) {
|
||||
js_loadfile(J, js_tostring(J, i));
|
||||
js_pushundefined(J);
|
||||
js_call(J, 0);
|
||||
js_pop(J, 1);
|
||||
}
|
||||
js_pushundefined(J);
|
||||
}
|
||||
|
||||
static void jsB_compile(js_State *J)
|
||||
{
|
||||
const char *source = js_tostring(J, 1);
|
||||
const char *filename = js_isdefined(J, 2) ? js_tostring(J, 2) : "[string]";
|
||||
js_loadstring(J, filename, source);
|
||||
}
|
||||
|
||||
static void jsB_print(js_State *J)
|
||||
{
|
||||
int i, top = js_gettop(J);
|
||||
for (i = 1; i < top; ++i) {
|
||||
const char *s = js_tostring(J, i);
|
||||
if (i > 1) putchar(' ');
|
||||
fputs(s, stdout);
|
||||
}
|
||||
putchar('\n');
|
||||
js_pushundefined(J);
|
||||
}
|
||||
|
||||
static void jsB_write(js_State *J)
|
||||
{
|
||||
int i, top = js_gettop(J);
|
||||
for (i = 1; i < top; ++i) {
|
||||
const char *s = js_tostring(J, i);
|
||||
if (i > 1) putchar(' ');
|
||||
fputs(s, stdout);
|
||||
}
|
||||
js_pushundefined(J);
|
||||
}
|
||||
|
||||
static void jsB_read(js_State *J)
|
||||
{
|
||||
const char *filename = js_tostring(J, 1);
|
||||
FILE *f;
|
||||
char *s;
|
||||
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));
|
||||
}
|
||||
|
||||
s = malloc(n + 1);
|
||||
if (!s) {
|
||||
fclose(f);
|
||||
js_error(J, "out of memory");
|
||||
}
|
||||
|
||||
t = fread(s, 1, n, f);
|
||||
if (t != n) {
|
||||
free(s);
|
||||
fclose(f);
|
||||
js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno));
|
||||
}
|
||||
s[n] = 0;
|
||||
|
||||
js_pushstring(J, s);
|
||||
free(s);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void jsB_readline(js_State *J)
|
||||
{
|
||||
char *line = readline("");
|
||||
if (!line) {
|
||||
js_pushnull(J);
|
||||
return;
|
||||
}
|
||||
js_pushstring(J, line);
|
||||
if (*line)
|
||||
add_history(line);
|
||||
free(line);
|
||||
}
|
||||
|
||||
static void jsB_quit(js_State *J)
|
||||
{
|
||||
exit(js_tonumber(J, 1));
|
||||
}
|
||||
|
||||
static void jsB_repr(js_State *J)
|
||||
{
|
||||
js_repr(J, 1);
|
||||
}
|
||||
|
||||
static const char *require_js =
|
||||
"function require(name) {\n"
|
||||
"var cache = require.cache;\n"
|
||||
"if (name in cache) return cache[name];\n"
|
||||
"var exports = {};\n"
|
||||
"cache[name] = exports;\n"
|
||||
"Function('exports', read(name+'.js'))(exports);\n"
|
||||
"return exports;\n"
|
||||
"}\n"
|
||||
"require.cache = Object.create(null);\n"
|
||||
;
|
||||
|
||||
|
||||
static const char *stacktrace_js =
|
||||
"Error.prototype.toString = function() {\n"
|
||||
"var s = this.name;\n"
|
||||
"if ('message' in this) s += ': ' + this.message;\n"
|
||||
"if ('stack' in this) s += this.stack;\n"
|
||||
"return s;\n"
|
||||
"};\n"
|
||||
;
|
||||
|
||||
static const char *console_js =
|
||||
"var console = { log: print, debug: print, warn: print, error: print };"
|
||||
;
|
||||
|
||||
static int eval_print(js_State *J, const char *source)
|
||||
{
|
||||
if (js_ploadstring(J, "[stdin]", source)) {
|
||||
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
|
||||
js_pop(J, 1);
|
||||
return 1;
|
||||
}
|
||||
js_pushundefined(J);
|
||||
if (js_pcall(J, 0)) {
|
||||
fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
|
||||
js_pop(J, 1);
|
||||
return 1;
|
||||
}
|
||||
if (js_isdefined(J, -1)) {
|
||||
printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
|
||||
}
|
||||
js_pop(J, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *read_stdin(void)
|
||||
{
|
||||
int n = 0;
|
||||
int t = 512;
|
||||
char *s = NULL;
|
||||
|
||||
for (;;) {
|
||||
char *ss = realloc(s, t);
|
||||
if (!ss) {
|
||||
free(s);
|
||||
fprintf(stderr, "cannot allocate storage for stdin contents\n");
|
||||
return NULL;
|
||||
}
|
||||
s = ss;
|
||||
n += fread(s + n, 1, t - n - 1, stdin);
|
||||
if (n < t - 1)
|
||||
break;
|
||||
t *= 2;
|
||||
}
|
||||
|
||||
if (ferror(stdin)) {
|
||||
free(s);
|
||||
fprintf(stderr, "error reading stdin\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s[n] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: mujs [options] [script [scriptArgs*]]\n");
|
||||
fprintf(stderr, "\t-i: Enter interactive prompt after running code.\n");
|
||||
fprintf(stderr, "\t-s: Check strictness.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *input;
|
||||
js_State *J;
|
||||
int status = 0;
|
||||
int strict = 0;
|
||||
int interactive = 0;
|
||||
int i, c;
|
||||
|
||||
while ((c = xgetopt(argc, argv, "is")) != -1) {
|
||||
switch (c) {
|
||||
default: usage(); break;
|
||||
case 'i': interactive = 1; break;
|
||||
case 's': strict = 1; break;
|
||||
}
|
||||
}
|
||||
|
||||
J = js_newstate(NULL, NULL, strict ? JS_STRICT : 0);
|
||||
if (!J) {
|
||||
fprintf(stderr, "Could not initialize MuJS.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
js_newcfunction(J, jsB_gc, "gc", 0);
|
||||
js_setglobal(J, "gc");
|
||||
|
||||
js_newcfunction(J, jsB_load, "load", 1);
|
||||
js_setglobal(J, "load");
|
||||
|
||||
js_newcfunction(J, jsB_compile, "compile", 2);
|
||||
js_setglobal(J, "compile");
|
||||
|
||||
js_newcfunction(J, jsB_print, "print", 0);
|
||||
js_setglobal(J, "print");
|
||||
|
||||
js_newcfunction(J, jsB_write, "write", 0);
|
||||
js_setglobal(J, "write");
|
||||
|
||||
js_newcfunction(J, jsB_read, "read", 1);
|
||||
js_setglobal(J, "read");
|
||||
|
||||
js_newcfunction(J, jsB_readline, "readline", 0);
|
||||
js_setglobal(J, "readline");
|
||||
|
||||
js_newcfunction(J, jsB_repr, "repr", 0);
|
||||
js_setglobal(J, "repr");
|
||||
|
||||
js_newcfunction(J, jsB_quit, "quit", 1);
|
||||
js_setglobal(J, "quit");
|
||||
|
||||
js_dostring(J, require_js);
|
||||
js_dostring(J, stacktrace_js);
|
||||
js_dostring(J, console_js);
|
||||
|
||||
if (xoptind == argc) {
|
||||
interactive = 1;
|
||||
} else {
|
||||
c = xoptind++;
|
||||
|
||||
js_newarray(J);
|
||||
i = 0;
|
||||
while (xoptind < argc) {
|
||||
js_pushstring(J, argv[xoptind++]);
|
||||
js_setindex(J, -2, i++);
|
||||
}
|
||||
js_setglobal(J, "scriptArgs");
|
||||
|
||||
if (js_dofile(J, argv[c]))
|
||||
status = 1;
|
||||
}
|
||||
|
||||
if (interactive) {
|
||||
printf("Welcome to MuJS %d.%d.%d.\n",
|
||||
JS_VERSION_MAJOR, JS_VERSION_MINOR, JS_VERSION_PATCH);
|
||||
if (isatty(0)) {
|
||||
using_history();
|
||||
rl_bind_key('\t', rl_insert);
|
||||
input = readline(PS1);
|
||||
while (input) {
|
||||
eval_print(J, input);
|
||||
if (*input)
|
||||
add_history(input);
|
||||
free(input);
|
||||
input = readline(PS1);
|
||||
}
|
||||
putchar('\n');
|
||||
} else {
|
||||
input = read_stdin();
|
||||
if (!input || !js_dostring(J, input))
|
||||
status = 1;
|
||||
free(input);
|
||||
}
|
||||
}
|
||||
|
||||
js_gc(J, 0);
|
||||
js_freestate(J);
|
||||
|
||||
return status;
|
||||
}
|
||||
252
mujs.h
252
mujs.h
@@ -1,252 +0,0 @@
|
||||
#ifndef mujs_h
|
||||
#define mujs_h
|
||||
|
||||
#include <setjmp.h> /* required for setjmp in fz_try macro */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define JS_VERSION_MAJOR 1
|
||||
#define JS_VERSION_MINOR 3
|
||||
#define JS_VERSION_PATCH 5
|
||||
|
||||
#define JS_VERSION (JS_VERSION_MAJOR * 10000 + JS_VERSION_MINOR * 100 + JS_VERSION_PATCH)
|
||||
#define JS_CHECKVERSION(x,y,z) (JS_VERSION >= ((x) * 10000 + (y) * 100 + (z)))
|
||||
|
||||
/* 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,
|
||||
};
|
||||
|
||||
/* enum for js_type() */
|
||||
enum {
|
||||
JS_ISUNDEFINED,
|
||||
JS_ISNULL,
|
||||
JS_ISBOOLEAN,
|
||||
JS_ISNUMBER,
|
||||
JS_ISSTRING,
|
||||
JS_ISFUNCTION,
|
||||
JS_ISOBJECT
|
||||
};
|
||||
|
||||
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_currentfunctiondata(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_newcfunctionx(js_State *J, js_CFunction fun, const char *name, int length, void *data, js_Finalize finalize);
|
||||
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_isbooleanobject(js_State *J, int idx);
|
||||
int js_isdateobject(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);
|
||||
int js_type(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
|
||||
25
one.c
25
one.c
@@ -1,25 +0,0 @@
|
||||
#include "jsarray.c"
|
||||
#include "jsboolean.c"
|
||||
#include "jsbuiltin.c"
|
||||
#include "jscompile.c"
|
||||
#include "jsdate.c"
|
||||
#include "jsdtoa.c"
|
||||
#include "jserror.c"
|
||||
#include "jsfunction.c"
|
||||
#include "jsgc.c"
|
||||
#include "jsintern.c"
|
||||
#include "jslex.c"
|
||||
#include "jsmath.c"
|
||||
#include "jsnumber.c"
|
||||
#include "jsobject.c"
|
||||
#include "json.c"
|
||||
#include "jsparse.c"
|
||||
#include "jsproperty.c"
|
||||
#include "jsregexp.c"
|
||||
#include "jsrepr.c"
|
||||
#include "jsrun.c"
|
||||
#include "jsstate.c"
|
||||
#include "jsstring.c"
|
||||
#include "jsvalue.c"
|
||||
#include "regexp.c"
|
||||
#include "utf.c"
|
||||
85
opnames.h
85
opnames.h
@@ -1,85 +0,0 @@
|
||||
"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",
|
||||
"skiparray",
|
||||
"initarray",
|
||||
"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",
|
||||
46
regexp.h
46
regexp.h
@@ -1,46 +0,0 @@
|
||||
#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 16
|
||||
#endif
|
||||
|
||||
struct Resub {
|
||||
int nsub;
|
||||
struct {
|
||||
const char *sp;
|
||||
const char *ep;
|
||||
} sub[REG_MAXSUB];
|
||||
};
|
||||
|
||||
#endif
|
||||
139
tools/test262
139
tools/test262
@@ -1,139 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
usage() {
|
||||
[ "${1-}" ] && { to=2; >&$to printf "Error: %s\n" "$1"; } || to=1
|
||||
>&$to echo "Usage: ${0##*/} [OPTIONS] test-file | test-dir"
|
||||
>&$to echo "Run test-262 ES5 test file or directory (at the test262 dir)."
|
||||
>&$to echo " -s Print source code of failed tests."
|
||||
>&$to echo " -p Print every test name before running it"
|
||||
>&$to echo " -f Display full paths and full stack trace when possible"
|
||||
>&$to echo " -l file.js Load file.js after the harness and before the test (up to one)"
|
||||
>&$to echo " -m MUJS MUJS is [path/to/]mujs binary to test"
|
||||
>&$to echo " Default is $(dirname "$0")/../build/release/mujs or mujs at \$PATH"
|
||||
>&$to echo " -b Don't skip known bad (crashing/hanging) tests"
|
||||
>&$to echo " -B Run only known bad tests"
|
||||
exit $((to-1))
|
||||
}
|
||||
|
||||
KNOWN_BAD="
|
||||
--hang-with-sta.js:
|
||||
S15.1.3.2_A2.5_T1.js
|
||||
S15.1.3.1_A2.5_T1.js
|
||||
|
||||
--Hang-(or-taking-more-than-few-seconds):
|
||||
15.4.4.18-3-14.js
|
||||
15.4.4.20-3-14.js
|
||||
S15.4.4.10_A3_T2.js
|
||||
S15.4.4.10_A3_T1.js
|
||||
15.4.4.19-3-29.js
|
||||
15.4.4.19-3-28.js
|
||||
15.4.4.19-3-8.js
|
||||
15.4.4.19-3-14.js
|
||||
S15.4.4.8_A3_T3.js
|
||||
15.4.4.22-3-9.js
|
||||
15.4.4.22-3-7.js
|
||||
15.4.4.22-3-25.js
|
||||
15.4.4.22-3-14.js
|
||||
15.4.4.21-3-14.js
|
||||
15.4.4.15-3-28.js
|
||||
15.4.4.15-3-14.js
|
||||
15.4.4.15-3-7.js
|
||||
15.4.4.15-3-25.js
|
||||
15.4.4.15-3-9.js
|
||||
"
|
||||
|
||||
SKIP_KNOWN=yes # "yes": skip bad "no": don't skip "neg": run only bad
|
||||
PRINT_ALL=
|
||||
EXTRA_ARGS=
|
||||
mujs= lopt=
|
||||
|
||||
while getopts bBfhl:ps o; do
|
||||
case $o in
|
||||
h) usage ;;
|
||||
b) SKIP_KNOWN=no ;;
|
||||
B) SKIP_KNOWN=neg ;;
|
||||
p) PRINT_ALL=yes ;;
|
||||
s) EXTRA_ARGS="$EXTRA_ARGS -s" ;;
|
||||
f) EXTRA_ARGS="$EXTRA_ARGS -f" ;;
|
||||
l) [ "$OPTARG" ] && lopt=$OPTARG || usage "empty file for -l" ;;
|
||||
m) mujs=$OPTARG;;
|
||||
*) usage "unknown option -$o" ;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
[ $# = 1 ] || usage "expecting one file/dir"
|
||||
|
||||
BAD=
|
||||
if [ "$SKIP_KNOWN" != no ]; then
|
||||
for b in $KNOWN_BAD; do
|
||||
BAD="$BAD $b "
|
||||
done
|
||||
fi
|
||||
|
||||
find_root() {
|
||||
ROOT=$1
|
||||
n=0
|
||||
while ! [ -e "$ROOT"/test/harness/sta.js ]; do
|
||||
ROOT=$ROOT/..
|
||||
n=$((n+1))
|
||||
[ $n -lt 10 ] || usage "can't find test-suite root"
|
||||
done
|
||||
}
|
||||
|
||||
if [ -d "$1" ]; then
|
||||
find_root "$1"
|
||||
|
||||
if [ "$ROOT" = "$1" ]; then
|
||||
FILES_CMD='find "$1/test/suite" -name "*.js" | sort -V'
|
||||
else
|
||||
FILES_CMD='find "$1" -name "*.js" | sort -V'
|
||||
fi
|
||||
else
|
||||
find_root "$(dirname "$1")"
|
||||
FILES_CMD='printf "%s\n" "$1"'
|
||||
fi
|
||||
|
||||
if ! [ "$mujs" ]; then
|
||||
# try to use a recently built mujs rather than a global one
|
||||
mujs=$(dirname "$0")/../build/release/mujs
|
||||
[ -e "$mujs" ] || mujs=mujs
|
||||
fi
|
||||
jsharness=$(dirname "$0")/test262-harness.js
|
||||
|
||||
total=0
|
||||
skipped=0
|
||||
failed=0
|
||||
|
||||
eval "$FILES_CMD" | (
|
||||
while IFS= read -r f && [ "$f" ]; do
|
||||
total=$((total+1))
|
||||
base=${f##*/}
|
||||
|
||||
case $BAD in *" $base "*) bad=yes;; *) bad=no;; esac
|
||||
|
||||
case $bad-$SKIP_KNOWN in
|
||||
yes-yes)
|
||||
skipped=$((skipped+1))
|
||||
printf "[Skipping: $base]\n\n"
|
||||
;;
|
||||
no-neg) # not known bad and running only bad - don't print anything
|
||||
skipped=$((skipped+1))
|
||||
;;
|
||||
*)
|
||||
[ "$PRINT_ALL" ] && echo "Testing: $f"
|
||||
if ! "$mujs" -- "$jsharness" $EXTRA_ARGS ${lopt:+-l "$lopt"} "$ROOT" "$f" 2>&1; then
|
||||
failed=$((failed+1))
|
||||
echo
|
||||
fi
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $total -gt 1 ]; then
|
||||
printf "Total: $total\n"
|
||||
printf "Pass: %${#total}s\n" $((total - skipped - failed))
|
||||
printf "Skip: %${#total}s\n" $skipped
|
||||
printf "Fail: %${#total}s\n" $failed
|
||||
fi
|
||||
|
||||
[ "$failed" = 0 ]
|
||||
)
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Runs one test file from the ES5 test suite test-262
|
||||
* Usage: mujs <this-file> [-s ] [-f] [-l file1.js -l ...] suit-root test-file
|
||||
* -s: print test source on failure
|
||||
* -f: print full paths/stacktraces if possible
|
||||
* -l: load a js file after the harness and before the test (to override things)
|
||||
*
|
||||
* If there are errors, print them and exits with code 1, else exit code is 0.
|
||||
*
|
||||
* The test suite is at: https://github.com/tc39/test262.git
|
||||
* The ES5 suite is at branch "es5-tests"
|
||||
*
|
||||
* - The test suite throws on any error, possibly with info at ex.message .
|
||||
* - Some tests make irreversible changes to global attrubutes, therefore it's
|
||||
* required to run each test file in a new mujs instance.
|
||||
*/
|
||||
|
||||
(function(global) {
|
||||
"use strict";
|
||||
|
||||
// clean the global environment
|
||||
var mujs = {};
|
||||
|
||||
["gc", "load", "compile", "print", "write", "read", "readline", "quit", "scriptArgs"]
|
||||
.forEach(function(a) {
|
||||
mujs[a] = global[a];
|
||||
delete global[a];
|
||||
});
|
||||
|
||||
// restore the original Error.toString behavior - it's being tested too
|
||||
Error.prototype.toString = function() {
|
||||
return this.name + ': ' + this.message;
|
||||
}
|
||||
|
||||
function die_usage(str) {
|
||||
if (str)
|
||||
mujs.print(str);
|
||||
mujs.print("Usage: mujs <this-file> [-f] [-l file1.js -l ...] suit-root test-file");
|
||||
mujs.quit(1);
|
||||
}
|
||||
|
||||
// our file loader
|
||||
function load(str, as_filename) {
|
||||
try {
|
||||
var runtime_err = false;
|
||||
var compiled = mujs.compile(str, as_filename);
|
||||
runtime_err = true;
|
||||
compiled();
|
||||
return false;
|
||||
} catch (e) {
|
||||
return {err: e, runtime: runtime_err};
|
||||
}
|
||||
}
|
||||
|
||||
var args = mujs.scriptArgs;
|
||||
var full_mode = false;
|
||||
var print_src = false;
|
||||
var overrides = [];
|
||||
while ((""+args[0])[0] == "-") {
|
||||
switch (args[0]) {
|
||||
case "-f": full_mode = true;
|
||||
break;
|
||||
case "-s": print_src = true;
|
||||
break;
|
||||
case "-l": args.shift();
|
||||
overrides.push(args[0]);
|
||||
break;
|
||||
default: die_usage("Unknown option " + args[0]);
|
||||
}
|
||||
args.shift();
|
||||
}
|
||||
if (args.length != 2)
|
||||
die_usage("Exactly 2 paths are expected");
|
||||
var root_path = args[0];
|
||||
var test_path = args[1];
|
||||
|
||||
// load suite utils
|
||||
["sta.js", "testBuiltInObject.js", "testIntl.js"]
|
||||
.forEach(function(u) {
|
||||
var path = root_path + "/test/harness/" + u;
|
||||
var as_file = full_mode ? path : "test/harness/" + u;
|
||||
var err = load(mujs.read(path), as_file);
|
||||
if (err) throw (err.err);
|
||||
});
|
||||
|
||||
// load user overrides (e.g. reduced getPrecision), with a global mujs
|
||||
if (overrides.length) {
|
||||
global.mujs = mujs
|
||||
overrides.forEach(function(f) {
|
||||
var err = load(mujs.read(f), f);
|
||||
if (err) throw (err.err);
|
||||
});
|
||||
delete global.mujs;
|
||||
}
|
||||
|
||||
// the actual test
|
||||
var source = mujs.read(test_path);
|
||||
var negative = !!source.match(/@negative/);
|
||||
if (negative)
|
||||
var neg_str = (source.match(/@negative (.*)/) || [])[1];
|
||||
var as_file = test_path;
|
||||
if (!full_mode) {
|
||||
as_file = test_path.replace(/\\/g, "/");
|
||||
var sub = as_file.indexOf("/suite/");
|
||||
if (sub >= 0)
|
||||
as_file = "test" + as_file.substring(sub);
|
||||
}
|
||||
|
||||
var result = load(mujs.read(test_path), as_file);
|
||||
if (!!result == negative) {
|
||||
// The docs don't really help about matching str, but this covers all cases
|
||||
if (neg_str)
|
||||
var err_for_match = /NotEarlyError/.test(neg_str) ? result.err.message : result.err.name;
|
||||
if (!negative || !neg_str || RegExp(neg_str).exec(err_for_match))
|
||||
mujs.quit(0);
|
||||
}
|
||||
|
||||
// failed
|
||||
// FIXME: @description can span lines. E.g. test/suite/bestPractice/Sbp_A3_T2.js
|
||||
var desc = source.match(/@description (.*)/);
|
||||
var info = "[File] " + as_file +
|
||||
(desc ? "\n[Desc] " + desc[1] : "") +
|
||||
"\n";
|
||||
|
||||
if (result) {
|
||||
var err = result.err;
|
||||
var msg = !neg_str ? err : "[Mismatch @negative " + neg_str + "]" + "\n " + err;
|
||||
|
||||
info += (result.runtime ? "[run] " : "[load] ") + msg;
|
||||
if (err && err.stack && (result.runtime || full_mode)) {
|
||||
if (full_mode) {
|
||||
info += err.stack;
|
||||
} else {
|
||||
// trim the internal loader from the trace
|
||||
var internal = err.stack.indexOf("\n" + load("mujs_blahblah()").err.stack.trim().split("\n")[1]);
|
||||
if (internal >= 0)
|
||||
info += err.stack.substring(0, internal);
|
||||
else
|
||||
info += err.stack;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info += "[run] [Error expected but none thrown]";
|
||||
}
|
||||
|
||||
if (print_src)
|
||||
info += "\n[Source]\n" + source;
|
||||
|
||||
mujs.print(info);
|
||||
mujs.quit(1);
|
||||
|
||||
})(this)
|
||||
305
utf.c
305
utf.c
@@ -1,305 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "utfdata.h"
|
||||
|
||||
#define nelem(a) (int)(sizeof (a) / sizeof (a)[0])
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static const Rune *
|
||||
ucd_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 = ucd_bsearch(c, ucd_tolower2, nelem(ucd_tolower2)/3, 3);
|
||||
if(p && c >= p[0] && c <= p[1])
|
||||
return c + p[2];
|
||||
p = ucd_bsearch(c, ucd_tolower1, nelem(ucd_tolower1)/2, 2);
|
||||
if(p && c == p[0])
|
||||
return c + p[1];
|
||||
return c;
|
||||
}
|
||||
|
||||
Rune
|
||||
toupperrune(Rune c)
|
||||
{
|
||||
const Rune *p;
|
||||
|
||||
p = ucd_bsearch(c, ucd_toupper2, nelem(ucd_toupper2)/3, 3);
|
||||
if(p && c >= p[0] && c <= p[1])
|
||||
return c + p[2];
|
||||
p = ucd_bsearch(c, ucd_toupper1, nelem(ucd_toupper1)/2, 2);
|
||||
if(p && c == p[0])
|
||||
return c + p[1];
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
islowerrune(Rune c)
|
||||
{
|
||||
const Rune *p;
|
||||
|
||||
p = ucd_bsearch(c, ucd_toupper2, nelem(ucd_toupper2)/3, 3);
|
||||
if(p && c >= p[0] && c <= p[1])
|
||||
return 1;
|
||||
p = ucd_bsearch(c, ucd_toupper1, nelem(ucd_toupper1)/2, 2);
|
||||
if(p && c == p[0])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
isupperrune(Rune c)
|
||||
{
|
||||
const Rune *p;
|
||||
|
||||
p = ucd_bsearch(c, ucd_tolower2, nelem(ucd_tolower2)/3, 3);
|
||||
if(p && c >= p[0] && c <= p[1])
|
||||
return 1;
|
||||
p = ucd_bsearch(c, ucd_tolower1, nelem(ucd_tolower1)/2, 2);
|
||||
if(p && c == p[0])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
isalpharune(Rune c)
|
||||
{
|
||||
const Rune *p;
|
||||
|
||||
p = ucd_bsearch(c, ucd_alpha2, nelem(ucd_alpha2)/2, 2);
|
||||
if(p && c >= p[0] && c <= p[1])
|
||||
return 1;
|
||||
p = ucd_bsearch(c, ucd_alpha1, nelem(ucd_alpha1), 1);
|
||||
if(p && c == p[0])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Rune *
|
||||
tolowerrune_full(Rune c)
|
||||
{
|
||||
const Rune *p;
|
||||
p = ucd_bsearch(c, ucd_tolower_full, nelem(ucd_tolower_full)/4, 4);
|
||||
if(p && c == p[0])
|
||||
return p + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const Rune *
|
||||
toupperrune_full(Rune c)
|
||||
{
|
||||
const Rune *p;
|
||||
p = ucd_bsearch(c, ucd_toupper_full, nelem(ucd_toupper_full)/5, 5);
|
||||
if(p && c == p[0])
|
||||
return p + 1;
|
||||
return NULL;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user