Commits

Alexander Tsepkov committed 28deebf

Class binding rewritten, auto-bind option added and explained in README

  • Participants
  • Parent commits b1b81d9

Comments (0)

Files changed (20)

 
 Installation
 ------------
-First make sure you have installed the latest version of [node.js](http://nodejs.org/) (You may need to restart your computer after this step).
+First make sure you have installed the latest version of [node.js](http://nodejs.org/) (You may need to restart your computer after this step). You may also need to install `optimist` library.
 
 From NPM for use as a command line app:
 
-    npm install rapydscript -g
+	npm install rapydscript -g
 
 From NPM for programmatic use:
 
-    npm install rapydscript
+	npm install rapydscript
 
 From Mercurial:
 
-    hg clone https://bitbucket.org/pyjeon/rapydscript
-    cd rapydscript
-    npm link .
+	hg clone https://bitbucket.org/pyjeon/rapydscript
+	cd rapydscript
+	npm link .
 
 From Git:
 
-    git clone git://github.com/atsepkov/RapydScript.git
-    cd RapydScript
-    npm link .
+	git clone git://github.com/atsepkov/RapydScript.git
+	cd RapydScript
+	npm link .
 
 If you're using OSX, you can probably use the same commands (let me know if that's not the case). If you're using Windows, you should be able to follow similar commands after installing node.js and git on your system.
 
 
 The available options are:
 
-    -o, --output       Output file (default STDOUT).
-    -b, --bare         Omit scope-protection wrapper around generated code
-    -p, --prettify     Beautify output/specify output options.            [string]
-    -n, --namespace-imports  Pythonic imports (experimental)
-    -v, --verbose      Verbose                                           [boolean]
-    -V, --version      Print version number and exit.                    [boolean]
+	-o, --output       Output file (default STDOUT).
+	-b, --bare         Omit scope-protection wrapper around generated code
+	-p, --prettify     Beautify output/specify output options.            [string]
+	-n, --namespace-imports  Pythonic imports (experimental)
+	-v, --verbose      Verbose                                           [boolean]
+	-V, --version      Print version number and exit.                    [boolean]
+	-t, --test         Run unit tests, making sure the compiler produces usable code
+	-m, --omit-baselib Omit base library from generated code, make sure you're including baselib.js if you use this
+	-i, --auto-bind    Automatically bind methods to the class they belong to (more Pythonic, but could interfere with other JS libs)
+	--screw-ie8        Optimize compilation, sacrificing compatibility with older browsers
 
 The rest of the option remain from UglifyJS and have not been tested, some may work, but most will not, since the AST is different between RapydScript and UglifyJS. These option  will eventually be removed or modified to be relevant to RapydScript.
 
 Some methods in the native JavaScript classes, such as `String.fromCharCode()` have also been marked as static to make things easier for the developer.
 
 
-External Classes
-----------------
+### External Classes
 RapydScript will automatically detect classes declared within the same scope (as long as the declaration occurs before use), as well as classes properly imported into the module (each module making use of a certain class should explicitly import the module containing that class). RapydScript will also properly detect native JavaScript classes (String, Array, Date, etc.). Unfortunately, RapydScript has no way of detecting classes from third-party libraries. In those cases, you could use the `new` keyword every time you create an object from such class. Alternatively, you could mark the class as external.
 
 Marking a class as external is done via `external` decorator. You do not need to fill in the contents of the class, a simple `pass` statement will do:
 	class Alpha:
 		pass
 
-RapydScript will now treat `Alpha` as if it was declared within the same scope, auto-prepending the `new` keyword when needed and using `prototype` to access its methods. You don't need to pre-declare the methods of this class (unless you decide to for personal reference, the compiler will simply ignore them) unless you want to mark certain methods as static:
+RapydScript will now treat `Alpha` as if it was declared within the same scope, auto-prepending the `new` keyword when needed and using `prototype` to access its methods (see `casperjs` example in next section to see how this can be used in practice). You don't need to pre-declare the methods of this class (unless you decide to for personal reference, the compiler will simply ignore them) unless you want to mark certain methods as static:
 
 	@external
 	class Alpha:
 You could also use `external` decorator to bypass improperly imported RapydScript modules. However, if you actually have control of these modules, the better solution would be to fix those imports.
 
 
+### Method Binding
+By default, RapydScript does not bind methods to the classes they're declared under. This behavior is unlike Python, but very much like the rest of JavaScript. For example, consider this code:
+
+	class Boy:
+		def __init__(self, name):
+			self.name = name
+
+		def greet(self):
+			print('My name is' + self.name)
+
+	tod = Boy('Tod')
+	tod.greet()                 # Hello, my name is Tod
+	getattr(tod, 'greet')()     # Hello, my name is undefined
+
+In some cases, however, you may wish for the functions to remain bound to the object they were retrieved from. For those cases, RapydScript has `bind` function. Unlike regular JavaScript `Function.prototype.bind`, RapydScript's `bind` can rebind methods that have already been bound. The binding we wanted to see in the above example can be achieved as follows:
+
+	bound = bind(getattr(tod, 'greet'), tod)
+	bound()                     # Hello, my name is Tod
+
+To unbind a bound method, you can call pass `false` as a second argument instead of an object you wish to bind to. You can also auto-bind all methods of the class by calling `rebind_all`:
+
+	class Boy:
+		def __init__(self, name):
+			self.name = name
+			rebind_all(self)
+
+		def greet(self):
+			print('My name is' + self.name)
+
+	tod = Boy('Tod')
+	tod.greet()                 # Hello, my name is Tod
+	getattr(tod, 'greet')()     # Hello, my name is Tod
+
+Likewise, `rebind_all(self, false)` will unbind all methods. It's not recommended to auto-bind classes that inherit from 3rd party libraries. For example, `casperjs` has `Casper` class, which RapydScript can easily inherit and extend:
+
+	@external
+	class Casper:
+		pass
+
+	class Scraper(Casper):
+		def __init__(self):
+			Casper.__init__(self)
+			self.start()
+
+	s = Scraper()
+	s.thenOpen('http://casperjs.org',
+		def(): this.echo(this.getTitle())
+	)
+	s.run()
+
+Including `rebind_all` call in the constructor, however, will break `Casper`. It is for that reason that `rebind_all` isn't added to the constructor by default by RapydScript. You could, however use `--auto-bind` compile flag to have RapydScript rebind automatically for you. There is a bit more that this flag does behind the scenes, which ensures that class binding behaves identical to Python, at the expense of some performance and compatibility with libraries like `casperjs`.
+
+
 Modules
 -------
 Unlike Python, RapydScript's import system does not automatically encapsulate external files in modules. Multiple RapydScript users have raised concerns about this, so I added explicit modules to RapydScript. They work very similar to implicit modules of Python, with the exception that developer would use the `module` keyword rather than creating a new file. As a result, one can place multiple modules into a single file, or even nest them (note that import logic cannot import from within nested modules individually, only from files). In terms of JavaScript, a module is basically a function such that all of its local variables are visible to the outside. For example:

File bin/rapydscript

     .describe("o", "Output file (default STDOUT).")
     .describe("b", "Remove the module wrapper that prevents RapydScript \
 scope from bleeding into other JavaScript logic.")
-    .describe("n", "Import modules into separate namespaces like Python \
+    .describe("n", "Import files into separate modules like Python \
 instead of concatenating them [experimental].")
+    .describe("i", "Automatically bind function methods to functions themselves \
+instead of using @bound decorator [experimental].")
     .describe("p", "Prettify output/specify output options.")
     .describe("m", "Omit baselib functions (use this if you have a different way of ensuring they're imported, such as including baselib.js).")
-    .describe("d", "Global definitions")
-    .describe("e", "Embed everything in a big function, with a configurable parameter/argument list.")
     .describe("t", "Run RapydScript tests")
 
     .describe("comments", "Preserve copyright comments in the output. \
 because of dead code removal or cascading statements into sequences.")
 
     .describe("stats", "Display operations run time on STDERR.")
-    .describe("self", "Build itself (RapydScript2) as a library (implies --wrap=RapydScript --export-all)")
-    .describe("wrap", "Embed everything in a big function, making the “exports” and “global” variables available. \
-You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser.")
-    .describe("export-all", "Only used when --wrap, this tells RapydScript to add code to automatically export all globals.")
+//    .describe("self", "Build itself (RapydScript2) as a library (implies --wrap=RapydScript --export-all)")
+//    .describe("wrap", "Embed everything in a big function, making the “exports” and “global” variables available. \
+//You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser.")
+//    .describe("export-all", "Only used when --wrap, this tells RapydScript to add code to automatically export all globals.")
     .describe("v", "Verbose")
     .describe("V", "Print version number and exit.")
 
     .alias("b", "bare")
     .alias("v", "verbose")
     .alias("n", "namespace-imports")
+    .alias("i", "auto-bind")
     .alias("p", "prettify")
     .alias("m", "omit-baselib")
-    .alias("d", "define")
-    .alias("r", "reserved")
     .alias("V", "version")
-    .alias("e", "enclose")
     .alias("t", "test")
 
     .string("p")
-    .string("d")
-    .string("e")
     .string("comments")
     .string("wrap")
     .boolean("screw-ie8")
-    .boolean("export-all")
-    .boolean("self")
     .boolean("v")
     .boolean("stats")
     .boolean("V")
+//    .boolean("export-all")
+//    .boolean("self")
 
     .wrap(80)
 
 var BEAUTIFY = getOptions("p", true);
 var NO_MODULE_WRAPPER = getOptions("b", false);
 var NAMESPACE_IMPORTS = getOptions("n", false);
+var AUTO_BIND = getOptions("i", false);
 var OMIT_BASELIB = getOptions("m", false);
 
 var OUTPUT_OPTIONS = {
     beautify: BEAUTIFY ? true : false,
     private_scope: NO_MODULE_WRAPPER ? false : true,
     namespace_imports: NAMESPACE_IMPORTS ? true : false,
+    auto_bind: AUTO_BIND ? true : false,
     omit_baselib: OMIT_BASELIB ? true : false,
     screw_old_browsers: ARGS.screw_ie8 ? true : false
 };
             return;
         }
         // generate output
-        // only a certain subset of flags we can set could produce successful unit tests, let's hardcode that subset
+        // test with and without screw-ie8 flag
         for (var i = 0; i < 2; i++) {
             var title = i == 0 ? 'normal:\t\t' : 'screw-ie8:\t';
             sys.print(title);
             } catch (e) {
                 sys.print(file + ":\t" + e.stack + "\n\n");
                 fs.unlinkSync(filepath + ".js");
-                return;
+                continue;
             }
             sys.print(file + ":\ttest completed successfully\n");
             fs.unlinkSync(filepath + ".js");
                 toplevel: TOPLEVEL,
                 readfile: fs.readFileSync,
                 basedir: path.dirname(file),
+                auto_bind: AUTO_BIND ? true : false,
                 libdir: path.normalize(
                     path.join(
                         path.dirname(module.filename),

File bin/rapydscript.bindattempt1

-#! /usr/bin/env node
-// -*- js -*-
-
-"use strict";
-
-var RapydScript = require("../tools/node");
-var sys = require("util");
-var optimist = require("optimist");
-var fs = require("fs");
-var async = require("async");
-var path = require("path");
-var ARGS = optimist
-    .usage("$0 input1.js [input2.js ...] [options]\n\
-Use a single dash to read input from the standard input.\
-\n\n\
-")
-    .describe("screw-ie8", "Pass this flag if you don't care about full compliance with Internet Explorer 6-8 quirks (by default RapydScript will try to be IE-proof).")
-    .describe("o", "Output file (default STDOUT).")
-    .describe("b", "Remove the module wrapper that prevents RapydScript \
-scope from bleeding into other JavaScript logic.")
-    .describe("n", "Import modules into separate namespaces like Python \
-instead of concatenating them [experimental].")
-    .describe("i", "Automatically bind function methods to functions themselves \
-instead of using @bound decorator [experimental].")
-    .describe("p", "Prettify output/specify output options.")
-    .describe("m", "Omit baselib functions (use this if you have a different way of ensuring they're imported, such as including baselib.js).")
-    .describe("d", "Global definitions")
-    .describe("e", "Embed everything in a big function, with a configurable parameter/argument list.")
-    .describe("t", "Run RapydScript tests")
-
-    .describe("comments", "Preserve copyright comments in the output. \
-By default this works like Google Closure, keeping JSDoc-style comments that contain \"@license\" or \"@preserve\". \
-You can optionally pass one of the following arguments to this flag:\n\
-- \"all\" to keep all comments\n\
-- a valid JS regexp (needs to start with a slash) to keep only comments that match.\n\
-\
-Note that currently not *all* comments can be kept when compression is on, \
-because of dead code removal or cascading statements into sequences.")
-
-    .describe("stats", "Display operations run time on STDERR.")
-    .describe("self", "Build itself (RapydScript2) as a library (implies --wrap=RapydScript --export-all)")
-    .describe("wrap", "Embed everything in a big function, making the “exports” and “global” variables available. \
-You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser.")
-    .describe("export-all", "Only used when --wrap, this tells RapydScript to add code to automatically export all globals.")
-    .describe("v", "Verbose")
-    .describe("V", "Print version number and exit.")
-
-    .alias("o", "output")
-    .alias("b", "bare")
-    .alias("v", "verbose")
-    .alias("n", "namespace-imports")
-    .alias("i", "auto-bind")
-    .alias("p", "prettify")
-    .alias("m", "omit-baselib")
-    .alias("d", "define")
-    .alias("r", "reserved")
-    .alias("V", "version")
-    .alias("e", "enclose")
-    .alias("t", "test")
-
-    .string("p")
-    .string("d")
-    .string("e")
-    .string("comments")
-    .string("wrap")
-    .boolean("screw-ie8")
-    .boolean("export-all")
-    .boolean("self")
-    .boolean("v")
-    .boolean("stats")
-    .boolean("V")
-
-    .wrap(80)
-
-    .argv
-;
-
-normalize(ARGS);
-
-if (ARGS.version || ARGS.V) {
-    var json = require("../package.json");
-    sys.puts(json.name + ' ' + json.version);
-    process.exit(0);
-}
-
-if (ARGS.ast_help) {
-    var desc = RapydScript.describe_ast();
-    sys.puts(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
-    process.exit(0);
-}
-
-if (ARGS.h || ARGS.help) {
-    sys.puts(optimist.help());
-    process.exit(0);
-}
-
-if (ARGS.t || ARGS.test) {
-    // run all tests and exit
-    var assert = require("assert");
-    var test_dir = path.normalize(
-        path.join(
-            path.dirname(module.filename),
-            "../test"
-        )
-    );
-    var files = fs.readdirSync(test_dir).filter(function(name){
-        return /^[^_].*\.pyj$/.test(name);
-    });
-    files.forEach(function(file){
-        var ast;
-        var filepath = path.join(test_dir, file);
-        try {
-            ast = RapydScript.parse(fs.readFileSync(filepath, "utf-8"), {
-                filename: file,
-                toplevel: ast,
-                readfile: fs.readFileSync,
-				basedir: path.normalize(
-                    path.join(
-                        path.dirname(module.filename),
-                        "../test"
-                    )
-                ),
-                libdir: path.normalize(
-                    path.join(
-                        path.dirname(module.filename),
-                        "../src"
-                    )
-                )
-            });
-        } catch(ex) {
-//            if (ex instanceof RapydScript.JS_Parse_Error) {
-//                sys.print("Error parsing test file: " + file);
-//            }
-            sys.print(file + ":\t" + ex + "\n");
-            return;
-        }
-        // generate output
-        var output = RapydScript.OutputStream({beautify: true});
-        ast.print(output);
-
-        // test that output performs correct JS operations
-//        sys.print(output);
-//            eval(output.toString());
-        var testcontent = "exports.run = function(){assert = require('assert');" + output.toString() + "};";
-        fs.writeFileSync(filepath + ".js", testcontent);
-        var testcase = require(filepath + ".js");
-        try {
-            testcase.run();
-        } catch (e) {
-            sys.print(file + ":\t" + e.stack + "\n\n");
-            fs.unlinkSync(filepath + ".js");
-            return;
-        }
-        sys.print(file + ":\ttest completed successfully\n");
-        fs.unlinkSync(filepath + ".js");
-    });
-    process.exit(0);
-}
-
-var BEAUTIFY = getOptions("p", true);
-var NO_MODULE_WRAPPER = getOptions("b", false);
-var NAMESPACE_IMPORTS = getOptions("n", false);
-var AUTO_BIND = getOptions("i", false);
-var OMIT_BASELIB = getOptions("m", false);
-
-var OUTPUT_OPTIONS = {
-    beautify: BEAUTIFY ? true : false,
-    private_scope: NO_MODULE_WRAPPER ? false : true,
-    namespace_imports: NAMESPACE_IMPORTS ? true : false,
-//    auto_bind: AUTO_BIND ? true : false,
-    omit_baselib: OMIT_BASELIB ? true : false
-};
-
-if (BEAUTIFY)
-    RapydScript.merge(OUTPUT_OPTIONS, BEAUTIFY);
-
-if (ARGS.comments) {
-    if (/^\//.test(ARGS.comments)) {
-        OUTPUT_OPTIONS.comments = new Function("return(" + ARGS.comments + ")")();
-    } else if (ARGS.comments == "all") {
-        OUTPUT_OPTIONS.comments = true;
-    } else {
-        OUTPUT_OPTIONS.comments = function(node, comment) {
-            var text = comment.value;
-            var type = comment.type;
-            if (type == "comment2") {
-                // multiline comment
-                return /@preserve|@license|@cc_on/i.test(text);
-            }
-        }
-    }
-}
-
-var files = ARGS._.slice();
-
-if (ARGS.self) {
-    if (files.length > 0) {
-        sys.error("WARN: Ignoring input files since --self was passed");
-    }
-    files = RapydScript.FILES;
-    if (!ARGS.wrap) ARGS.wrap = "RapydScript";
-    ARGS.export_all = true;
-}
-
-if (files.length == 0) {
-    files = [ "-" ];
-}
-
-if (files.filter(function(el){ return el == "-" }).length > 1) {
-    sys.error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
-    process.exit(1);
-}
-
-var STATS = {};
-var OUTPUT_FILE = ARGS.o;
-var TOPLEVEL = null;
-
-try {
-    var output = RapydScript.OutputStream(OUTPUT_OPTIONS);
-} catch(ex) {
-    if (ex instanceof RapydScript.DefaultsError) {
-        sys.error(ex.msg);
-        sys.error("Supported options:");
-        sys.error(sys.inspect(ex.defs));
-        process.exit(1);
-    }
-}
-
-async.eachLimit(files, 1, function (file, cb) {
-    read_whole_file(file, function (err, code) {
-        if (err) {
-            sys.error("ERROR: can't read file: " + file);
-            process.exit(1);
-        }
-//        if (ARGS.p != null) {
-//            file = file.replace(/^\/+/, "").split(/\/+/).slice(ARGS.p).join("/");
-//        }
-        time_it("parse", function(){
-            TOPLEVEL = RapydScript.parse(code, {
-                filename: file,
-                toplevel: TOPLEVEL,
-                readfile: fs.readFileSync,
-                basedir: path.dirname(file),
-//                auto_bind: AUTO_BIND ? true : false,
-                libdir: path.normalize(
-                    path.join(
-                        path.dirname(module.filename),
-                        "../src"
-                    )
-                )
-            });
-        });
-        cb();
-    });
-}, function () {
-    if (ARGS.wrap) {
-        TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
-    }
-
-    if (ARGS.enclose) {
-        var arg_parameter_list = ARGS.enclose;
-
-        if (!(arg_parameter_list instanceof Array)) {
-            arg_parameter_list = [arg_parameter_list];
-        }
-
-        TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list);
-    }
-
-    time_it("generate", function(){
-        TOPLEVEL.print(output);
-    });
-
-    output = output.get();
-
-    if (OUTPUT_FILE) {
-        fs.writeFileSync(OUTPUT_FILE, output, "utf8");
-    } else {
-        sys.print(output);
-        sys.error("\n");
-    }
-
-    if (ARGS.stats) {
-        sys.error(RapydScript.string_template("Timing information (compressed {count} files):", {
-            count: files.length
-        }));
-        for (var i in STATS) if (STATS.hasOwnProperty(i)) {
-            sys.error(RapydScript.string_template("- {name}: {time}s", {
-                name: i,
-                time: (STATS[i] / 1000).toFixed(3)
-            }));
-        }
-    }
-});
-
-/* -----[ functions ]----- */
-
-function normalize(o) {
-    for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
-        o[i.replace(/-/g, "_")] = o[i];
-        delete o[i];
-    }
-}
-
-function getOptions(x, constants) {
-    x = ARGS[x];
-    if (!x) return null;
-    var ret = {};
-    if (x !== true) {
-        var ast;
-        try {
-            ast = RapydScript.parse(x);
-        } catch(ex) {
-            if (ex instanceof RapydScript.JS_Parse_Error) {
-                sys.error("Error parsing arguments in: " + x);
-                process.exit(1);
-            }
-        }
-        ast.walk(new RapydScript.TreeWalker(function(node){
-            if (node instanceof RapydScript.AST_Toplevel) return; // descend
-            if (node instanceof RapydScript.AST_SimpleStatement) return; // descend
-            if (node instanceof RapydScript.AST_Seq) return; // descend
-            if (node instanceof RapydScript.AST_Assign) {
-                var name = node.left.print_to_string({ beautify: false }).replace(/-/g, "_");
-                var value = node.right;
-                if (constants)
-                    value = new Function("return (" + value.print_to_string() + ")")();
-                ret[name] = value;
-                return true;    // no descend
-            }
-            sys.error(node.TYPE)
-            sys.error("Error parsing arguments in: " + x);
-            process.exit(1);
-        }));
-    }
-    return ret;
-}
-
-function read_whole_file(filename, cb) {
-    if (filename == "-") {
-        var chunks = [];
-        process.stdin.setEncoding('utf-8');
-        process.stdin.on('data', function (chunk) {
-            chunks.push(chunk);
-        }).on('end', function () {
-            cb(null, chunks.join(""));
-        });
-        process.openStdin();
-    } else {
-        fs.readFile(filename, "utf-8", cb);
-    }
-}
-
-function time_it(name, cont) {
-    var t1 = new Date().getTime();
-    var ret = cont();
-    if (ARGS.stats) {
-        var spent = new Date().getTime() - t1;
-        if (STATS[name]) STATS[name] += spent;
-        else STATS[name] = spent;
-    }
-    return ret;
-}

File c1.js

-
-assert = require("assert");
-(function(){
-    function _$rapyd$_bind1(f) {
-        var r = f.bind.apply(f, Array.prototype.slice.call(arguments, 1));
-        r.bind = function() {
-            var args = Array.prototype.slice.call(arguments);
-            return Function.prototype.bind.apply(f, args);
-        }
-        return r;
-    }
-    function _$rapyd$_bind(fn, scope) {
-//        var r = fn.bind(scope);
-//        r.bind = function(){
-//            return Function.prototype.bind.call(fn, scope);
-//        };
-//        return r;
-//        if (!fn.hasOwnProperty('_orig')) {
-//            fn._orig = fn;
-//        }
-//        var r = fn._orig.bind(scope);
-//        r._orig = fn._orig;
-//        return r;
-        if (fn.hasOwnProperty('_orig')) {
-            fn = fn._orig;
-        }
-        var r = fn.bind(scope);
-        r._orig = fn;
-        return r;
-    }
-    function _$rapyd$_unbindAll(thisArg, rebind) {
-        for (var p in thisArg) {
-            if (thisArg[p] && thisArg[p].orig) {
-                if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
-                else thisArg[p] = thisArg[p].orig;
-            }
-        }
-    }
-    function hasattr(obj, name) {
-        return name in obj;
-    }
-    function getattr(obj, name) {
-        return obj[name];
-    }
-    function setattr(obj, name, value) {
-        obj[name] = value;
-    }
-    var blank, bob, joe, angela, bound, st, c, inc, m;
-    function Blank() {
-    }
-
-    blank = new Blank();
-
-    assert.ok(blank instanceof Blank);
-
-    function Human(name){
-        var self = this;
-        this.greet = _$rapyd$_bind(this.greet, this);
-        self.name = name;
-    };
-    Human.prototype.greet = function(){
-        var self = this;
-        return "Hello, I'm " + self.name;
-    };
-    Human.getTypicalWeight = function(){
-        return "150";
-    };
-
-    function Friend() {
-        console.log("-", arguments[0]);
-        this.greet = _$rapyd$_bind(this.greet, this);
-        console.log('b: ', this.name, "|", this.greet());
-        this.nickname = _$rapyd$_bind(this.nickname, this);
-        Human.prototype.constructor.apply(this, arguments);
-        this.greet = _$rapyd$_bind(this.greet, this);
-        console.log('a: ', this.name, "|", this.greet());
-    }
-    Friend.prototype = new Human("crap");
-    Friend.prototype.constructor = Friend;
-    Friend.prototype.greet = function(){
-        var self = this;
-        return "Yo, it's me, " + self.name;
-    };
-    Friend.prototype.nickname = function(name){
-        var self = this;
-        self.name = name;
-    };
-
-    function OldFriend(name, duration){
-        var self = this;
-        this.how_long = _$rapyd$_bind(this.how_long, this);
-        this.get_bound_method = _$rapyd$_bind(this.get_bound_method, this);
-        self.duration = duration;
-        console.log(name);
-        Friend.prototype.constructor.call(self, name);
-    };
-    OldFriend.prototype = new Friend("doh");
-    OldFriend.prototype.constructor = OldFriend;
-    OldFriend.prototype.how_long = function(){
-        var self = this;
-        return "I've known you for " + self.duration + " years";
-    };
-    OldFriend.prototype.get_bound_method = function(){
-        var self = this;
-        return self.how_long;
-    };
-
-    bob = new Human("Bob");
-
-    assert.equal(bob.greet(), "Hello, I'm Bob");
-
-    assert.equal(Human.prototype.greet.call(bob), "Hello, I'm Bob");
-
-    assert.equal(Human.getTypicalWeight(), "150");
-
-    joe = new Friend("Joe");
-
-    assert.equal(joe.greet(), "Yo, it's me, Joe");
-
-    assert.ok(joe instanceof Friend);
-
-    assert.ok(joe instanceof Human);
-
-    console.log('A');
-    angela = new OldFriend("Angela", 8);
-    console.log('B');
-
-    assert.equal(angela.greet(), "Yo, it's me, Angela");
-
-    assert.equal(angela.how_long(), "I've known you for 8 years");
-
-    bound = angela.get_bound_method();
-
-    assert.equal(bound(), angela.how_long());
-
-    angela.nickname("Angie");
-
-    assert.equal(angela.greet(), "Yo, it's me, Angie");
-
-    (function module() {
-        function Stranger() {
-            this.greet = _$rapyd$_bind(this.greet, this);
-            Human.prototype.constructor.apply(this, arguments);
-        }
-        Stranger.prototype = new Human();
-        Stranger.prototype.constructor = Stranger;
-        Stranger.prototype.greet = function(){
-            var self = this;
-            return Friend.prototype.greet.call(self);
-        };
-        dude = new Stranger("some guy");
-    })();
-
-    assert.equal(dude.greet(), "Yo, it's me, some guy");
-
-    assert.throws(function() {
-        new Friend("another friend");
-        Stranger("another guy");
-    }, /Stranger is not defined/);
-
-    assert.ok(hasattr(dude, "greet"));
-
-    assert.equal(getattr(dude, "greet")(), "Yo, it's me, some guy");
-
-    assert.equal(hasattr(dude, "stuff"), false);
-
-    setattr(dude, "stuff", true);
-
-    assert.ok(hasattr(dude, "stuff"));
-
-    st = new String("test");
-
-    assert.equal(st, "test");
-
-    assert.equal(st.toUpperCase(), "TEST");
-
-    assert.equal(String.prototype.toUpperCase.call(st), "TEST");
-
-    assert.equal(String.fromCharCode(65), "A");
-
-    function Counter(n){
-        var s = this;
-        if (typeof n === "undefined") n = 0;
-        this.getIncrementer = _$rapyd$_bind(this.getIncrementer, this);
-        s.count = n;
-    };
-    Counter.prototype.getIncrementer = function(){
-        var self = this;
-        return function() {
-            self.count += 1;
-        };
-    };
-
-    c = new Counter(5);
-
-    inc = c.getIncrementer();
-
-    inc();
-
-    assert.equal(c.count, 6);
-
-    function negate(fn) {
-        function wrapped() {
-            var args = [].slice.call(arguments, 0);
-            return -fn.apply(this, [].concat(args));
-        }
-        return wrapped;
-    }
-
-    function add_pi(cls) {
-        cls.prototype.pi = 3.14;
-        return cls;
-    }
-
-    
-
-    function Math() {
-        this.sum = _$rapyd$_bind(this.sum, this);
-        this.concatSum = _$rapyd$_bind(this.concatSum, this);
-        this.plus = _$rapyd$_bind(this.plus, this);
-    }
-    Math.prototype.sum = function(){
-        var s = this;
-        var args = [].slice.call(arguments, 0);
-        var ttl, ttl, i;
-        ttl = 0;
-        var _$rapyd$_Iter0 = args;
-        for (var _$rapyd$_Index0 = 0; _$rapyd$_Index0 < _$rapyd$_Iter0.length; _$rapyd$_Index0++) {
-            i = _$rapyd$_Iter0[_$rapyd$_Index0];
-            ttl += i;
-        }
-        return ttl;
-    };
-    Math.prototype.concatSum = function(){
-        var s = this;
-        var string = arguments[0];
-        var nums = [].slice.call(arguments, 1);
-        return string + s.sum.apply(s, [].concat(nums));
-    };
-    Math.prototype.plus = function(a, b){
-        var s = this;
-        return a + b;
-    };
-    Math.prototype.plus = negate(Math.prototype.plus);
-    Math = add_pi(Math);
-
-    m = new Math();
-
-    assert.equal(m.sum(1, 2, 3), 6);
-
-    assert.equal(m.sum.apply(m, [1].concat([ 2, 3 ])), 6);
-
-    assert.equal(m.concatSum("foo", 1, 2, 5), "foo8");
-
-    assert.equal(m.plus(2, 5), -7);
-
-    assert.equal(m.pi, 3.14);
-})();

File c2.js

-
-assert = require("assert");
-(function(){
-    function _$rapyd$_bind(f) {
-        var r = f.bind.apply(f, Array.prototype.slice.call(arguments, 1));
-        r.bind = function() {
-            var args = Array.prototype.slice.call(arguments);
-            return Function.prototype.bind.apply(f, args);
-        }
-        return r;
-    }
-    function _$rapyd$_unbindAll(thisArg, rebind) {
-        for (var p in thisArg) {
-            if (thisArg[p] && thisArg[p].orig) {
-                if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
-                else thisArg[p] = thisArg[p].orig;
-            }
-        }
-    }
-    function hasattr(obj, name) {
-        return name in obj;
-    }
-    function getattr(obj, name) {
-        return obj[name];
-    }
-    function setattr(obj, name, value) {
-        obj[name] = value;
-    }
-    var blank, bob, joe, angela, bound, st, c, inc, m;
-    function Blank() {
-    }
-
-    blank = new Blank();
-
-    assert.ok(blank instanceof Blank);
-
-    function Human(name){
-        var self = this;
-        this.greet = _$rapyd$_bind(this.greet, this);
-        self.name = name;
-    };
-    Human.prototype.greet = function(){
-        var self = this;
-        return "Hello, I'm " + self.name;
-    };
-    Human.getTypicalWeight = function(){
-        return "150";
-    };
-
-    function Friend() {
-        if (arguments[0] != "doh") {
-            this.greet = _$rapyd$_bind(this.greet, this);
-            this.nickname = _$rapyd$_bind(this.nickname, this);
-            Human.prototype.constructor.apply(this, arguments);
-        }
-    }
-    Friend.prototype = new Human();
-    Friend.prototype.constructor = Friend;
-    Friend.prototype.greet = function(){
-        var self = this;
-        return "Yo, it's me, " + self.name;
-    };
-    Friend.prototype.nickname = function(name){
-        var self = this;
-        self.name = name;
-    };
-
-    function OldFriend(name, duration){
-        if (arguments[0] != "doh") {
-            var self = this;
-            this.how_long = _$rapyd$_bind(this.how_long, this);
-            this.get_bound_method = _$rapyd$_bind(this.get_bound_method, this);
-            self.duration = duration;
-            Friend.prototype.constructor.call(self, name);
-        }
-    };
-    OldFriend.prototype = new Friend("doh");
-    OldFriend.prototype.constructor = OldFriend;
-    OldFriend.prototype.how_long = function(){
-        var self = this;
-        return "I've known you for " + self.duration + " years";
-    };
-    OldFriend.prototype.get_bound_method = function(){
-        var self = this;
-        return self.how_long;
-    };
-
-    bob = new Human("Bob");
-
-    assert.equal(bob.greet(), "Hello, I'm Bob");
-
-    assert.equal(Human.prototype.greet.call(bob), "Hello, I'm Bob");
-
-    assert.equal(Human.getTypicalWeight(), "150");
-
-    joe = new Friend("Joe");
-
-    assert.equal(joe.greet(), "Yo, it's me, Joe");
-
-    assert.ok(joe instanceof Friend);
-
-    assert.ok(joe instanceof Human);
-
-    angela = new OldFriend("Angela", 8);
-
-    assert.equal(angela.greet(), "Yo, it's me, Angela");
-
-    assert.equal(angela.how_long(), "I've known you for 8 years");
-
-    bound = angela.get_bound_method();
-
-    assert.equal(bound(), angela.how_long());
-
-    angela.nickname("Angie");
-
-    assert.equal(angela.greet(), "Yo, it's me, Angie");
-
-    (function module() {
-        function Stranger() {
-            this.greet = _$rapyd$_bind(this.greet, this);
-            Human.prototype.constructor.apply(this, arguments);
-        }
-        Stranger.prototype = new Human();
-        Stranger.prototype.constructor = Stranger;
-        Stranger.prototype.greet = function(){
-            var self = this;
-            return Friend.prototype.greet.call(self);
-        };
-        dude = new Stranger("some guy");
-    })();
-
-    assert.equal(dude.greet(), "Yo, it's me, some guy");
-
-    assert.throws(function() {
-        new Friend("another friend");
-        Stranger("another guy");
-    }, /Stranger is not defined/);
-
-    assert.ok(hasattr(dude, "greet"));
-
-    assert.equal(getattr(dude, "greet")(), "Yo, it's me, some guy");
-
-    assert.equal(hasattr(dude, "stuff"), false);
-
-    setattr(dude, "stuff", true);
-
-    assert.ok(hasattr(dude, "stuff"));
-
-    st = new String("test");
-
-    assert.equal(st, "test");
-
-    assert.equal(st.toUpperCase(), "TEST");
-
-    assert.equal(String.prototype.toUpperCase.call(st), "TEST");
-
-    assert.equal(String.fromCharCode(65), "A");
-
-    function Counter(n){
-        var s = this;
-        if (typeof n === "undefined") n = 0;
-        this.getIncrementer = _$rapyd$_bind(this.getIncrementer, this);
-        s.count = n;
-    };
-    Counter.prototype.getIncrementer = function(){
-        var self = this;
-        return function() {
-            self.count += 1;
-        };
-    };
-
-    c = new Counter(5);
-
-    inc = c.getIncrementer();
-
-    inc();
-
-    assert.equal(c.count, 6);
-
-    function negate(fn) {
-        function wrapped() {
-            var args = [].slice.call(arguments, 0);
-            return -fn.apply(this, [].concat(args));
-        }
-        return wrapped;
-    }
-
-    function add_pi(cls) {
-        cls.prototype.pi = 3.14;
-        return cls;
-    }
-
-    
-
-    function Math() {
-        this.sum = _$rapyd$_bind(this.sum, this);
-        this.concatSum = _$rapyd$_bind(this.concatSum, this);
-        this.plus = _$rapyd$_bind(this.plus, this);
-    }
-    Math.prototype.sum = function(){
-        var s = this;
-        var args = [].slice.call(arguments, 0);
-        var ttl, ttl, i;
-        ttl = 0;
-        var _$rapyd$_Iter0 = args;
-        for (var _$rapyd$_Index0 = 0; _$rapyd$_Index0 < _$rapyd$_Iter0.length; _$rapyd$_Index0++) {
-            i = _$rapyd$_Iter0[_$rapyd$_Index0];
-            ttl += i;
-        }
-        return ttl;
-    };
-    Math.prototype.concatSum = function(){
-        var s = this;
-        var string = arguments[0];
-        var nums = [].slice.call(arguments, 1);
-        return string + s.sum.apply(s, [].concat(nums));
-    };
-    Math.prototype.plus = function(a, b){
-        var s = this;
-        return a + b;
-    };
-    Math.prototype.plus = negate(Math.prototype.plus);
-    Math = add_pi(Math);
-
-    m = new Math();
-
-    assert.equal(m.sum(1, 2, 3), 6);
-
-    assert.equal(m.sum.apply(m, [1].concat([ 2, 3 ])), 6);
-
-    assert.equal(m.concatSum("foo", 1, 2, 5), "foo8");
-
-    assert.equal(m.plus(2, 5), -7);
-
-    assert.equal(m.pi, 3.14);
-})();

File c3.js

-(function(){
-    function _$rapyd$_bind(fn, thisArg) {
-        if (fn._orig) fn = fn._orig;
-        var ret = fn.bind(thisArg);
-        ret._orig = fn;
-        return ret;
-    }
-    function _$rapyd$_unbindAll(thisArg, rebind) {
-        for (var p in thisArg) {
-            if (thisArg[p] && thisArg[p].orig) {
-                if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
-                else thisArg[p] = thisArg[p].orig;
-            }
-        }
-    }
-    var a;
-        function Alpha(){
-        var self = this;
-        _$rapyd$_unbindAll(this, true);
-        this.getName = _$rapyd$_bind(this.getName, this);
-        self.name = "Alpha";
-    };
-    Alpha.prototype.getName = function(){
-        var self = this;
-        return self.name;
-    };
-
-    
-
-    
-
-    function testBravo() {
-        var b;
-        b = new Bravo();
-        assert.equal(b.getName(), "Bravo");
-        assert.equal(Bravo.prototype.getName.call(b), "Bravo");
-        Bravo.setName(b, "Charlie");
-        assert.equal(b.getName(), "Charlie");
-    }
-
-    a = new Alpha();
-
-    assert.equal(a.getName(), "Alpha");
-
-    assert.equal(Alpha.prototype.getName.call(a), "Alpha");
-
-    function Bravo(){
-        var self = this;
-        _$rapyd$_unbindAll(this, true);
-        self.name = "Bravo";
-    };
-    Bravo.prototype = new Alpha();
-    Bravo.prototype.constructor = Bravo;
-    Bravo.setName = function(obj, name){
-        obj.name = name;
-    };
-
-    testBravo();
-})();

File examples/asteroids/output/asteroids.js

 (function(){
-    function _$rapyd$_bind(fn, thisArg) {
-        if (fn._orig) fn = fn._orig;
-        var ret = fn.bind(thisArg);
-        ret._orig = fn;
-        return ret;
-    }
-    function _$rapyd$_rebindAll(thisArg, rebind) {
-        for (var p in thisArg) {
-            if (thisArg[p] && thisArg[p]._orig) {
-                if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
-                else thisArg[p] = thisArg[p]._orig;
-            }
-        }
+    function _$rapyd$_extends(child, parent) {
+        child.prototype = new parent;
+        child.prototype.constructor = child;
     }
     function enumerate(item) {
         var arr = [];
     }
     var JSON, str, NUM_ASTEROIDS, FPS, FRICTION, THRUST, ROTATE_SPEED_PER_SEC, ROTATE_SPEED, MAX_ASTEROID_SPEED, SHOT_LIFESPAN, SHOT_SPEED, SHOT_DELAY, ASTEROID_SIZES, SHOT_COLOR, ASTEROID_SIZE, CANVAS_DIM_X, CANVAS_DIM_Y;
     "\nView\n\nThe view contains the canvas and has all the logic for drawing the game state\non the screen. The original Pyjs code used multiple libraries here. Of the 3\nfiles, this one required the most changes to port to RapydScript.\n";
-        JSON = JSON || {};
+            JSON = JSON || {};
     if (!JSON.stringify) {
         
-	JSON.stringify = function(obj) {
-		var t = typeof (obj);
-		if (t != "object" || obj === null) {
-			// simple data type
-			if (t == "string")
-				obj = '"' + obj + '"';
-			if (t == "function")
-				return; // return undefined
-			else
-				return String(obj);
-		} else {
-			// recurse array or object
-			var n, v, json = []
-			var arr = (obj && obj.constructor == Array);
-			for (n in obj) {
-				v = obj[n];
-				t = typeof (v);
-				if (t != "function" && t != "undefined") {
-					if (t == "string")
-						v = '"' + v + '"';
-					else if ((t == "object" || t == "function") && v !== null)
-						v = JSON.stringify(v);
-					json.push((arr ? "" : '"' + n + '":') + String(v));
-				}
+    JSON.stringify = function(obj) {
+        var t = typeof (obj);
+        if (t != "object" || obj === null) {
+            // simple data type
+            if (t == "string")
+                obj = '"' + obj + '"';
+            if (t == "function")
+                return; // return undefined
+            else
+                return String(obj);
+        } else {
+            // recurse array or object
+            var n, v, json = []
+            var arr = (obj && obj.constructor == Array);
+            for (n in obj) {
+                v = obj[n];
+                t = typeof (v);
+                if (t != "function" && t != "undefined") {
+                    if (t == "string")
+                        v = '"' + v + '"';
+                    else if ((t == "object" || t == "function") && v !== null)
+                        v = JSON.stringify(v);
+                    json.push((arr ? "" : '"' + n + '":') + String(v));
+                }
+            }
+            return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
+        }
+    };
+    ;
+    }
+    str = JSON.stringify;
+    function IndexError(message){
+        var self = this;
+        if (typeof message === "undefined") message = "list index out of range";
+        self.name = "IndexError";
+        self.message = message;
+    };
+
+    _$rapyd$_extends(IndexError, Error);
+
+    function TypeError(message){
+        var self = this;
+        self.name = "TypeError";
+        self.message = message;
+    };
+
+    _$rapyd$_extends(TypeError, Error);
+
+    function ValueError(message){
+        var self = this;
+        self.name = "ValueError";
+        self.message = message;
+    };
+
+    _$rapyd$_extends(ValueError, Error);
+
+    function AssertionError(message){
+        var self = this;
+        if (typeof message === "undefined") message = "";
+        self.name = "AssertionError";
+        self.message = message;
+    };
+
+    _$rapyd$_extends(AssertionError, Error);
+
+    if (!Array.prototype.map) {
+        
+	Array.prototype.map = function(callback, thisArg) {
+		var T, A, k;
+		if (this == null) {
+			throw new TypeError(" this is null or not defined");
+		}
+		var O = Object(this);
+		var len = O.length >>> 0;
+		if ({}.toString.call(callback) != "[object Function]") {
+			throw new TypeError(callback + " is not a function");
+		}
+		if (thisArg) {
+			T = thisArg;
+		}
+		A = new Array(len);
+		for (var k = 0; k < len; k++) {
+			var kValue, mappedValue;
+			if (k in O) {
+				kValue = O[k];
+				mappedValue = callback.call(T, kValue);
+				A[k] = mappedValue;
 			}
-			return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
 		}
+		return A;
 	};
 	;
     }
-    str = JSON.stringify;
-    function ValueError(message){
-        var self = this;
-        _$rapyd$_rebindAll(this, true);
-        self.name = "ValueError";
-        self.message = message;
-    };
-    ValueError.prototype = new Error();
-    ValueError.prototype.constructor = ValueError;
-    _$rapyd$_rebindAll(ValueError.prototype);
+    function map(oper, arr) {
+        return list(arr.map(oper));
+    }
+    if (!Array.prototype.filter) {
+        
+	Array.prototype.filter = function(filterfun, thisArg) {
+		"use strict";
+		if (this == null) {
+			throw new TypeError(" this is null or not defined");
+		}
+		var O = Object(this);
+		var len = O.length >>> 0;
+		if ({}.toString.call(filterfun) != "[object Function]") {
+			throw new TypeError(filterfun + " is not a function");
+		}
+		if (thisArg) {
+			T = thisArg;
+		}
+		var A = [];
+		var thisp = arguments[1];
+		for (var k = 0; k < len; k++) {
+			if (k in O) {
+				var val = O[k]; // in case fun mutates this
+				if (filterfun.call(T, val))
+					A.push(val);
+			}
+		}
+		return A;
+	};
+	;
+    }
+    function filter(oper, arr) {
+        return list(arr.filter(oper));
+    }
+    function sum(arr, start) {
+        if (typeof start === "undefined") start = 0;
+        return arr.reduce(function(prev, cur) {
+            return prev + cur;
+        }, start);
+    }
+    function deep_eq(a, b) {
+        var i;
+        "\n    Equality comparison that works with all data types, returns true if structure and\n    contents of first object equal to those of second object\n\n    Arguments:\n        a: first object\n        b: second object\n    ";
+        if (a === b) {
+            return true;
+        }
+        if (a instanceof Array && b instanceof Array || a instanceof Object && b instanceof Object) {
+            if (a.constructor !== b.constructor || a.length !== b.length) {
+                return false;
+            }
+            var _$rapyd$_Iter0 = dict.keys(a);
+            for (var _$rapyd$_Index0 = 0; _$rapyd$_Index0 < _$rapyd$_Iter0.length; _$rapyd$_Index0++) {
+                i = _$rapyd$_Iter0[_$rapyd$_Index0];
+                if (b.hasOwnProperty(i)) {
+                    if (!deep_eq(a[i], b[i])) {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
     String.prototype.find = Array.prototype.indexOf;
     String.prototype.strip = String.prototype.trim;
     String.prototype.lstrip = String.prototype.trimLeft;
         if (typeof iterable === "undefined") iterable = [];
         var result, i;
         result = [];
-        var _$rapyd$_Iter0 = iterable;
-        for (var _$rapyd$_Index0 = 0; _$rapyd$_Index0 < _$rapyd$_Iter0.length; _$rapyd$_Index0++) {
-            i = _$rapyd$_Iter0[_$rapyd$_Index0];
+        var _$rapyd$_Iter1 = iterable;
+        for (var _$rapyd$_Index1 = 0; _$rapyd$_Index1 < _$rapyd$_Iter1.length; _$rapyd$_Index1++) {
+            i = _$rapyd$_Iter1[_$rapyd$_Index1];
             result.append(i);
         }
         return result;
     Array.prototype.copy = function() {
         return this.slice(0);
     };
-    if (!Array.prototype.map) {
-        
-	Array.prototype.map = function(callback, thisArg) {
-		var T, A, k;
-		if (this == null) {
-			throw new TypeError(" this is null or not defined");
-		}
-		var O = Object(this);
-		var len = O.length >>> 0;
-		if ({}.toString.call(callback) != "[object Function]") {
-			throw new TypeError(callback + " is not a function");
-		}
-		if (thisArg) {
-			T = thisArg;
-		}
-		A = new Array(len);
-		for (var k = 0; k < len; k++) {
-			var kValue, mappedValue;
-			if (k in O) {
-				kValue = O[k];
-				mappedValue = callback.call(T, kValue);
-				A[k] = mappedValue;
-			}
-		}
-		return A;
-	};
-	;
-    }
-    function map(oper, arr) {
-        return arr.map(oper);
-    }
-    if (!Array.prototype.filter) {
-        
-	Array.prototype.filter = function(filterfun, thisArg) {
-		"use strict";
-		if (this == null) {
-			throw new TypeError(" this is null or not defined");
-		}
-		var O = Object(this);
-		var len = O.length >>> 0;
-		if ({}.toString.call(filterfun) != "[object Function]") {
-			throw new TypeError(filterfun + " is not a function");
-		}
-		if (thisArg) {
-			T = thisArg;
-		}
-		var A = [];
-		var thisp = arguments[1];
-		for (var k = 0; k < len; k++) {
-			if (k in O) {
-				var val = O[k]; // in case fun mutates this
-				if (filterfun.call(T, val))
-					A.push(val);
-			}
-		}
-		return A;
-	};
-	;
-    }
-    function filter(oper, arr) {
-        return arr.filter(oper);
-    }
     function dict(iterable) {
         var result, key;
         result = {};
-        var _$rapyd$_Iter1 = iterable;
-        for (var _$rapyd$_Index1 = 0; _$rapyd$_Index1 < _$rapyd$_Iter1.length; _$rapyd$_Index1++) {
-            key = _$rapyd$_Iter1[_$rapyd$_Index1];
+        var _$rapyd$_Iter2 = iterable;
+        for (var _$rapyd$_Index2 = 0; _$rapyd$_Index2 < _$rapyd$_Iter2.length; _$rapyd$_Index2++) {
+            key = _$rapyd$_Iter2[_$rapyd$_Index2];
             result[key] = iterable[key];
         }
         return result;
             var keys;
             keys = [];
             
-		for (var x in hash) {
-			if (hash.hasOwnProperty(x)) {
-				keys.push(x);
-			}
-		}
-		;
+        for (var x in hash) {
+            if (hash.hasOwnProperty(x)) {
+                keys.push(x);
+            }
+        }
+        ;
             return keys;
         };
     } else {
     dict.values = function(hash) {
         var vals, key;
         vals = [];
-        var _$rapyd$_Iter2 = dict.keys(hash);
-        for (var _$rapyd$_Index2 = 0; _$rapyd$_Index2 < _$rapyd$_Iter2.length; _$rapyd$_Index2++) {
-            key = _$rapyd$_Iter2[_$rapyd$_Index2];
+        var _$rapyd$_Iter3 = dict.keys(hash);
+        for (var _$rapyd$_Index3 = 0; _$rapyd$_Index3 < _$rapyd$_Iter3.length; _$rapyd$_Index3++) {
+            key = _$rapyd$_Iter3[_$rapyd$_Index3];
             vals.append(hash[key]);
         }
         return vals;
     dict.items = function(hash) {
         var items, key;
         items = [];
-        var _$rapyd$_Iter3 = dict.keys(hash);
-        for (var _$rapyd$_Index3 = 0; _$rapyd$_Index3 < _$rapyd$_Iter3.length; _$rapyd$_Index3++) {
-            key = _$rapyd$_Iter3[_$rapyd$_Index3];
+        var _$rapyd$_Iter4 = dict.keys(hash);
+        for (var _$rapyd$_Index4 = 0; _$rapyd$_Index4 < _$rapyd$_Iter4.length; _$rapyd$_Index4++) {
+            key = _$rapyd$_Iter4[_$rapyd$_Index4];
             items.append([key, hash[key]]);
         }
         return items;
     dict.copy = dict;
     dict.clear = function(hash) {
         var key;
-        var _$rapyd$_Iter4 = dict.keys(hash);
-        for (var _$rapyd$_Index4 = 0; _$rapyd$_Index4 < _$rapyd$_Iter4.length; _$rapyd$_Index4++) {
-            key = _$rapyd$_Iter4[_$rapyd$_Index4];
+        var _$rapyd$_Iter5 = dict.keys(hash);
+        for (var _$rapyd$_Index5 = 0; _$rapyd$_Index5 < _$rapyd$_Iter5.length; _$rapyd$_Index5++) {
+            key = _$rapyd$_Iter5[_$rapyd$_Index5];
             delete hash[key];
         }
     };
         if (typeof x === "undefined") x = null;
         if (typeof y === "undefined") y = null;
         if (typeof size === "undefined") size = 0;
-        _$rapyd$_rebindAll(this, true);
-        this.update_dim = _$rapyd$_bind(this.update_dim, this);
-        this.move = _$rapyd$_bind(this.move, this);
         self.model = model;
         if (x === null || y === null) {
             self.x = model.x / 2;
         self.radius2 = self.radius * self.radius;
         self.scale = self.radius / ASTEROID_SIZE * 2;
     };
+
+
     Asteroid.prototype.update_dim = function update_dim(pos, d_dim, max_dim){
         var self = this;
         pos += d_dim;
         }
         return [pos, d_dim];
     };
+
     Asteroid.prototype.move = function move(){
         var self = this;
-        var undefined;
+        var _$rapyd$_Unpack;
         _$rapyd$_Unpack = self.update_dim(self.x, self.dx, self.model.x);
         self.x = _$rapyd$_Unpack[0];
         self.dx = _$rapyd$_Unpack[1];
         self.dy = _$rapyd$_Unpack[1];
         self.rot += self.rotspeed;
     };
+
     function Shot(model, ship){
         var self = this;
-        _$rapyd$_rebindAll(this, true);
-        this.move = _$rapyd$_bind(this.move, this);
         self.model = model;
         self.x = ship.x;
         self.y = ship.y;
         self.direction = ship.rot;
         self.lifespan = SHOT_LIFESPAN;
     };
+
+
     Shot.prototype.move = function move(){
         var self = this;
-        var i, a;
+        var _$rapyd$_Unpack, i, a;
         self.lifespan -= 1;
         if (self.lifespan <= 0) {
             return false;
         }
         self.x = self.x + self.dx + SHOT_SPEED * Math.sin(self.direction);
         self.y = self.y + self.dy - SHOT_SPEED * Math.cos(self.direction);
-        var _$rapyd$_Iter5 = enumerate(self.model.asteroids);
-        for (var _$rapyd$_Index5 = 0; _$rapyd$_Index5 < _$rapyd$_Iter5.length; _$rapyd$_Index5++) {
-            _$rapyd$_Unpack = _$rapyd$_Iter5[_$rapyd$_Index5];
+        var _$rapyd$_Iter6 = enumerate(self.model.asteroids);
+        for (var _$rapyd$_Index6 = 0; _$rapyd$_Index6 < _$rapyd$_Iter6.length; _$rapyd$_Index6++) {
+            _$rapyd$_Unpack = _$rapyd$_Iter6[_$rapyd$_Index6];
             i = _$rapyd$_Unpack[0];
             a = _$rapyd$_Unpack[1];
             if (distsq(self.x, self.y, a.x, a.y) < a.radius2) {
         }
         return true;
     };
+
     function Ship(cx, cy){
         var self = this;
-        _$rapyd$_rebindAll(this, true);
-        this.rotate_ship = _$rapyd$_bind(this.rotate_ship, this);
-        this.thrust = _$rapyd$_bind(this.thrust, this);
-        this.friction = _$rapyd$_bind(this.friction, this);
-        this.move = _$rapyd$_bind(this.move, this);
-        this.reset = _$rapyd$_bind(this.reset, this);
         self.cx = cx;
         self.cy = cy;
         self.reset();
     };
+
+
     Ship.prototype.rotate_ship = function rotate_ship(drot){
         var self = this;
         self.rot += drot;
             drot -= 2 * Math.PI;
         }
     };
+
     Ship.prototype.thrust = function thrust(){
         var self = this;
         self.dx += THRUST * Math.sin(self.rot);
         self.dy -= THRUST * Math.cos(self.rot);
     };
+
     Ship.prototype.friction = function friction(){
         var self = this;
         var direction;
             self.dy -= FRICTION * Math.cos(direction);
         }
     };
+
     Ship.prototype.move = function move(){
         var self = this;
         self.shot_delay -= 1;
             self.y += self.cy;
         }
     };
+
     Ship.prototype.reset = function reset(){
         var self = this;
         self.x = self.cx / 2;
         self.rot = 0;
         self.shot_delay = 0;
     };
+
     function Model(x, y){
         var self = this;
-        _$rapyd$_rebindAll(this, true);
-        this.start_game = _$rapyd$_bind(this.start_game, this);
-        this.update = _$rapyd$_bind(this.update, this);
-        this.start_next_level = _$rapyd$_bind(this.start_next_level, this);
-        this.destroyShip = _$rapyd$_bind(this.destroyShip, this);
-        this.reset = _$rapyd$_bind(this.reset, this);
-        this.trigger_fire = _$rapyd$_bind(this.trigger_fire, this);
-        this.split_asteroid = _$rapyd$_bind(this.split_asteroid, this);
         self.x = x;
         self.y = y;
         self.num_asteroids = NUM_ASTEROIDS;
         self.ship = new Ship(x, y);
     };
+
+
     Model.prototype.start_game = function start_game(view){
         var self = this;
         self.view = view;
     };
+
     Model.prototype.update = function update(){
         var self = this;
         var a, i;
-        var _$rapyd$_Iter6 = self.asteroids;
-        for (var _$rapyd$_Index6 = 0; _$rapyd$_Index6 < _$rapyd$_Iter6.length; _$rapyd$_Index6++) {
-            a = _$rapyd$_Iter6[_$rapyd$_Index6];
+        var _$rapyd$_Iter7 = self.asteroids;
+        for (var _$rapyd$_Index7 = 0; _$rapyd$_Index7 < _$rapyd$_Iter7.length; _$rapyd$_Index7++) {
+            a = _$rapyd$_Iter7[_$rapyd$_Index7];
             a.move();
             if (distsq(self.ship.x, self.ship.y, a.x, a.y) < a.radius2) {
                 self.destroyShip();
                 return;
             }
         }
-        var _$rapyd$_Iter7 = reversed(range(len(self.shots)));
-        for (var _$rapyd$_Index7 = 0; _$rapyd$_Index7 < _$rapyd$_Iter7.length; _$rapyd$_Index7++) {
-            i = _$rapyd$_Iter7[_$rapyd$_Index7];
+        var _$rapyd$_Iter8 = reversed(range(len(self.shots)));
+        for (var _$rapyd$_Index8 = 0; _$rapyd$_Index8 < _$rapyd$_Iter8.length; _$rapyd$_Index8++) {
+            i = _$rapyd$_Iter8[_$rapyd$_Index8];
             if (!self.shots[i].move()) {
                 self.shots.pop(i);
                 if (len(self.asteroids) == 0) {
         self.ship.move();
         self.view.draw();
     };
+
     Model.prototype.start_next_level = function start_next_level(){
         var self = this;
         self.num_asteroids += 1;
         self.reset();
     };
+
     Model.prototype.destroyShip = function destroyShip(){
         var self = this;
         self.num_asteroids = NUM_ASTEROIDS;
         self.reset();
     };
+
     Model.prototype.reset = function reset(){
         var self = this;
         self.shots = [];
         })();
         self.ship.reset();
     };
+
     Model.prototype.trigger_fire = function trigger_fire(){
         var self = this;
         if (self.ship.shot_delay > 0) {
             self.ship.shot_delay = SHOT_DELAY;
         }
     };
+
     Model.prototype.split_asteroid = function split_asteroid(i){
         var self = this;
         var a, j;
         }
         self.asteroids.pop(i);
     };
+
         "\nController\n\nThe controller runs the game and modifies the Model. This required very few changes\nto port from Pyjs.\n";
     
     function Controller(model){
         var self = this;
-        _$rapyd$_rebindAll(this, true);
-        this.start_game = _$rapyd$_bind(this.start_game, this);
-        this.update = _$rapyd$_bind(this.update, this);
-        this.keyboard_updates = _$rapyd$_bind(this.keyboard_updates, this);
         self.model = model;
         self.key_up = false;
         self.key_down = false;
         self.key_right = false;
         self.key_fire = false;
     };
+
+
     Controller.prototype.start_game = function start_game(view){
         var self = this;
         self.view = view;
             self.update();
         }, 1e3 / FPS);
     };
+
     Controller.prototype.update = function update(){
         var self = this;
         self.keyboard_updates();
         self.model.update();
     };
+
     Controller.prototype.keyboard_updates = function keyboard_updates(){
         var self = this;
         var ship, drot;
             self.model.trigger_fire();
         }
     };
+
     SHOT_COLOR = "#fff";
     ASTEROID_SIZE = 180;
     CANVAS_DIM_X = 800;
     CANVAS_DIM_Y = 600;
     function View(w, h, canvas){
         var self = this;
-        _$rapyd$_rebindAll(this, true);
-        this.setKey = _$rapyd$_bind(this.setKey, this);
-        this.draw_asteroid = _$rapyd$_bind(this.draw_asteroid, this);
-        this.draw_shot = _$rapyd$_bind(this.draw_shot, this);
-        this.draw_ship = _$rapyd$_bind(this.draw_ship, this);
-        this.draw = _$rapyd$_bind(this.draw, this);
         var imgsrcs, i;
         self.width = w;
         self.height = h;
             };
         }
     };
+
+
     View.prototype.setKey = function setKey(k, set){
         var self = this;
         if (k == 38) {
             self.controller.key_fire = set;
         }
     };
+
     View.prototype.draw_asteroid = function draw_asteroid(ctx, asteroid){
         var self = this;
         ctx.save();
         ctx.drawImage(self.img[2], -(ASTEROID_SIZE / 2), -(ASTEROID_SIZE / 2));
         ctx.restore();
     };
+
     View.prototype.draw_shot = function draw_shot(ctx, shot){
         var self = this;
         ctx.fillStyle = SHOT_COLOR;
         ctx.fillRect(Math.ceil(shot.x - 1), Math.ceil(shot.y - 1), 3, 3);
     };
+
     View.prototype.draw_ship = function draw_ship(ctx, ship){
         var self = this;
         var img;
         ctx.drawImage(img, -15, -12);
         ctx.restore();
     };
+
     View.prototype.draw = function draw(){
         var self = this;
         var ctx, i;
         }
         self.draw_ship(ctx, self.model.ship);
     };
+
     window.runGame = function() {
         var canvas, view;
         canvas = document.getElementById("myCanvas");

File examples/paint/output/paint.html

 				License: Creative Commons: Attribution + Noncommerial + ShareAlike
 			</p>
 			<p>
-This app is meant both, as a showcase of RapydScript and RapydML potential as well as a means to showcase clean and DRY coding conventions using RapydScript. 
+This app is meant both, as a showcase of RapydScript and RapydML potential as well as clean and DRY coding conventions using RapydScript. Note that many tools have alternatives for right-click. For example, using right-click for line-drawing tool creates an intermediate control point, turning the line into a bezier spline. 
 			</p>
 		</div>
 	</body>

File examples/paint/output/paint.js

 (function(){
-    function _$rapyd$_bind(fn, thisArg) {
-        if (fn._orig) fn = fn._orig;
-        var ret = fn.bind(thisArg);
-        ret._orig = fn;
-        return ret;
-    }
-    function _$rapyd$_rebindAll(thisArg, rebind) {
-        for (var p in thisArg) {
-            if (thisArg[p] && thisArg[p]._orig) {
-                if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
-                else thisArg[p] = thisArg[p]._orig;
-            }
-        }
+    function _$rapyd$_extends(child, parent) {
+        child.prototype = new parent;
+        child.prototype.constructor = child;
     }
     function len(obj) {
         if (obj instanceof Array || typeof obj === "string") return obj.length;
     RCLICK = 3;
     function Drawing(){
         var self = this;
-        _$rapyd$_rebindAll(this, true);
-        this.undo = _$rapyd$_bind(this.undo, this);
-        this.redo = _$rapyd$_bind(this.redo, this);
-        this.setMode = _$rapyd$_bind(this.setMode, this);
-        this.setStroke = _$rapyd$_bind(this.setStroke, this);
-        this.setFill = _$rapyd$_bind(this.setFill, this);
-        this.setWidth = _$rapyd$_bind(this.setWidth, this);
-        this.clear = _$rapyd$_bind(this.clear, this);
-        this.exportDwg = _$rapyd$_bind(this.exportDwg, this);
-        this.invert = _$rapyd$_bind(this.invert, this);
-        this.redFilter = _$rapyd$_bind(this.redFilter, this);
-        this.greenFilter = _$rapyd$_bind(this.greenFilter, this);
-        this.blueFilter = _$rapyd$_bind(this.blueFilter, this);
-        this.darken = _$rapyd$_bind(this.darken, this);
-        this.lighten = _$rapyd$_bind(this.lighten, this);
         var ctx, $tmpCanvas, tmpCanvas, tmpCtx, canvasWidth, canvasHeight, dragging, points, selection, lastPt, transparent_bg, getXY, normalize, ellipse, drawSpline, sample, matchStartColor, eachPixel, clear, onMouseDown, onMouseMove, onMouseUp, onMouseLeave;
         self._canvas = $("#perm-dwg").get(0);
         self._ctx = ctx = self._canvas.getContext("2d");
             return [x, y, width, height];
         };
         ellipse = function(context, x, y, width, height) {
-            var ctrX, ctrY, circ, scaleX, scaleY;
+            var _$rapyd$_Unpack, ctrX, ctrY, circ, scaleX, scaleY;
             _$rapyd$_Unpack = normalize(x, y, width, height);
             x = _$rapyd$_Unpack[0];
             y = _$rapyd$_Unpack[1];
             context.clearRect(0, 0, canvasWidth, canvasHeight);
         };
         onMouseDown = function(event) {
-            var pixelStack, colorLayer, startPixel, locX, locY, swatchPixel, newPos, x, y, reachLeft, reachRight, pixelPos, tmp, data, merge;
+            var pixelStack, colorLayer, startPixel, _$rapyd$_Unpack, locX, locY, swatchPixel, newPos, x, y, reachLeft, reachRight, pixelPos, tmp, data, merge;
             event.preventDefault();
             dragging = true;
             _$rapyd$_Unpack = getXY(this, event);
             }
         };
         onMouseMove = function(event) {
-            var point, x, y;
+            var _$rapyd$_Unpack, point, x, y;
             if (self._mode == LINE && len(points)) {
                 _$rapyd$_Unpack = getXY(this, event);
                 x = _$rapyd$_Unpack[0];
             }
         };
         onMouseUp = function(event) {
-            var sx, sy, width, height, x, y;
+            var _$rapyd$_Unpack, sx, sy, width, height, x, y;
             if (_$rapyd$_in(self._mode, [ RECT, ELLIPSE ])) {
                 _$rapyd$_Unpack = getXY(this, event);
                 x = _$rapyd$_Unpack[0];
         $tmpCanvas.mouseleave(onMouseLeave);
         self._ctx.lineJoin = tmpCtx.lineJoin = self._ctx.lineCap = tmpCtx.lineCap = "round";
     };
+
+
     Drawing.prototype.undo = function undo(){
         var self = this;
         var state;
             self._ctx.putImageData(state, 0, 0);
         }
     };
+
     Drawing.prototype.redo = function redo(){
         var self = this;
         var state;
             self._ctx.putImageData(state, 0, 0);
         }
     };
+
     Drawing.prototype.setMode = function setMode(mode){
         var self = this;
         self._mode = mode;
     };
+
     Drawing.prototype.setStroke = function setStroke(style){
         var self = this;
         self._brushColor = style;
     };
+
     Drawing.prototype.setFill = function setFill(style){
         var self = this;
         self._fillColor = style;
     };
+
     Drawing.prototype.setWidth = function setWidth(value){
         var self = this;
         self._lineWidth = value;
     };
+
     Drawing.prototype.clear = function clear(){
         var self = this;
         self._clear(self._ctx);
     };
+
     Drawing.prototype.exportDwg = function exportDwg(){
         var self = this;
         return self._canvas.toDataURL();
     };
+
     Drawing.prototype.invert = function invert(){
         var self = this;
         var invert;
         };
         self._filter(invert);
     };
+
     Drawing.prototype.redFilter = function redFilter(){
         var self = this;
         var remove;
         };
         self._filter(remove);
     };
+
     Drawing.prototype.greenFilter = function greenFilter(){
         var self = this;
         var remove;
         };
         self._filter(remove);
     };
+
     Drawing.prototype.blueFilter = function blueFilter(){
         var self = this;
         var remove;
         };
         self._filter(remove);
     };
+
     Drawing.prototype.darken = function darken(){
         var self = this;
         var darken;
         };
         self._filter(darken);
     };
+
     Drawing.prototype.lighten = function lighten(){
         var self = this;
         var lighten;
         };
         self._filter(lighten);
     };
+
     function ColorSwatch(){
         var self = this;
-        _$rapyd$_rebindAll(this, true);
         var fg, bg;
         fg = $("<div></div>").width(36).height(36).css({
             "position": "absolute",
         bg = fg.clone();
         $("#color-swatch");
     };
+
+
     function main() {
-        var dwg, onChange, $brushWidget, triggerChange, $tools, makeMode, $stroke, $fill, setStroke, setFill, $colorPickers, $colorPicker, makeHandler, makeReset, $swatch, idtag, resetid, callback, popupUnder, $menus, makeMenu, hideMenus, $about;
+        var dwg, onChange, $brushWidget, triggerChange, $tools, makeMode, $stroke, $fill, setStroke, setFill, $colorPickers, $colorPicker, makeHandler, makeReset, _$rapyd$_Unpack, $swatch, idtag, resetid, callback, popupUnder, $menus, makeMenu, hideMenus, $about;
         dwg = new Drawing();
         onChange = function() {
             dwg.setWidth($(this).val());

File examples/paint/paint.pyml

 				'License: Creative Commons: Attribution + Noncommerial + ShareAlike'
 			text:
 				This app is meant both, as a showcase of RapydScript and RapydML potential as well
-				as a means to showcase clean and DRY coding conventions using RapydScript.
-			
+				as clean and DRY coding conventions using RapydScript. Note that many tools have
+				alternatives for right-click. For example, using right-click for line-drawing tool
+				creates an intermediate control point, turning the line into a bezier spline.

File examples/rapydray/output/rapydray.js

 (function(){
-    function _$rapyd$_bind(fn, thisArg) {
-        if (fn._orig) fn = fn._orig;
-        var ret = fn.bind(thisArg);
-        ret._orig = fn;
-        return ret;
-    }
-    function _$rapyd$_rebindAll(thisArg, rebind) {
-        for (var p in thisArg) {
-            if (thisArg[p] && thisArg[p]._orig) {
-                if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
-                else thisArg[p] = thisArg[p]._orig;
-            }
-        }
+    function _$rapyd$_extends(child, parent) {
+        child.prototype = new parent;
+        child.prototype.constructor = child;
     }
     function range(start, stop, step) {
         if (arguments.length <= 1) {