Migrate to Codeberg.

This commit is contained in:
Tor Andersson
2025-08-13 15:56:44 +02:00
parent 05cd646bad
commit 2385035568
52 changed files with 1 additions and 21546 deletions

View File

@@ -1 +0,0 @@
Tor Andersson <tor.andersson@artifex.com>

16
COPYING
View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -0,0 +1 @@
This repository has migrated to https://codeberg.org/ccxvii/mujs

View File

@@ -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

View File

@@ -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 &lt;stdio.h&gt;
#include &lt;mujs.h&gt;
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 &lt;stdio.h&gt;
#include &lt;mujs.h&gt;
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 &lt;stdio.h&gt;
#include &lt;mujs.h&gt;
#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 &copy; 2013-2017 Artifex Software Inc.
</footer>
</body>
</html>

View File

@@ -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 &copy; 2013-2017 Artifex Software Inc.
</footer>
</body>
</html>

View File

@@ -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 &mdash; 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 &copy; 2013-2017 Artifex Software Inc.
</footer>
</body>
</html>

View File

@@ -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 &copy; 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 &copy; 2013-2017 Artifex Software Inc.
</footer>
</body>
</html>

View File

@@ -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

View File

@@ -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
View File

@@ -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)

832
jsarray.c

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

View File

@@ -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);
}

File diff suppressed because it is too large Load Diff

861
jsdate.c

File diff suppressed because it is too large Load Diff

749
jsdtoa.c

File diff suppressed because it is too large Load Diff

128
jserror.c
View File

@@ -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
}

View File

@@ -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
View File

@@ -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);
}

867
jsi.h

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

878
jslex.c

File diff suppressed because it is too large Load Diff

194
jsmath.c
View File

@@ -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);
}

View File

@@ -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);
}

File diff suppressed because it is too large Load Diff

422
json.c
View File

@@ -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);
}

1065
jsparse.c

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -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
View File

@@ -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;
}

2063
jsrun.c

File diff suppressed because it is too large Load Diff

334
jsstate.c
View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

708
jsvalue.c

File diff suppressed because it is too large Load Diff

394
main.c
View File

@@ -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
View File

@@ -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
View File

@@ -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"

View File

@@ -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",

980
pp.c

File diff suppressed because it is too large Load Diff

1277
regexp.c

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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 ]
)

View File

@@ -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
View File

@@ -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