diff --git a/Doc/Manual/Javascript.md b/Doc/Manual/Javascript.md deleted file mode 100644 index 36dfa7c2f..000000000 --- a/Doc/Manual/Javascript.md +++ /dev/null @@ -1,773 +0,0 @@ -# SWIG and Javascript - -This chapter describes SWIG's support of Javascript. -It does not cover SWIG basics, but only information that is specific to this module. - -## Overview - -JavaScript is a prototype-based scripting language that is dynamic, weakly typed -and has first-class functions. Its arguably the most popular language for web development. -Beyond of being a browser-based scripting language, with [node.js](http://nodejs.org) -Javascript has found its way to a backend development language, too. - -Native Javascript extensions can be used for applications that embed a web-browser view or -that embed a Javascript engine (such as *node.js*). -Extending a general purpose web-browser is not possible as this would be severe security issue. - -SWIG Javasript currently supports **JavascriptCore**, the Javascript engine used by `Safari/Webkit`, and **v8**, which is used by `Chromium` and `node.js`. - -[WebKit](http://www.webkit.org/) is a modern browser -implementation available as open-source which can be embedded into an application. - -## Preliminaries - -### Running SWIG - -Suppose that you defined a SWIG module such as the following: - - %module example - %{ - #include "example.h" - %} - int gcd(int x, int y); - extern double Foo; - -To build a Javascript module, run SWIG using the `-javascript` option -and a desired target engine `-jsc`, `-v8`, or `-node`. -The generator for `node` is essentially delegating to the `v8` generator and adds -some necessary preprocessor definitions. - - $ swig -javascript -jsc example.i - -If building a C++ extension, add the -c++ option: - - $ swig -c++ -javascript -jsc example.i - -This creates a C/C++ source file example_wrap.c or example_wrap.cxx. The generated C source file contains the low-level wrappers that need to be compiled and linked with the rest of your C/C++ application to create an extension module. - -The name of the wrapper file is derived from the name of the input file. -For example, if the input file is example.i, the name of the wrapper file is example_wrap.c. -To change this, you can use the -o option. -The wrapped module will export one function which must be called to register the module with the Javascript interpreter. -For example, if your module is named `example` the corresponding initializer for JavascriptCore would be - - bool example_initialize(JSGlobalContextRef context, JSObjectRef *exports) - -and for v8: - - void example_initialize (v8::Handle exports) - -### Running Tests and Examples - -The configuration for tests and examples currently supports Linux and Mac only, MinGW not yet. - -The default interpreter is `node.js` as it is available on all platforms and convenient to use. - -Running the examples with JavascriptCore requires `libjavascriptcoregtk-1.0` to be installed, e.g., under Ubuntu with - - $ sudo apt-get install libjavascriptcoregtk-1.0-dev - -Running with `V8` requires `libv8`: - - $ sudo apt-get install libv8-dev - -Examples can be run using - - $ make ENGINE=jsc check-javascript-examples - -`ENGINE` can be `node`, `jsc`, or `v8`. - -The test-suite can be run using - - $ make ENGINE=jsc check-javascript-test-suite - -A smaller, manually selected set of tests can be run using - - $ make SMOKE=1 ENGINE=jsc check-javascript-test-suite - - -Tests should run without any problems, i.e., have been tried out, on the following platforms/interpreters: - - - Ubuntu Precise 12.04 64bit - - JavascriptCore (Webkit 1.8.3) - - Node.js (0.10.26) - - v8 (3.7.12) - - Ubuntu Saucy 13.10 64bit - - JavascriptCore (Webkit 1.10.2) - - Node.js - - v8 (3.14.5) - - Mac OSX Mountain Lion 10.8 - - JavascriptCore (built-in) - - Node.js - - Windows 7 64bit (VS 2010) - - Node.js - -Note: a `CMake` based configuration can be found in the `cmake` branch on - [](https://github.com/oliver----/swig-v8) which can be used to generate a Visual Studio solution. It is rather limited building only the SWIG executable and Javascript examples. - -### Future work - -The Javascript module is not yet as mature as other modules and some things are still missing. -As it makes use of Swigs Unified typemap library (UTL), many typemaps are inherited. -We could work on that if requested: - -- More typemaps: compared to other modules there are only a few typemaps implemented. - For instance a lot of the `std_*.i` typemaps are missing, such as `std_iostream`, for instance. - -- Director support: this would allow to extend a C++ abstract base class in Javascript. - A pragmatic intermediate step for the most important usecase - would be to support Javascript callbacks as arguments. - -- We will try to find a way into - [Chromium Embedded Framework (CEF)](http://code.google.com/p/chromiumembedded/). - CEF is also open-source and available for all platforms. - However, at the moment it does not provide access to the native V8 engine, - making it impossible to extend the engine using the extensions created with this module. - - -## Integration - -This chapter gives a short introduction how to use a native Javascript extension: as a `node.js` module, and as an extension for an embedded Webkit. - - -### Creating `node.js` Extensions - -To install `node.js` you can download an installer from their -[web-site](https://launchpad.net/~chris-lea/+archive/node.js) for OSX and Windows. -For Linux you can either build the source yourself and to a `sudo checkinstall` -or stick to the (probably stone-age) packaged version. -For Ubuntu there is a [PPA](https://launchpad.net/~chris-lea/+archive/node.js/) available. - - $ sudo add-apt-repository ppa:chris-lea/node.js - $ sudo apt-get update - $ sudo apt-get install nodejs - -As `v8` is written in C++ and comes as a C++ library it is crucial to compile your module -using the same compiler flags as used for building v8. -To make things easier, `node.js` provides a build tool called `node-gyp`. - -You have to install it using `npm`: - - $ npm install -g node-gyp - - -`node-gyp` expects a configuration file named `binding.gyp` which is basically in JSON -format and conforms to the same format that is used with Google's build-tool `gyp`. - -`binding.gyp`: - - { - "targets": [ - { - "target_name": "example", - "sources": [ "example.cxx", "example_wrap.cxx" ] - } - ] - } - -First create the wrapper using SWIG: - - $ swig -javascript -node -c++ example.cxx - -Then run `node-gyp` - - $ node-gyp - -This will create a `build` folder containing the native module. -To use the extension you have to require it in your javascript source file. - - require("./build/Release/example") - - -A more detailed exlanation is given in section `Examples`. - - -#### Troubleshooting - -- *'module' object has no attribute 'script_main'* - - This happened when `gyp` was installed as distribution package. - It seems to be outdated. Removing it resolves the problem. - - $ sudo apt-get remove gyp - - -### Embedded Webkit - -Webkit is built-in for OSX and available as library for GTK. - - -#### OSX - -There is general information about programming with WebKit on -[Apple Developer Documentation](https://developer.apple.com/library/mac/documentation/cocoa/conceptual/DisplayWebContent/DisplayWebContent.html). -Details about `Cocoa` programming are not covered here. - -An integration of a native extension 'example' would look like this: - - #import "appDelegate.h" - - extern bool example_initialize(JSGlobalContextRef context); - - - @implementation ExampleAppDelegate - - @synthesize webView; - - - - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - - // Start a webview with the bundled index.html file - NSString *path = [[NSBundle mainBundle] bundlePath]; - NSString *url = [NSString stringWithFormat: @"file://%@/Contents/Assets/index.html", path]; - - WebFrame *webframe = [webView mainFrame]; - JSGlobalContextRef context = [webframe globalContext]; - - example_initialize(context); - - [ [webView mainFrame] loadRequest: - [NSURLRequest requestWithURL: [NSURL URLWithString:url] ] - ]; - } - - @end - -#### GTK - -There is general information about programming GTK on the -[GTK documentation](https://developer.gnome.org/gtk2/), in the -[GTK tutorial](https://developer.gnome.org/gtk-tutorial), -and for Webkit there is a [Webkit GTK+ API Reference](http://webkitgtk.org/reference/webkitgtk/stable/index.html). - -An integration of a native extension 'example' would look like this: - - #include - #include - - extern bool example_initialize(JSGlobalContextRef context); - - int main(int argc, char* argv[]) - { - // Initialize GTK+ - gtk_init(&argc, &argv); - - ... - - // Create a browser instance - WebKitWebView *webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); - WebFrame *webframe = webkit_web_view_get_main_frame(webView); - JSGlobalContextRef context = webkit_web_frame_get_global_context(webFrame); - example_initialize(context); - - ... - - // Load a web page into the browser instance - webkit_web_view_load_uri(webView, "http://www.webkitgtk.org/"); - - ... - - // Run the main GTK+ event loop - gtk_main(); - - return 0; - } - -## Examples - -Some basic examples are shown here in more detail. - -### Simple - -The common example `simple` looks like this: - - /* File : example.i */ - %module example - - %inline %{ - extern int gcd(int x, int y); - extern double Foo; - %} - -To make this available as node extension a `binding.gyp` has to be created: - - { - "targets": [ - { - "target_name": "example", - "sources": [ "example.cxx", "example_wrap.cxx" ] - } - ] - } - -Then `node-gyp` is used to build the extension: - - $ node-gyp configure build - - -From a 'nodejs` application this would be used this way: - - // import the extension via require - var example = require("./build/Release/example"); - - // calling the global method - var x = 42; - var y = 105; - var g = example.gcd(x,y); - - // Accessing the globak variable - var f = example.Foo; - example.Foo = 3.1415926; - -First the module `example` is loaded from the previously built extension. -Global methods and variables are available in the scope of the module. - -> Note: ECMAScript 5, the currently implemented Javascript standard, does not have modules. -> `node.js` and other implementations provide this mechanism defined by the -> [CommonJS](http://wiki.commonjs.org/wiki/CommonJS) group. -> For browsers this is provided by [Browserify](http://browserify.org), for instance. - -### Class - -The common example `class` defines three classes, `Shape`, `Circle`, and `Square`: - - class Shape { - public: - Shape() { - nshapes++; - } - virtual ~Shape() { - nshapes--; - }; - double x, y; - void move(double dx, double dy); - virtual double area(void) = 0; - virtual double perimeter(void) = 0; - static int nshapes; - }; - - class Circle : public Shape { - private: - double radius; - public: - Circle(double r) : radius(r) { }; - virtual double area(void); - virtual double perimeter(void); - }; - - class Square : public Shape { - private: - double width; - public: - Square(double w) : width(w) { }; - virtual double area(void); - virtual double perimeter(void); - }; - -`Circle` and `Square` inherit from `Shape`. `Shape` has a static variable `nshapes`, -a function `move` that can't be overridden (non-virtual), -and two abstract functions `area` and `perimeter` (pure virtual) that must be -overridden by the sub-classes. - -A `nodejs` extension is built the same way as for the `simple` example. - -In javascript it can be used this way: - - - var example = require("./build/Release/example"); - - // local aliases for convenience - var Shape = example.Shape; - var Circle = example.Circle; - var Square = example.Square; - - // creating new instances using the 'new' operator - var c = new Circle(10); - var s = new Square(10); - - // accessing a static member - Shape.nshapes; - - // accessing member variables - c.x = 20; - c.y = 30; - s.x = -10; - s.y = 5; - - // calling some methods - c.area(); - c.perimeter(); - s.area(); - s.perimeter(); - - // instantiation of Shape is not permitted - new Shape(); - -Running these commands in an interactive node shell results in the following output: - - $ node -i - > var example = require("./build/Release/example"); - undefined - > var Shape = example.Shape; - undefined - > var Circle = example.Circle; - undefined - > var Square = example.Square; - undefined - > var c = new Circle(10); - undefined - > var s = new Square(10); - undefined - > Shape.nshapes; - 2 - > c.x = 20; - 20 - > c.y = 30; - 30 - > s.x = -10; - -10 - > s.y = 5; - 5 - > c.area(); - 314.1592653589793 - > c.perimeter(); - 62.83185307179586 - > s.area(); - 100 - > s.perimeter(); - 40 - > c.move(40, 40) - undefined - > c.x - 60 - > c.y - 70 - > new Shape() - Error: Class Shape can not be instantiated - at repl:1:2 - at REPLServer.self.eval (repl.js:110:21) - at Interface. (repl.js:239:12) - at Interface.EventEmitter.emit (events.js:95:17) - at Interface._onLine (readline.js:202:10) - at Interface._line (readline.js:531:8) - at Interface._ttyWrite (readline.js:760:14) - at ReadStream.onkeypress (readline.js:99:10) - at ReadStream.EventEmitter.emit (events.js:98:17) - at emitKey (readline.js:1095:12) - - -> Note: In ECMAScript 5 there is no concept for classes. - Instead each function can be used as a constructor function which is executed by the 'new' - operator. Furthermore, during construction the key property `prototype` of the constructor function is used to attach a prototype instance to the created object. - A prototype is essentially an object itself that is the first-class delegate of a class - used whenever the access to a property of an object fails. - The very same prototype instance is shared among all instances of one type. - Prototypal inheritance is explained in more detail on in - [Inheritance and the prototype chain](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain), for instance. - - -## Implementation - -The Javascript Module implementation has take a very different approach than other modules -to be able to generate code for different Javascript interpreters. - -### Source Code - -The Javascript module is implemented in `Source/Modules/javascript.cxx`. -It dispatches the code generation to a `JSEmitter` instance, `V8Emitter` or `JSCEmitter`. Additionally there are some helpers: `Template`, for templated code generation, and `JSEmitterState`, which is used to manage state information during AST traversal. -This rough map shall make it easier to find a way through this huge source file: - - // module wide defines - - #define NAME "name" - ... - - // ############################### - // # Helper class declarations - - class JSEmitterState { ... }; - - class Template { ... }; - - // ############################### - // # JSEmitter declaration - - class JSEmitter { ... }; - - // Emitter factory declarations - - JSEmitter *swig_javascript_create_JSCEmitter(); - JSEmitter *swig_javascript_create_V8Emitter(); - - // ############################### - // # Javascript module - - // Javascript module declaration - - class JAVASCRIPT:public Language { ... }; - - // Javascript module implementation - - int JAVASCRIPT::functionWrapper(Node *n) { ... } - ... - - // Module factory implementation - - static Language *new_swig_javascript() { ... } - - extern "C" Language *swig_javascript(void) { ... } - - // ############################### - // # JSEmitter base implementation - - JSEmitter::JSEmitter() { ... } - - Template JSEmitter::getTemplate(const String *name) { ... } - ... - - // ############################### - // # JSCEmitter - - // JSCEmitter declaration - - class JSCEmitter: public JSEmitter { ... }; - - // JSCEmitter implementation - - JSCEmitter::JSCEmitter() { ... } - - void JSCEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) { ... } - ... - - // JSCEmitter factory - - JSEmitter *swig_javascript_create_JSCEmitter() { ... } - - - // ############################### - // # V8Emitter - - // V8Emitter declaration - - class V8Emitter: public JSEmitter { ... }; - - // V8Emitter implementation - - V8Emitter::V8Emitter() { ... } - - int V8Emitter::initialize(Node *n) { ... } - - // V8Emitter factory - - JSEmitter *swig_javascript_create_V8Emitter() { ... } - - - // ############################### - // # Helper implementation (JSEmitterState, Template) - - JSEmitterState::JSEmitterState() { ... } - ... - - Template::Template(const String *code_) { ... } - ... - - -### Code Templates - -All generated code is created on the basis of code templates. -The templates for *JavascriptCore* can be found in `Lib/javascript/jsc/javascriptcode.swg`, -for *v8* in `Lib/javascript/v8/javascriptcode.swg`. - -To track the originating code template for generated code you can run - - $ swig -javascript -jsc -debug-codetemplates - -which wraps generated code with a descriptive comment - - /* begin fragment("temlate_name") */ - - ...generated code ... - - /* end fragment("temlate_name") */ - -The Template class is used like this: - - Template t_register = getTemplate("jsv8_register_static_variable"); - t_register.replace("$jsparent", state.clazz(NAME_MANGLED)) - .replace("$jsname", state.variable(NAME)) - .replace("$jsgetter", state.variable(GETTER)) - .replace("$jssetter", state.variable(SETTER)) - .trim(). - print(f_init_static_wrappers); - -A code template is registered with the *JSEmitter* via `fragment(name, "template")`, e.g., - - %fragment ("jsc_variable_declaration", "templates") - %{ - {"$jsname", $jsgetter, $jssetter, kJSPropertyAttributeNone}, - %} - -`Template` creates a copy of that string and `Template::replace` uses Swig's `Replaceall` -to replace variables in the template. `Template::trim` can be used to eliminate -leading and trailing whitespaces. `Template::print` is used to write the final template string -to a Swig `DOH` (based on `Printv`). All methods allow chaining. - -### Emitter - -The Javascript module delegates code generation to a `JSEmitter` instance. -The following extract shows the essential interface: - - class JSEmitter { - ... - - /** - * Opens output files and temporary output DOHs. - */ - virtual int initialize(Node *n); - - /** - * Writes all collected code into the output file(s). - */ - virtual int dump(Node *n) = 0; - - /** - * Cleans up all open output DOHs. - */ - virtual int close() = 0; - - ... - - /** - * Invoked at the beginning of the classHandler. - */ - virtual int enterClass(Node *); - - /** - * Invoked at the end of the classHandler. - */ - virtual int exitClass(Node *) { - return SWIG_OK; - }; - - /** - * Invoked at the beginning of the variableHandler. - */ - virtual int enterVariable(Node *); - - /** - * Invoked at the end of the variableHandler. - */ - virtual int exitVariable(Node *) { - return SWIG_OK; - }; - - /** - * Invoked at the beginning of the functionHandler. - */ - virtual int enterFunction(Node *); - - /** - * Invoked at the end of the functionHandler. - */ - virtual int exitFunction(Node *) { - return SWIG_OK; - }; - - /** - * Invoked by functionWrapper callback after call to Language::functionWrapper. - */ - virtual int emitWrapperFunction(Node *n); - - /** - * Invoked from constantWrapper after call to Language::constantWrapper. - **/ - virtual int emitConstant(Node *n); - - /** - * Registers a given code snippet for a given key name. - * - * This method is called by the fragmentDirective handler - * of the JAVASCRIPT language module. - **/ - int registerTemplate(const String *name, const String *code); - - /** - * Retrieve the code template registered for a given name. - */ - Template getTemplate(const String *name); - - State &getState(); - - ... - - } - -The module calls `initialize`, `dump`, and `close` from within the `top` method: - - int JAVASCRIPT::top(Node *n) { - emitter->initialize(n); - - Language::top(n); - - emitter->dump(n); - emitter->close(); - - return SWIG_OK; - } - -The methods `enterClass` and `exitClass` are called from within the `classHandler` method: - - int JAVASCRIPT::classHandler(Node *n) { - - emitter->enterClass(n); - Language::classHandler(n); - emitter->exitClass(n); - - return SWIG_OK; - } - -In `enterClass` the emitter stores state information that is necessary when processing class members. In `exitClass` the wrapper code for the whole class is generated. - - -### Emitter states - -For storing information during the AST traversal the emitter provides a `JSEmitterState` with -different slots to store data representing the scopes global, class, function, and variable. - - class JSEmitterState { - - public: - - JSEmitterState(); - - ~JSEmitterState(); - - DOH *global(); - - DOH *global(const char* key, DOH *initial = 0); - - DOH *clazz(bool reset = false); - - DOH *clazz(const char* key, DOH *initial = 0); - - DOH *function(bool reset = false); - - DOH *function(const char* key, DOH *initial = 0); - - DOH *variable(bool reset = false); - - DOH *variable(const char* key, DOH *initial = 0); - - static int IsSet(DOH *val); - - ... - }; - -When entering a scope, such as in `enterClass`, the corresponding state is reset and new data -is stored: - - state.clazz(RESET); - state.clazz(NAME, Getattr(n, "sym:name")); - -State information can be retrieved using `state.clazz(NAME)` or -with `Getattr` on `state.clazz()` which actually returns a `Hash` instance.