class for SpiderMonkey, it's quite intimidating. To build a class that
conversions between SpiderMonkey datatypes and
regular C++ datatypes.
Although it's not impossible, it quickly becomes tedious if you have many classes that need to be integrated.
The code contains code wrappers and the necessary functions to
The generated code links each C++ class instance to a
class. This allows you to use the same instances from both entry points. (An
getJSObject() on it.)
You can take an existing class header, add a couple
comments here and there, add an include in your .h and .cpp files, and run it through this program and it will be
jsgen works best if you're using a single .cpp/.h file for each separate class.
After you define your context, you must initialize each class using
the JSInit function generated by jsgen. This makes SpiderMonkey
aware of your class, and if you made any constructors visible, allows the
// Define JSTest class
// Define Vector2d class
new Vector2d, or whatever constructors they have.
In addition, you can create class using
context with the generated
getJSObject(JSContext *) function.
JS_DefineProperty(cx, globalObj, "test", OBJECT_TO_JSVAL(test.getJSObject(cx)), NULL, NULL, JSPROP_ENUMERATE);
jsgen isn't under any specific license. Feel free to use it, modify it, do
whatever with it, for any use, whether it's personal, academic, commercial, or whatever. The main the credit
goes to the writers of SpiderMonkey for such as a cool scripting
Back to Top
JSObject *newJSObject(JSContext *)
JS_NewObject, and doesn't call JSInit anymore
getContext()function, in favor of a special argument of type
jsval* argvspecial arguments, so they can be used in combination with other arguments
JSObject*with special argument
JSObject*to be converted with
Object* owill function like a regular object by reference
-Wall -W -Werror -Wno-unusedto makefile, and updated jsgen's output to produce no errors in this setting
virtualkeyword is no longer default for get/set accessor functions
Added support for static variables and functions
enumblocks read as
static const int readonly normalvariables.
jsgen was designed on mingw32 (gcc for win32), but it should theoretically work with any modern C++ compiler or platform that supports the standard classes (iostream, string, fstream, sstream, vector, map), and some other headers (ctype.h, string.h).
jsgen itself doesn't use SpiderMonkey, but anything generated by it (such as the example included) will need it.
To compile everything:
To compile just jsgen:
Back to Top
jsgen <source.h> <output.h> <output.cpp>
The most important point to keep in mind is that jsgen is a very dumb parser (anyone who wants to help make it better, let me know). It's a basic
linear parser that looks for specific phrases and hardcoded formatting
that should function with most C++.
Anything it's not specifically looking for will likely screw things up, so make sure you read this section carefully.
Because jsgen cares only about syntax in its comment regions,
they're the only important parts to clean up for jsgen. (For example, comments inside a region will
In general it will accept odd code without crashing, but it will generate code may be odd (and not work) as well.
jsgen doesn't use a preprocessor, so macros and includes are ignored.
jsgen's parsing strategy:
class, and grabbing the following word (word is everything but whitespace). If the next word ends with a
;jsgen will ignore it and start looking for
classagain (a semicolon should signify that the class is part of a forward declaration).
class yourclass : public/protected anotherclass," with whitespace around the
:, then jsgen will assume inheritance and automatically generate code to deal with prototypes.
private, jsgen will treat the class if it had no parent (and generate no code for dealing with prototype).
v): jsgen reads to the end of the comment and parses them as variable definitions.
[brackets]is optional, without the
[static] [virtual] [const] type name [readonly] [normal] [const];
;and assumes that's a variable definition.
namestarts with *, it'll be stripped off and appended to the
type, this will make
int *iinto type=
int*, and name=
normalwill create a public member variable in the C++ class with the specified type and name. jsgen will generate code to assign and retrieve with this variable with no further interfacing.
normal, jsgen creates two function prototypes:
void setName(type). jsgen capitalizes the first letter of the variable, and appends it to get or set. So
int x;will create int getX(); and void setX(int x);
normal, the code for assigning to the variable is left out, otherwise no set function is defined.
virtualwill simply mark the generated get/set functions as
staticmakes a static variable.
consthas a double meaning. It will either generate
get()functions that are
normalis not set; or, if
normalis set, jsgen will assume this value is already defined as a constant somewhere (such as a
enum), and return that every time.
m): jsgen first looks for the
*/, then immediately grabs everything from
/* end */and tries to parse functions from that. (In the future extra keywords may be placed after the word
/* end */block will confuse the parser, so keep them outside the block.
(as the method name.
type *name), jsgen will move
&from the name to the type so as not to cause problems.
)as the arguments
), and getting the first word as a type, and the second as a name.
c): grabs everything the same way as with
): grabs everything the same way as with
,(comma), then strips off
=and anything after it if found, this is used as the variable name.
static const int NAME normal readonly;variables, and will function as if you made a variables block with definitions for each enum.
Back to Top
The standard (argument/return/variable) types that jsgen can recognize are
JSString*. These will all be autoconverted using jsgen's macros.
Any other type is considered an object. You can use other C++
classes as parameters and variables with jsgen, provided they've been jsgen-generated as well. If you want to
use a class that doesn't have jsgen-generated code in it, it will need the following function:
JSObject *getJSObject(JSContext *).
You should be able to pass classes by reference by using &, but this hasn't been tested on non-class types
(for example, int &).
You can use class variables by reference using the pointer type of the
class if you don't want the class copied around using the assignment operator.
const keyword on function arguments isn't yet understood by jsgen, and will cause jsgen to generate invalid code.
const functions should theoretically work, because that keyword is after the
), and jsgen ignores that part.
jsvaltype arguments and variables allow you to get use values without any automatic conversions by jsgen. It's also useful as an unspecific variable type.
jsval), it gives you full control over your variables.
objects and strings around without having to use
JSVAL_TO_STRING in your own
JSString* type arguments, the argument will be checked with
JSVAL_IS_STRING unlike with using a regular
arguments, jsgen handles overloaded constructors and methods by
checking the argument types.
jsvaltype, and do your own checking.
JSBool(this is different from
bool!), you can return
JS_FALSEfor function success. jsgen won't convert this special return type. (If you also want to return a value, read further down about
JSContext *is hidden.
If either of these arguments are included in your function (I highly
recommend placing them as the last two arguments), then the argument
The argument type and names must be exactly (case-sensitive)
uintN argc and
jsval *argv (or
jsval* argv), or jsgen will not recognize them as special arguments.
argv will allow you dynamic variable types, when overloading, functions/constructors with these two special
arguments will be called after variables have first been matched functions/constructors without either of these arguments.
This allows you use these special arguments in a "catch-all" function/constructor that can handle any combination of arguments after first checking more specific argument combinations.
You can also mix these special arguments with regular arguments. jsgen will first check if
is greater or equal to the number of non-special arguments, then match the first
entries in argv to the non-special arguments and call the function.
If you have any parameter of type
jsval*, but isn't called
is the recommended name), it will be given the pointer to the return
With this argument, you should either
JSBool, otherwise jsgen will overwrite any changes to the pointer after the function call returns.
will be passed the current context from the function call. The placement doesn't matter, but I recommend placing this as the very first argument.
JSContext *argument, after that.
double, so if you use the
float type, jsgen will just cast between
float as necessary. This may be a good reason to use
double in your code.
To make life easier, jsgen pretends
are all the same type, and converts between them as necessary.
This is so the user can use a non-decimal as an argument to a function
that takes a
double, or a decimal to a function that takes a
Note: I found it a requirement for
int to be automatically converted to
int, and it can't be used if the function only accepts double.
However, I can see the argument to not automatically convert from
int. It is convenient, though, and I'll only remove it if recommended.
These are the only auto-converted types, it's up to the user to use
parseFloat to convert other types (such as a string) to a number.
double are considered the same type, and thus will probably cause problems when overloading.
stringtype uses STL strings. If you don't use STL strings, consider them, they're quite nice. If you need otherwise, you can use
jsvaltype as an argument and convert manually.
Back to Top
static JSObject *JSInit(JSContext *cx, JSObject *obj = NULL);
This static function initializes the class into a specified object by calling
JS_InitClass, it will automatically call
JSIniton a parent class with the same context and object.
JSInitfirst checks if the class (or something of the same name) already exists in the
obj, and can safely be called multiple times.
objis the object that the class is part of, in general this will be your global object. If
JS_GetGlobalObjectis used to retrieve the global object associated with the context.
JSInitreturns the result of
JS_InitClass, or the previously created class.
JSObject *getJSObject(JSContext *cx);
This function returns the JSObject * associated with the instance of the C++ class. If there is none, one is created using the
newJSObjectfunction and associated for future calls to
This function is used by jsgen code to automatically convert C++ classes to
JS_DefineProperty(cx, globalObj, "foo", OBJECT_TO_JSVAL(foo.getJSObject(cx)), NULL, NULL, JSPROP_ENUMERATE);
The following function you may call from your own code, but generally shouldn't:
jsgen will generate other functions, but they shouldn't be called by your own code.
static JSObject *newJSObject(JSContext *cx);
This function is a wrapper for
JS_NewObject, and will automatically create the prototype as necessary. This is used by
getJSObjectwhen a new object is needed.
Back to Top
The files example directory demonstrate jsgen in
action. It also shows you how you could use jsgen in a Makefile
to autogenerate code whenever the class definition file changes.
After compiling, type
test test.js to try it out. Most of the output will be gibberish, so open test.js up in a text editor to see what's going on.
The JSTest class is a fairly useless class that
demonstrates a number of different function formats (most of
which print to standard out), variables formats, and the ability to
have another class
as a variable.
The Vector2d class is a demonstration of an actual class that might be used.
The JSTestChild/JSTestChild2/Vector2dChild classes demonstrate prototyping.
Back to Top
jsin your source directory to store the files generated by jsgen.
js/%.h: %.h $(JSGEN)
$(JSGEN) $< js/$< js/$(subst .h,.cpp,$<)
JSGENearlier in your makefile.)
JS_HFILES= $(addprefix js/,$(addsuffix .h, $(notdir $(JS_MODULES))))
MODULESin the same format as
JS_MODULES, use the following code:
OBJS= $(addprefix objs/, $(addsuffix .o, $(notdir $(MODULES) $(JS_MODULES))))to merge the classes from the
MODULESlist with the
JS_MODULESlist into a list of object files (in a directory called objs, in this example).
$(OUTEXE): $(JS_HFILES) $(OBJS)
$(CXX) $(OBJS) -o $@ $(LIBDIR) $(LIBS)
js/include.h: $(JS_HFILES) $(MERGEJS)
$(MERGEJS) js/include.h $(JS_MODULES)
JS_MODULES, and builds a function (
inline static void loadJS(JSContext *cx, JSObject *obj)) that calls JSInit(cx,obj) on all the classes. This is handy if you want to add classes "on the fly."
Back to Top
The various problems are noted in the Usage section.
JSContexts, but I haven't got a good way to test, so I can't say for sure.
There are no intentionally incomplete features at the moment.
Possible features in the future:
There also aren't any more immediate plans for features in the
future. Basically as soon as I need something for my own project,
I add it.
Back to Top
jsgen was written in entirely TextPad using Mingw32 (make/g++, for building/compiling) by Marcello Bastéa-Forte.
SpiderMonkey is a mozilla.org project by Brendan Eich.
Back to Top
I'm discussing this on and off the allegro.cc forums, so please post if you see my thread.
Last of all you can email me at email@example.com.
Back to Top