ref: 08276111f575ac6142e922d62aa264dc1f30b69e
parent: 269960707037bcc7999c918cfe2e28c94351cd82
author: Tor Andersson <tor.andersson@artifex.com>
date: Tue Sep 29 06:18:15 EDT 2015
Add documentation.
--- /dev/null
+++ b/docs/about.html
@@ -1,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="style.css" rel="stylesheet">
+<title>MuJS: about</title>
+</head>
+<body>
+
+<h2>What is MuJS?</h2>
+
+<p>
+MuJS is a lightweight implementation of the Javascript language in a library.
+Its primary purpose is to add scripting capability to other programs, but can also be used as an extensible scripting language.
+
+<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=ghostscript">#ghostscript</a>
+IRC channel on freenode.
+
+<h2>Why choose MuJS?</h2>
+
+<h3>Javascript</h3>
+
+<p>
+Javascript is one of the most popular programming languages in the world.
+It is a powerful extension language, used everywhere on the web — both as a way to add interactivity to web pages in the browser, and on the server side with platforms like node.js.
+
+<p>
+With MuJS you can bring this power to your application as well!
+
+<h3>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>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>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>Small</h3>
+
+<p>
+Adding MuJS to an application does not bloat it.
+The source contains around 10'000 lines of C.
+Under 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>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.
+
+<h3>Free software (commercial licensing available)</h3>
+
+<p>
+MuJS is free open source software distributed under the Affero GPL.
+Commercial licenses for use with proprietary software are also available.
+Contact sales@artifex.com for more details about licensing.
+
+</body>
--- /dev/null
+++ b/docs/examples.html
@@ -1,0 +1,148 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="style.css" rel="stylesheet">
+<title>MuJS: examples</title>
+</head>
+<body>
+
+<h1>MuJS Examples</h1>
+
+<h2>A stand-alone interpreter</h2>
+
+<pre>
+#include <stdio.h>
+#include <mujs.h>
+
+int main(int argc, char **argv)
+{
+ char line[256];
+ js_State *J = js_newstate(NULL, NULL, JS_STRICT);
+ while (fgets(line, sizeof line, stdin))
+ js_dostring(J, line, 1);
+ js_freestate(J);
+}
+</pre>
+
+<h2>Hello, world!</h2>
+
+<pre>
+#include <stdio.h>
+#include <mujs.h>
+
+static void hello(js_State *J)
+{
+ const char *name = js_tostring(J, 1);
+ printf("Hello, %s!\n", name);
+ js_pushundefined(J);
+}
+
+int main(int argc, char **argv)
+{
+ js_State *J = js_newstate(NULL, NULL, JS_STRICT);
+
+ js_newcfunction(J, hello, 1);
+ js_setglobal(J, "hello");
+
+ js_dostring(J, "hello('world');", 0);
+
+ js_freestate(J);
+}
+</pre>
+
+<h2>Configuration file</h2>
+
+<pre>
+js_dofile(J, "config.lua")
+
+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>Complete userdata example</h2>
+
+<pre>
+#include <stdio.h>
+#include <mujs.h>
+
+#define TAG "File"
+
+static void new_File(js_State *J)
+{
+ FILE *file;
+
+ if (js_isundefined(J, 1)) {
+ file = stdin;
+ } else {
+ const char *filename = js_tostring(J, 1);
+ file = fopen(filename, "r");
+ if (!file)
+ js_error(J, "cannot open file: '%s'", filename);
+ }
+
+ js_currentfunction(J);
+ js_getproperty(J, -1, "prototype");
+ js_newuserdata(J, TAG, file);
+}
+
+static void File_prototype_readByte(js_State *J)
+{
+ FILE *file = js_touserdata(J, 0, TAG);
+ js_pushnumber(J, getc(file));
+}
+
+static void File_prototype_readLine(js_State *J)
+{
+ char line[256], *s;
+ FILE *file = js_touserdata(J, 0, TAG);
+ s = fgets(line, sizeof line, file);
+ if (s)
+ js_pushstring(J, line);
+ else
+ js_pushnull(J);
+}
+
+static void File_prototype_close(js_State *J)
+{
+ FILE *file = js_touserdata(J, 0, TAG);
+ fclose(file);
+ js_pushundefined(J);
+}
+
+void initfile(js_State *J)
+{
+ js_getglobal(J, "Object");
+ js_getproperty(J, -1, "prototype"); // File.prototype.[[Prototype]] = Object.prototype
+ js_newuserdata(J, TAG, stdin); // File.prototype.[[Userdata]] = stdin
+ {
+ js_newcfunction(J, File_prototype_readByte, 0);
+ js_defproperty(J, -2, "readByte", JS_DONTENUM);
+
+ js_newcfunction(J, File_prototype_readLine, 0);
+ js_defproperty(J, -2, "readLine", JS_DONTENUM);
+
+ js_newcfunction(J, File_prototype_close, 0);
+ js_defproperty(J, -2, "close", JS_DONTENUM);
+ }
+ js_newcconstructor(J, new_File, new_File, 1);
+ js_defglobal(J, "File", JS_DONTENUM);
+}
+</pre>
+
+</body>
--- /dev/null
+++ b/docs/reference.html
@@ -1,0 +1,598 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="style.css" rel="stylesheet">
+<title>MuJS: reference manual</title>
+</head>
+<body>
+
+<h1>MuJS Reference Manual</h1>
+
+<h2>Introduction</h2>
+
+<p>
+MuJS is a library, written in clean and simple C.
+Being an extension library, MuJS has no notion of a main program: it only works embedded in a host client program.
+The host program can invoke functions to execute Javascript code, read and write Javascript variables, and register C functions to be called by Javascript.
+
+<p>
+The MuJS distribution includes a sample host program called "mujs", which uses the MuJS library to offer a standalone Javascript interpreter for interactive or batch use.
+
+<p>
+This reference manual assumes that you are already familiar with the Javascript language, in particular the type system and object prototype mechanisms.
+
+<h2>Basic Concepts</h2>
+
+<h3>Values and Types</h3>
+
+<p>
+There are six basic types in Javascript: undefined, null, boolean, number, string and object.
+
+<p>
+Each object also has a class: object, array, function, userdata, regular expression, etc.
+
+<p>
+Javascript can call functions written in C provided by the host program, as well as other Javascript functions.
+
+<p>
+Objects with the userdata class are provided to allow arbitrary C data to be attached to Javascript objects.
+A userdata object has a pointer to a block of raw memory, which is managed by the host.
+Userdata values cannot be created or modified in Javascript, only through the C API.
+This guarantees the integrity of data owned by the host program.
+
+<p>
+Custom properties on userdata objects can be implemented using getter and setter property accessor functions.
+
+<p>
+Numbers are represented using double precision floating point values.
+
+<p>
+Strings in the C interface are zero-terminated byte arrays in UTF-8 encoding.
+
+<h3>Environments</h3>
+
+<p>
+Each function executes within an environment which defines which variables are accessible.
+This is a chain of all environment records in scope, with the global environment at the top.
+Each environment record in MuJS is represented as an object with the null prototype, including the global environment object.
+
+<p>
+The registry is a hidden environment record which is only accessible to C.
+This is where Javascript values and objects that should only be accessible to C functions may be stored.
+
+<h3>Error Handling</h3>
+
+<p>
+All Javascript actions start from C code in the host program calling a function from the MuJS library.
+Whenever an exception is thrown during the compilation or execution of Javascript, control returns to the host, which can take appropriate measures (such as printing an error message).
+C code can also throw exceptions by calling functions to create an error object and return control to Javascript.
+
+<p>
+Internally, MuJS uses the C longjmp facility to handle errors.
+A protected environment uses setjmp to set a recovery point.
+The try statement in Javascript creates such a recovery point, as does calling js_dostring, js_dofile, js_ploadstring, js_ploadfile,
+js_pcall and js_pconstruct.
+
+<p>
+When an error occurs or an exception is thrown from Javascript, it does a long jump to the most recent active recovery point.
+
+<p>
+If an error occurs outside any protected environment, MuJS first calls the panic function and then calls abort, thus exiting the host application.
+Your panic function can avoid this exit by never returning (for example by doing a long jump to your own recovery point outside MuJS).
+
+<h3>Garbage Collection</h3>
+
+<p>
+MuJS performs automatic memory management using a basic mark-and-sweep collector.
+Collection is automatically triggered when enough allocations have accumulated.
+You can also force a collection pass from C.
+
+<p>
+TODO: garbage collection of userdata.
+
+<h3>The Stack</h3>
+
+<p>
+MuJS uses a virtual stack to pass values to and from C.
+Each element in this stack represents a Javascript value (null, number, string, etc).
+
+<p>
+Whenever Javascript calls C, the called function gets a new stack.
+This stack initially contains the this value and any arguments passed to the function.
+When the C function returns, the top value on the stack is passed back to the caller as the return value.
+
+<p>
+The stack values are accessed using stack indices.
+Index 0 always contains this value, and function arguments are index 1 and up.
+Negative indices count down from the top of the stack, so index -1 is the top of the index and index -2 is the one below that.
+
+<h2>The Application Program Interface</h2>
+
+<h3>State</h3>
+
+<pre>
+typedef struct js_State js_State;
+</pre>
+
+<p>
+The interpreter state is bundled up in the opaque struct js_State.
+This state contains the value stacks, protected environments, and environment records.
+
+<pre>
+js_State *js_newstate(js_Alloc alloc, void *context, int flags);
+</pre>
+
+<p>
+Create a new state using the allocator function and allocator context.
+Pass NULL to use the default allocator.
+
+<p>
+The available flags:
+
+<ul>
+<li>JS_STRICT: compile and run code using ES5 strict mode.
+</ul>
+
+<pre>
+void js_freestate(js_State *J);
+</pre>
+
+<p>
+Destroy the state and free all dynamic memory used by the state.
+
+<h3>Allocator</h3>
+
+<p>
+The interpreter uses a host provided function for all memory allocation needs:
+
+<pre>
+typedef void *(*js_Alloc)(void *memctx, void *ptr, unsigned int size);
+</pre>
+
+<p>
+When size is zero, the allocator should behave like free and return NULL.
+When size is not zero, the allocator should behave like realloc.
+The allocator should return NULL if it cannot fulfill the request.
+The default allocator uses malloc, realloc and free.
+
+<h3>Panic</h3>
+
+<pre>
+typedef void (*js_Panic)(js_State *J);
+
+js_Panic js_atpanic(js_State *J, js_Panic panic);
+</pre>
+
+Set a new panic function, and return the old one.
+
+<h3>Garbage collection</h3>
+
+<pre>
+js_gc(js_State *J, int report);
+</pre>
+
+<p>
+Force a garbage collection pass.
+If the report argument is non-zero, print a summary of garbage collection statistics to stdout.
+
+<h3>Loading and compiling scripts</h3>
+
+<p>
+A script is compiled by calling js_loadstring or js_loadfile.
+The result of a successful compilation is a function on the top of the stack.
+This function can then be executed with js_call.
+
+<pre>
+void js_loadstring(js_State *J, const char *filename, const char *source);
+void js_loadfile(js_State *J, const char *filename);
+</pre>
+
+<p>
+Compile the script and push the resulting function.
+
+<pre>
+int js_ploadstring(js_State *J, const char *filename, const char *source);
+int js_ploadfile(js_State *J, const char *filename);
+</pre>
+
+Like js_loadstring/js_loadfile but in a protected environment.
+In case of success, return 0 with the result as a function on the stack.
+In case of failure, return 1 with the error object on the stack.
+
+<h3>Calling functions</h3>
+
+<pre>
+void js_call(js_State *J, int n);
+</pre>
+
+<p>
+To call a function, you must use the following protocol:
+1) push the function to call onto the stack,
+2) push the this value to be used by the function,
+3) push the arguments to the function in order,
+4) finally, call js_call with the number of arguments pushed in step 3.
+
+<p>
+Pop the function, the this value, and all arguments;
+execute the function;
+then push the return value from the function.
+
+<pre>
+void js_construct(js_State *J, int n);
+</pre>
+
+<p>
+The construct function implements the 'new' expression in Javascript.
+This is similar to js_call, but without pushing a this value:
+1) push the constructor function to call onto the stack,
+2) push the arguments to the constructor function in order,
+3) finally, call js_construct with the number of arguments pushed in step 2.
+
+<pre>
+int js_pcall(js_State *J, int n);
+int js_pconstruct(js_State *J, int n);
+</pre>
+
+<p>
+Like js_call and js_construct but in a protected environment.
+In case of success, return 0 with the result on the stack.
+In case of failure, return 1 with the error object on the stack.
+
+<h3>Script helpers</h3>
+
+<p>
+There are two convenience functions for loading and executing code.
+
+<pre>
+int js_dostring(js_State *J, const char *source, int report);
+</pre>
+
+<p>
+Compile and execute the script in the zero-terminated string in source argument.
+If any errors occur, print the error message to stderr and return 1.
+If the report argument is non-zero, print the result of executing the script to stdout.
+Return 0 on success.
+
+<pre>
+int js_dofile(js_State *J, const char *filename);
+</pre>
+
+<p>
+Load the script from the file with the given filename, then compile and execute it.
+If any errors occur, print the error message to stderr and return 1.
+Return 0 on success.
+
+<h3>Errors</h3>
+
+<pre>
+void js_throw(js_State *J);
+</pre>
+
+<p>
+Pop the error object on the top of the stack and return control flow to the most recent protected environment.
+
+<pre>
+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);
+</pre>
+
+<p>
+Push a new error object on the stack.
+
+<pre>
+void js_error(js_State *J, const char *fmt, ...);
+void js_evalerror(js_State *J, const char *fmt, ...);
+void js_rangeerror(js_State *J, const char *fmt, ...);
+void js_referenceerror(js_State *J, const char *fmt, ...);
+void js_syntaxerror(js_State *J, const char *fmt, ...);
+void js_typeerror(js_State *J, const char *fmt, ...);
+void js_urierror(js_State *J, const char *fmt, ...);
+</pre>
+
+<p>
+Wrapper to push a new error object on the stack using a printf formatting string and call js_throw.
+
+<h3>Stack manipulation</h3>
+
+<pre>
+int js_gettop(js_State *J);
+void js_settop(js_State *J, int idx); -- not implemented yet
+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); -- not implemented yet
+void js_replace(js_State* J, int idx); -- not implemented yet
+</pre>
+
+<h3>Comparisons and arithmetic</h3>
+
+<pre>
+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);
+</pre>
+
+<p>
+The equivalent of the '+', comparison, and instanceof operators.
+The okay argument to js_compare is set to 0 if any of the values are NaN, otherwise it is set to 1.
+
+</pre>
+
+<h3>Primitive values</h3>
+
+<pre>
+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_pushliteral(js_State *J, const char *v);
+</pre>
+
+<p>
+Push primitive values.
+js_pushstring makes a copy of the string, so it may be freed or changed after passing it in.
+js_pushliteral keeps a pointer to the string, so it must not be changed or freed after passing it in.
+
+<pre>
+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);
+</pre>
+
+<p>
+Test if a primitive value is of a given type.
+
+<pre>
+int js_toboolean(js_State *J, int idx);
+double js_tonumber(js_State *J, int idx);
+double 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);
+const char *js_tostring(js_State *J, int idx);
+</pre>
+
+<p>
+Convert the value at the given index into a C value.
+If the value is an object, invoke the toString and/or valueOf methods to do the conversion.
+
+<p>
+The conversion may <i>change the actual value in the stack</i>!
+
+<p>
+There is no guarantee that the pointer returned by js_tostring will be valid after
+the corresponding value is removed from the stack.
+
+<h3>Objects</h3>
+
+<pre>
+enum {
+ JS_REGEXP_G = 1,
+ JS_REGEXP_I = 2,
+ JS_REGEXP_M = 4,
+};
+
+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_newregexp(js_State *J, const char *pattern, int flags);
+</pre>
+
+<p>
+Creat and push objects on the stack.
+
+<pre>
+int js_isobject(js_State *J, int idx);
+int js_isarray(js_State *J, int idx);
+int js_iscallable(js_State *J, int idx);
+int js_isregexp(js_State *J, int idx);
+</pre>
+
+<p>
+Test the type and class of an object on the stack.
+
+<h3>Properties</h3>
+
+<p>
+The property functions all work on an object.
+If the stack slot referenced by the index does not contain an object, they will throw an error.
+
+<pre>
+enum {
+ JS_READONLY = 1,
+ JS_DONTENUM = 2,
+ JS_DONTCONF = 4,
+};
+</pre>
+
+<p>
+Property attribute bit-mask values.
+
+<pre>
+int js_hasproperty(js_State *J, int idx, const char *name);
+</pre>
+
+<p>
+If the object has a property with the given name, return 1 and push the value of the property; otherwise return 0 and leave the stack untouched.
+
+<pre>
+void js_getproperty(js_State *J, int idx, const char *name);
+</pre>
+
+<p>
+Push the value of the named property of the object.
+If the object does not have the named property, push undefined instead.
+
+<pre>
+void js_setproperty(js_State *J, int idx, const char *name);
+</pre>
+
+<p>
+Pop a value from the top of the stack and set the value of the named property of the object.
+
+<pre>
+void js_defproperty(js_State *J, int idx, const char *name, int atts);
+</pre>
+
+<p>
+Pop a value from the top of the stack and set the value of the named property of the object.
+Also define the property attributes.
+
+<pre>
+void js_defaccessor(js_State *J, int idx, const char *name, int atts);
+</pre>
+
+<p>
+Define the getter and setter attributes of a property on the object.
+Pop the two getter and setter functions from the stack.
+Use null instead of a function object if you want to leave any of the functions unset.
+
+<pre>
+void js_delproperty(js_State *J, int idx, const char *name);
+</pre>
+
+<p>
+Delete the named property from the object.
+
+<h3>Array properties</h3>
+
+<pre>
+unsigned int js_getlength(js_State *J, int idx);
+void js_setlength(js_State *J, int idx, unsigned int len);
+</pre>
+
+<p>
+Wrappers to get and set the "length" property of an object.
+
+<pre>
+int js_hasindex(js_State *J, int idx, unsigned int i);
+void js_getindex(js_State *J, int idx, unsigned int i);
+void js_setindex(js_State *J, int idx, unsigned int i);
+void js_delindex(js_State *J, int idx, unsigned int i);
+</pre>
+
+<p>
+These array index functions functions are simple wrappers around the equivalent property functions.
+They convert the numeric index to a string to use as the property name.
+
+<h3>Globals</h3>
+
+<pre>
+void js_pushglobal(js_State *J);
+</pre>
+
+<p>
+Push the object representing the global environment record.
+
+<pre>
+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);
+</pre>
+
+<p>
+Wrappers around js_pushglobal and js_get/set/defproperty to read and write the values of global variables.
+
+<h3>C Functions</h3>
+
+<pre>
+void js_newcfunction(js_State *J, js_CFunction fun, unsigned int length);
+</pre>
+
+<p>
+Push a function object wrapping a C function pointer.
+
+<p>
+The length argument is the number of arguments to the function.
+If the function is called with fewer arguments, the argument list will be padded with undefined.
+
+<pre>
+void js_newcconstructor(js_State *J,
+ js_CFunction fun, js_CFunction con, unsigned int length);
+</pre>
+
+<p>
+Pop the object to set as the "prototype" property for the constructor function object.
+Push a function object wrapping a C function pointer, allowing for separate function pointers for regular calls and 'new' operator calls.
+
+<pre>
+void js_currentfunction(js_State *J);
+</pre>
+
+<p>
+Push the currently executing function object.
+
+<h3>Userdata</h3>
+
+<pre>
+void js_newuserdata(js_State *J, const char *tag, void *data);
+</pre>
+
+<p>
+Pop an object from the top of the stack to use as the internal prototype property for the new object.
+Push a new userdata object wrapping a pointer to C memory.
+The userdata object is tagged using a string, to represent the type of the C memory.
+
+<pre>
+int js_isuserdata(js_State *J, int idx, const char *tag);
+</pre>
+
+<p>
+Test if an object is a userdata object with the given type tag string.
+
+<pre>
+void *js_touserdata(js_State *J, int idx, const char *tag);
+</pre>
+
+<p>
+Return the wrapped pointer from a userdata object.
+If the object is undefined or null, return NULL.
+If the object is not a userdata object with the given type tag string, throw a type error.
+
+<h3>Registry</h3>
+
+<p>
+The registry can be used to store references to Javascript objects accessible from C,
+but hidden from Javascript to prevent tampering.
+
+<pre>
+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);
+</pre>
+
+<p>
+Access properties on the hidden registry object.
+
+<pre>
+const char *js_ref(js_State *J);
+</pre>
+
+<p>
+WIP: Pop a value from the stack and store it in the registry using a new unique property name.
+Return the property name.
+
+<pre>
+void js_unref(js_State *J, const char *ref);
+</pre>
+
+<p>
+WIP: Delete the reference from the registry.
+
+</body>
--- /dev/null
+++ b/docs/style.css
@@ -1,0 +1,16 @@
+@import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400italic,600,600italic|Source+Code+Pro);
+
+body {
+ font-family: 'Source Sans Pro', sans-serif;
+ font-size: 12pt;
+ margin: 3pc;
+ max-width: 45em;
+ text-align: justify;
+}
+pre, tt, code {
+ font-family: 'Source Code Pro', monospaced;
+ font-size: 11pt;
+}
+h2 {
+ border-bottom: 2px solid black;
+}