Browse Source

formatting

Herbert Vojčík 9 years ago
parent
commit
2e881451e5

+ 97 - 97
external/amber-cli/support/amberc-cli.js

@@ -9,7 +9,7 @@ var parameters = process.argv.slice(2);
 
 // check if at least one parameter was passed to the script
 if (1 > parameters.length) {
-	print_usage_and_exit();
+    print_usage_and_exit();
 }
 
 
@@ -29,107 +29,107 @@ compiler.main(configuration);
  * Followed by check_for_closure_compiler() and then collect_files().
  */
 function handle_options(optionsArray) {
-	var programName = [];
-	var currentItem = optionsArray.shift();
-	var defaults = amberc.createDefaultConfiguration();
+    var programName = [];
+    var currentItem = optionsArray.shift();
+    var defaults = amberc.createDefaultConfiguration();
 
-	while(undefined !== currentItem) {
-		switch(currentItem) {
-			case '-l':
-				defaults.load.push.apply(defaults.load, optionsArray.shift().split(','));
-				break;
-			case '-L':
-				defaults.jsLibraryDirs.push.apply(defaults.jsLibraryDirs, optionsArray.shift().split(','));
-				break;
-			case '-g':
-				defaults.jsGlobals.push.apply(defaults.jsGlobals, optionsArray.shift().split(','));
-				break;
-			case '-n':
-				defaults.amd_namespace = optionsArray.shift();
-				break;
-			case '-D':
-				defaults.output_dir = optionsArray.shift();
-				break;
-			case '-d':
-				amber_dir = path.normalize(optionsArray.shift());
-				break;
-			case '-v':
-				defaults.verbose = true;
-				break;
-			case '-h':
-			case '--help':
-			case '?':
-			case '-?':
-				print_usage_and_exit();
-				break;
-			default:
-				defaults.stFiles.push(currentItem);
-				break;
-		}
-		currentItem = optionsArray.shift();
-	}
+    while (undefined !== currentItem) {
+        switch (currentItem) {
+            case '-l':
+                defaults.load.push.apply(defaults.load, optionsArray.shift().split(','));
+                break;
+            case '-L':
+                defaults.jsLibraryDirs.push.apply(defaults.jsLibraryDirs, optionsArray.shift().split(','));
+                break;
+            case '-g':
+                defaults.jsGlobals.push.apply(defaults.jsGlobals, optionsArray.shift().split(','));
+                break;
+            case '-n':
+                defaults.amd_namespace = optionsArray.shift();
+                break;
+            case '-D':
+                defaults.output_dir = optionsArray.shift();
+                break;
+            case '-d':
+                amber_dir = path.normalize(optionsArray.shift());
+                break;
+            case '-v':
+                defaults.verbose = true;
+                break;
+            case '-h':
+            case '--help':
+            case '?':
+            case '-?':
+                print_usage_and_exit();
+                break;
+            default:
+                defaults.stFiles.push(currentItem);
+                break;
+        }
+        currentItem = optionsArray.shift();
+    }
 
-	if(1 < programName.length) {
-		throw new Error('More than one name for ProgramName given: ' + programName);
-	} else {
-		defaults.program = programName[0];
-	}
-	return defaults;
+    if (1 < programName.length) {
+        throw new Error('More than one name for ProgramName given: ' + programName);
+    } else {
+        defaults.program = programName[0];
+    }
+    return defaults;
 }
 
 
 // print available flags
 function print_usage_and_exit() {
-	var usage = [
-		'Usage: amberc [-L libdir1,libdir2...] [-l lib1,lib2...] [-g jsGlobal1,jsGlobal2]',
-		'          [-n namespace] [-D output_dir] [-v] file1 file2 ...',
-		'',
-		'   amberc compiles Amber files.',
-		'   Files are compiled into .js files before concatenation.',
-		'   If not found we look in $AMBER/src/',
-		'',
-		'     NOTE: Each .st file is currently considered to be a fileout of a single class',
-		'     category of the same name as the file!',
-		'',
-		'  -l library1,library2',
-		'     Add listed JavaScript libraries in listed order.',
-		'     Libraries are not separated by spaces or end with .js.',
-		'',
-		'  -L directory1,directory2',
-		'     Add listed directories to the library search path.',
-		'     The order of processing is:',
-		'     1. current directory',
-		'     2. directories specified by -L',
-		'     3. $AMBER',
-		'',
-		'  -g jsGlobal1,jsGlobal2',
-		'     Comma separated list of JS global variable names.',
-		'     The names are added to a list containing "window", "document" and others.',
-		'',
-		'  -n amd_namespace',
-		'     Export packages with <amd_namespace> as the require.js namespace.',
-		'     Default value is "amber_core".',
-		'',
-		'  -v',
-		'     Produce a more verbose output.',
-		'',
-		'  -D',
-		'     Specifies the output directory for all generated .js files.',
-		'     The hierarchy of the input files is not maintaned.',
-		'     If this option is omitted all generated .js files are placed next to their input files',
-		'',
-		'  -d',
-		'     Specifies the alternate directory to look for Amber files.',
-		'     If not specified, the version embedded in CLI is used.',
-		'',
-		'     Example invocations:',
-		'',
-		'     Just compile Kernel-Objects.st to Kernel-Objects.js:',
-		'',
-		'        amberc Kernel-Objects.st',
-	];
-	usage.forEach(function (line) {
-		console.log(line);
-	});
-	process.exit();
+    var usage = [
+        'Usage: amberc [-L libdir1,libdir2...] [-l lib1,lib2...] [-g jsGlobal1,jsGlobal2]',
+        '          [-n namespace] [-D output_dir] [-v] file1 file2 ...',
+        '',
+        '   amberc compiles Amber files.',
+        '   Files are compiled into .js files before concatenation.',
+        '   If not found we look in $AMBER/src/',
+        '',
+        '     NOTE: Each .st file is currently considered to be a fileout of a single class',
+        '     category of the same name as the file!',
+        '',
+        '  -l library1,library2',
+        '     Add listed JavaScript libraries in listed order.',
+        '     Libraries are not separated by spaces or end with .js.',
+        '',
+        '  -L directory1,directory2',
+        '     Add listed directories to the library search path.',
+        '     The order of processing is:',
+        '     1. current directory',
+        '     2. directories specified by -L',
+        '     3. $AMBER',
+        '',
+        '  -g jsGlobal1,jsGlobal2',
+        '     Comma separated list of JS global variable names.',
+        '     The names are added to a list containing "window", "document" and others.',
+        '',
+        '  -n amd_namespace',
+        '     Export packages with <amd_namespace> as the require.js namespace.',
+        '     Default value is "amber_core".',
+        '',
+        '  -v',
+        '     Produce a more verbose output.',
+        '',
+        '  -D',
+        '     Specifies the output directory for all generated .js files.',
+        '     The hierarchy of the input files is not maintaned.',
+        '     If this option is omitted all generated .js files are placed next to their input files',
+        '',
+        '  -d',
+        '     Specifies the alternate directory to look for Amber files.',
+        '     If not specified, the version embedded in CLI is used.',
+        '',
+        '     Example invocations:',
+        '',
+        '     Just compile Kernel-Objects.st to Kernel-Objects.js:',
+        '',
+        '        amberc Kernel-Objects.st',
+    ];
+    usage.forEach(function (line) {
+        console.log(line);
+    });
+    process.exit();
 }

+ 343 - 340
external/amber-dev/lib/amberc.js

@@ -22,80 +22,80 @@
  * // The variable concatenation contains the concatenated result
  * // which can either be stored in a file or interpreted with eval().
  */
-function createConcatenator () {
-	return {
-		elements: [],
-		ids: [],
-		add: function () {
-			this.elements.push.apply(this.elements, arguments);
-		},
-		addId: function () {
-			this.ids.push.apply(this.ids, arguments);
-		},
-		forEach: function () {
-			this.elements.forEach.apply(this.elements, arguments);
-		},
-		start: function () {
-			this.add(
-				'var define = (' + require('amdefine') + ')(null, function (id) { throw new Error("Dependency not found: " +  id); }), requirejs = define.require;',
-				'define("amber/browser-compatibility", [], {});'
-			);
-		},
-		finish: function (realWork) {
-			this.add(
-				'define("app", ["' + this.ids.join('","') + '"], function (boot) {',
-				'boot.api.initialize();',
-				realWork,
-				'});',
-				'requirejs(["app"]);'
-			);
-		},
-		toString: function () {
-			return this.elements.join('\n');
-		}
-	};
+function createConcatenator() {
+    return {
+        elements: [],
+        ids: [],
+        add: function () {
+            this.elements.push.apply(this.elements, arguments);
+        },
+        addId: function () {
+            this.ids.push.apply(this.ids, arguments);
+        },
+        forEach: function () {
+            this.elements.forEach.apply(this.elements, arguments);
+        },
+        start: function () {
+            this.add(
+                'var define = (' + require('amdefine') + ')(null, function (id) { throw new Error("Dependency not found: " +  id); }), requirejs = define.require;',
+                'define("amber/browser-compatibility", [], {});'
+            );
+        },
+        finish: function (realWork) {
+            this.add(
+                'define("app", ["' + this.ids.join('","') + '"], function (boot) {',
+                'boot.api.initialize();',
+                realWork,
+                '});',
+                'requirejs(["app"]);'
+            );
+        },
+        toString: function () {
+            return this.elements.join('\n');
+        }
+    };
 }
 
 
 var path = require('path'),
-	fs = require('fs'),
-	Promise = require('es6-promise').Promise;
+    fs = require('fs'),
+    Promise = require('es6-promise').Promise;
 
 /**
  * AmberCompiler constructor function.
  * amber_dir: points to the location of an amber installation
  */
 function AmberCompiler(amber_dir) {
-	if (undefined === amber_dir || !fs.existsSync(amber_dir)) {
-		throw new Error('amber_dir needs to be a valid directory');
-	}
-
-	this.amber_dir = amber_dir;
-	// Important: in next list, boot MUST be first
-	this.kernel_libraries = ['boot', 'Kernel-Objects', 'Kernel-Classes', 'Kernel-Methods',
-							'Kernel-Collections', 'Kernel-Infrastructure', 'Kernel-Exceptions', 'Kernel-Announcements',
-							'Platform-Services', 'Platform-Node'];
-	this.compiler_libraries = this.kernel_libraries.concat(['parser', 'Platform-ImportExport', 'Compiler-Exceptions',
-							'Compiler-Core', 'Compiler-AST', 'Compiler-Exceptions', 'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic']);
+    if (undefined === amber_dir || !fs.existsSync(amber_dir)) {
+        throw new Error('amber_dir needs to be a valid directory');
+    }
+
+    this.amber_dir = amber_dir;
+    // Important: in next list, boot MUST be first
+    this.kernel_libraries = ['boot', 'Kernel-Objects', 'Kernel-Classes', 'Kernel-Methods',
+        'Kernel-Collections', 'Kernel-Infrastructure', 'Kernel-Exceptions', 'Kernel-Announcements',
+        'Platform-Services', 'Platform-Node'];
+    this.compiler_libraries = this.kernel_libraries.concat(['parser', 'Platform-ImportExport', 'Compiler-Exceptions',
+        'Compiler-Core', 'Compiler-AST', 'Compiler-Exceptions', 'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic']);
 }
 
 
 /**
  * Default values.
  */
-var createDefaultConfiguration = function() {
-	return {
-		'load': [],
-		'stFiles': [],
-		'jsGlobals': [],
-		'amd_namespace': 'amber_core',
-		'libraries': [],
-		'jsLibraryDirs': [],
-		'compile': [],
-		'compiled': [],
-		'output_dir': undefined,
-		'verbose': false
-	};
+var createDefaultConfiguration = function () {
+    return {
+        'load': [],
+        'stFiles': [],
+        'jsGlobals': [],
+        'amd_namespace': 'amber_core',
+        'libraries': [],
+        'jsLibraryDirs': [],
+        'compile': [],
+        'compiled': [],
+        'output_dir': undefined,
+        'verbose': false
+    };
 };
 
 
@@ -104,46 +104,47 @@ var createDefaultConfiguration = function() {
  * If check_configuration_ok() returns successfully
  * the configuration is used to trigger the following compilation steps.
  */
-AmberCompiler.prototype.main = function(configuration, finished_callback) {
-	console.time('Compile Time');
-
-	if (configuration.amd_namespace.length === 0) {
-		configuration.amd_namespace = 'amber_core';
-	}
-
-	if (undefined !== configuration.jsLibraryDirs) {
-		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'src'));
-		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'support'));
-	}
-
-	console.ambercLog = console.log;
-	if (false === configuration.verbose) {
-		console.log = function() {};
-	}
-
-	// the evaluated compiler will be stored in this variable (see create_compiler)
-	configuration.core = {};
-	configuration.globals = {};
-	configuration.kernel_libraries = this.kernel_libraries;
-	configuration.compiler_libraries = this.compiler_libraries;
-	configuration.amber_dir = this.amber_dir;
-
-	check_configuration(configuration)
-	.then(collect_st_files)
-	.then(resolve_kernel)
-	.then(create_compiler)
-	.then(compile)
-	.then(category_export)
-	.then(verify)
-	.then(function () {
-		console.timeEnd('Compile Time');
-	}, function(error) {
-		console.error(error);
-	})
-	.then(function () {
-		console.log = console.ambercLog;
-		finished_callback && finished_callback();
-	});
+AmberCompiler.prototype.main = function (configuration, finished_callback) {
+    console.time('Compile Time');
+
+    if (configuration.amd_namespace.length === 0) {
+        configuration.amd_namespace = 'amber_core';
+    }
+
+    if (undefined !== configuration.jsLibraryDirs) {
+        configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'src'));
+        configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'support'));
+    }
+
+    console.ambercLog = console.log;
+    if (false === configuration.verbose) {
+        console.log = function () {
+        };
+    }
+
+    // the evaluated compiler will be stored in this variable (see create_compiler)
+    configuration.core = {};
+    configuration.globals = {};
+    configuration.kernel_libraries = this.kernel_libraries;
+    configuration.compiler_libraries = this.compiler_libraries;
+    configuration.amber_dir = this.amber_dir;
+
+    check_configuration(configuration)
+        .then(collect_st_files)
+        .then(resolve_kernel)
+        .then(create_compiler)
+        .then(compile)
+        .then(category_export)
+        .then(verify)
+        .then(function () {
+            console.timeEnd('Compile Time');
+        }, function (error) {
+            console.error(error);
+        })
+        .then(function () {
+            console.log = console.ambercLog;
+            finished_callback && finished_callback();
+        });
 };
 
 
@@ -152,17 +153,17 @@ AmberCompiler.prototype.main = function(configuration, finished_callback) {
  * Returns a Promise which resolves into the configuration object.
  */
 function check_configuration(configuration) {
-	return new Promise(function(resolve, reject) {
-		if (undefined === configuration) {
-			reject(Error('AmberCompiler.check_configuration_ok(): missing configuration object'));
-		}
+    return new Promise(function (resolve, reject) {
+        if (undefined === configuration) {
+            reject(Error('AmberCompiler.check_configuration_ok(): missing configuration object'));
+        }
 
-		if (0 === configuration.stFiles.length) {
-			reject(Error('AmberCompiler.check_configuration_ok(): no files to compile specified in configuration object'));
-		}
+        if (0 === configuration.stFiles.length) {
+            reject(Error('AmberCompiler.check_configuration_ok(): no files to compile specified in configuration object'));
+        }
 
-		resolve(configuration);
-	});
+        resolve(configuration);
+    });
 };
 
 
@@ -177,9 +178,9 @@ function check_configuration(configuration) {
  * @param configuration the main amberc configuration object
  */
 function resolve_js(filename, configuration) {
-	var baseName = path.basename(filename, '.js');
-	var jsFile = baseName + '.js';
-	return resolve_file(jsFile, configuration.jsLibraryDirs);
+    var baseName = path.basename(filename, '.js');
+    var jsFile = baseName + '.js';
+    return resolve_file(jsFile, configuration.jsLibraryDirs);
 };
 
 
@@ -192,7 +193,7 @@ function resolve_js(filename, configuration) {
  * @param configuration the main amberc configuration object
  */
 function resolve_st(filename, configuration) {
-	return resolve_file(filename, [configuration.amber_dir]);
+    return resolve_file(filename, [configuration.amber_dir]);
 };
 
 
@@ -202,26 +203,26 @@ function resolve_st(filename, configuration) {
  * then check in each of the directories specified in parameter searchDirectories.
  */
 function resolve_file(filename, searchDirectories) {
-	return new Promise(function(resolve, reject) {
-		console.log('Resolving: ' + filename);
-		fs.exists(filename, function(exists) {
-			if (exists) {
-				resolve(filename);
-			} else {
-				var alternativeFile = '';
-				// check for filename in any of the given searchDirectories
-				var found = searchDirectories.some(function(directory) {
-					alternativeFile = path.join(directory, filename);
-					return fs.existsSync(alternativeFile);
-				});
-				if (found) {
-					resolve(alternativeFile);
-				} else {
-					reject(Error('File not found: ' + alternativeFile));
-				}
-			}
-		});
-	});
+    return new Promise(function (resolve, reject) {
+        console.log('Resolving: ' + filename);
+        fs.exists(filename, function (exists) {
+            if (exists) {
+                resolve(filename);
+            } else {
+                var alternativeFile = '';
+                // check for filename in any of the given searchDirectories
+                var found = searchDirectories.some(function (directory) {
+                    alternativeFile = path.join(directory, filename);
+                    return fs.existsSync(alternativeFile);
+                });
+                if (found) {
+                    resolve(alternativeFile);
+                } else {
+                    reject(Error('File not found: ' + alternativeFile));
+                }
+            }
+        });
+    });
 };
 
 
@@ -230,15 +231,15 @@ function resolve_file(filename, searchDirectories) {
  * Returns a Promise which resolves into the configuration object.
  */
 function collect_st_files(configuration) {
-	return Promise.all(
-		configuration.stFiles.map(function(stFile) {
-			return resolve_st(stFile, configuration);
-		})
-	)
-	.then(function(data) {
-		configuration.compile = configuration.compile.concat(data);
-		return configuration;
-	});
+    return Promise.all(
+        configuration.stFiles.map(function (stFile) {
+            return resolve_st(stFile, configuration);
+        })
+    )
+        .then(function (data) {
+            configuration.compile = configuration.compile.concat(data);
+            return configuration;
+        });
 }
 
 
@@ -247,33 +248,33 @@ function collect_st_files(configuration) {
  * Returns a Promise which resolves into the configuration object.
  */
 function resolve_kernel(configuration) {
-	var kernel_files = configuration.kernel_libraries.concat(configuration.load);
-	return Promise.all(
-		kernel_files.map(function(file) {
-			return resolve_js(file, configuration);
-		})
-	)
-	.then(function(data) {
-		// boot.js and Kernel files need to be used first
-		// otherwise the global objects 'core' and 'globals' are undefined
-		configuration.libraries = data.concat(configuration.libraries);
-		return configuration;
-	});
+    var kernel_files = configuration.kernel_libraries.concat(configuration.load);
+    return Promise.all(
+        kernel_files.map(function (file) {
+            return resolve_js(file, configuration);
+        })
+    )
+        .then(function (data) {
+            // boot.js and Kernel files need to be used first
+            // otherwise the global objects 'core' and 'globals' are undefined
+            configuration.libraries = data.concat(configuration.libraries);
+            return configuration;
+        });
 }
 
 
 function withImportsExcluded(data) {
-	var srcLines = data.split(/\r\n|\r|\n/), dstLines = [], doCopy = true;
-	srcLines.forEach(function (line) {
-		if (line.replace(/\s/g, '') === '//>>excludeStart("imports",pragmas.excludeImports);') {
-			doCopy = false;
-		} else if (line.replace(/\s/g, '') === '//>>excludeEnd("imports");') {
-			doCopy = true;
-		} else if (doCopy) {
-			dstLines.push(line);
-		}
-	});
-	return dstLines.join('\n');
+    var srcLines = data.split(/\r\n|\r|\n/), dstLines = [], doCopy = true;
+    srcLines.forEach(function (line) {
+        if (line.replace(/\s/g, '') === '//>>excludeStart("imports",pragmas.excludeImports);') {
+            doCopy = false;
+        } else if (line.replace(/\s/g, '') === '//>>excludeEnd("imports");') {
+            doCopy = true;
+        } else if (doCopy) {
+            dstLines.push(line);
+        }
+    });
+    return dstLines.join('\n');
 }
 
 /**
@@ -282,97 +283,99 @@ function withImportsExcluded(data) {
  * Returns a Promise object which resolves into the configuration object.
  */
 function create_compiler(configuration) {
-	var compiler_files = configuration.compiler_libraries;
-	var include_files = configuration.load;
-	var builder;
-	return Promise.all(
-		compiler_files.map(function(file) {
-			return resolve_js(file, configuration);
-		})
-	)
-	.then(function(compilerFilesArray) {
-		return Promise.all(
-			compilerFilesArray.map(function(file) {
-				return new Promise(function(resolve, reject) {
-					console.log('Loading file: ' + file);
-					fs.readFile(file, function(err, data) {
-						if (err)
-							reject(err);
-						else
-							resolve(data);
-					});
-				});
-			})
-		)
-	})
-	.then(function(files) {
-		builder = createConcatenator();
-		builder.add('(function() {');
-		builder.start();
-
-		files.forEach(function(data) {
-			// data is an array where index 0 is the error code and index 1 contains the data
-			builder.add(data);
-			// matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
-			var match = ('' + data).match(/(^|\n)define\("([^"]*)"/);
-			if (match) {
-				builder.addId(match[2]);
-			}
-		});
-	})
-	.then(function () { return Promise.all(
-		include_files.map(function(file) {
-			return resolve_js(file, configuration);
-		})
-	); })
-	.then(function(includeFilesArray) {
-		return Promise.all(
-			includeFilesArray.map(function(file) {
-				return new Promise(function(resolve, reject) {
-					console.log('Loading library file: ' + file);
-					fs.readFile(file, function(err, data) {
-						if (err)
-							reject(err);
-						else
-							resolve(data);
-					});
-				});
-			})
-		)
-	})
-	.then(function(files) {
-		var loadIds = [];
-		files.forEach(function(data) {
-			data = data + '';
-			// matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
-			var match = data.match(/^define\("([^"]*)"/);
-			if (match) {
-				loadIds.push(match[1]);
-				data = withImportsExcluded(data);
-			}
-			builder.add(data);
-		});
-
-		// store the generated smalltalk env in configuration.{core,globals}
-		builder.finish('configuration.core = boot.api; configuration.globals = boot.globals;');
-		loadIds.forEach(function (id) {
-			builder.add('requirejs("' + id + '");');
-		});
-		builder.add('})();');
-
-		eval(builder.toString());
-
-		console.log('Compiler loaded');
-
-		configuration.globals.ErrorHandler._register_(configuration.globals.RethrowErrorHandler._new());
-
-		if(0 !== configuration.jsGlobals.length) {
-			var jsGlobalVariables = configuration.core.globalJsVariables;
-			jsGlobalVariables.push.apply(jsGlobalVariables, configuration.jsGlobals);
-		}
-
-		return configuration;
-	});
+    var compiler_files = configuration.compiler_libraries;
+    var include_files = configuration.load;
+    var builder;
+    return Promise.all(
+        compiler_files.map(function (file) {
+            return resolve_js(file, configuration);
+        })
+    )
+        .then(function (compilerFilesArray) {
+            return Promise.all(
+                compilerFilesArray.map(function (file) {
+                    return new Promise(function (resolve, reject) {
+                        console.log('Loading file: ' + file);
+                        fs.readFile(file, function (err, data) {
+                            if (err)
+                                reject(err);
+                            else
+                                resolve(data);
+                        });
+                    });
+                })
+            )
+        })
+        .then(function (files) {
+            builder = createConcatenator();
+            builder.add('(function() {');
+            builder.start();
+
+            files.forEach(function (data) {
+                // data is an array where index 0 is the error code and index 1 contains the data
+                builder.add(data);
+                // matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
+                var match = ('' + data).match(/(^|\n)define\("([^"]*)"/);
+                if (match) {
+                    builder.addId(match[2]);
+                }
+            });
+        })
+        .then(function () {
+            return Promise.all(
+                include_files.map(function (file) {
+                    return resolve_js(file, configuration);
+                })
+            );
+        })
+        .then(function (includeFilesArray) {
+            return Promise.all(
+                includeFilesArray.map(function (file) {
+                    return new Promise(function (resolve, reject) {
+                        console.log('Loading library file: ' + file);
+                        fs.readFile(file, function (err, data) {
+                            if (err)
+                                reject(err);
+                            else
+                                resolve(data);
+                        });
+                    });
+                })
+            )
+        })
+        .then(function (files) {
+            var loadIds = [];
+            files.forEach(function (data) {
+                data = data + '';
+                // matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
+                var match = data.match(/^define\("([^"]*)"/);
+                if (match) {
+                    loadIds.push(match[1]);
+                    data = withImportsExcluded(data);
+                }
+                builder.add(data);
+            });
+
+            // store the generated smalltalk env in configuration.{core,globals}
+            builder.finish('configuration.core = boot.api; configuration.globals = boot.globals;');
+            loadIds.forEach(function (id) {
+                builder.add('requirejs("' + id + '");');
+            });
+            builder.add('})();');
+
+            eval(builder.toString());
+
+            console.log('Compiler loaded');
+
+            configuration.globals.ErrorHandler._register_(configuration.globals.RethrowErrorHandler._new());
+
+            if (0 !== configuration.jsGlobals.length) {
+                var jsGlobalVariables = configuration.core.globalJsVariables;
+                jsGlobalVariables.push.apply(jsGlobalVariables, configuration.jsGlobals);
+            }
+
+            return configuration;
+        });
 }
 
 
@@ -381,48 +384,48 @@ function create_compiler(configuration) {
  * Returns a Promise object that resolves into the configuration object.
  */
 function compile(configuration) {
-	// return function which does the actual work
-	// and use the compile function to reference the configuration object
-	return Promise.all(
-		configuration.compile.map(function(stFile) {
-			return new Promise(function(resolve, reject) {
-				if (/\.st/.test(stFile)) {
-					console.ambercLog('Reading: ' + stFile);
-					fs.readFile(stFile, 'utf8', function(err, data) {
-						if (!err)
-							resolve(data);
-						else
-							reject(Error('Could not read: ' + stFile));
-					});
-				}
-			});
-		})
-	)
-	.then(function(fileContents) {
-		console.log('Compiling collected .st files');
-		// import/compile content of .st files
-		return Promise.all(
-			fileContents.map(function(code) {
-				return new Promise(function(resolve, reject) {
-					var importer = configuration.globals.Importer._new();
-					try {
-						importer._import_(code._stream());
-						resolve(true);
-					} catch (ex) {
-						reject(Error("Compiler error in section:\n" +
-							importer._lastSection() + "\n\n" +
-							"while processing chunk:\n" +
-							importer._lastChunk() + "\n\n" +
-							(ex._messageText && ex._messageText() || ex.message || ex))
-						);
-					}
-				});
-			})
-		);
-	})
-	.then(function () {
-		return configuration;
-	});
+    // return function which does the actual work
+    // and use the compile function to reference the configuration object
+    return Promise.all(
+        configuration.compile.map(function (stFile) {
+            return new Promise(function (resolve, reject) {
+                if (/\.st/.test(stFile)) {
+                    console.ambercLog('Reading: ' + stFile);
+                    fs.readFile(stFile, 'utf8', function (err, data) {
+                        if (!err)
+                            resolve(data);
+                        else
+                            reject(Error('Could not read: ' + stFile));
+                    });
+                }
+            });
+        })
+    )
+        .then(function (fileContents) {
+            console.log('Compiling collected .st files');
+            // import/compile content of .st files
+            return Promise.all(
+                fileContents.map(function (code) {
+                    return new Promise(function (resolve, reject) {
+                        var importer = configuration.globals.Importer._new();
+                        try {
+                            importer._import_(code._stream());
+                            resolve(true);
+                        } catch (ex) {
+                            reject(Error("Compiler error in section:\n" +
+                                    importer._lastSection() + "\n\n" +
+                                    "while processing chunk:\n" +
+                                    importer._lastChunk() + "\n\n" +
+                                    (ex._messageText && ex._messageText() || ex.message || ex))
+                            );
+                        }
+                    });
+                })
+            );
+        })
+        .then(function () {
+            return configuration;
+        });
 }
 
 
@@ -431,34 +434,34 @@ function compile(configuration) {
  * Returns a Promise() that resolves into the configuration object.
  */
 function category_export(configuration) {
-	return Promise.all(
-		configuration.compile.map(function(stFile) {
-			return new Promise(function(resolve, reject) {
-				var category = path.basename(stFile, '.st');
-				var jsFilePath = configuration.output_dir;
-				if (undefined === jsFilePath) {
-					jsFilePath = path.dirname(stFile);
-				}
-				var jsFile = category + '.js';
-				jsFile = path.join(jsFilePath, jsFile);
-				configuration.compiled.push(jsFile);
-				var smalltalkGlobals = configuration.globals;
-				var packageObject = smalltalkGlobals.Package._named_(category);
-				packageObject._transport()._namespace_(configuration.amd_namespace);
-				fs.writeFile(jsFile, smalltalkGlobals.String._streamContents_(function (stream) {
-					smalltalkGlobals.AmdExporter._new()._exportPackage_on_(packageObject, stream);
-				}), function(err) {
-					if (err)
-						reject(err);
-					else
-						resolve(true);
-				});
-			});
-		})
-	)
-	.then(function() {
-		return configuration;
-	});
+    return Promise.all(
+        configuration.compile.map(function (stFile) {
+            return new Promise(function (resolve, reject) {
+                var category = path.basename(stFile, '.st');
+                var jsFilePath = configuration.output_dir;
+                if (undefined === jsFilePath) {
+                    jsFilePath = path.dirname(stFile);
+                }
+                var jsFile = category + '.js';
+                jsFile = path.join(jsFilePath, jsFile);
+                configuration.compiled.push(jsFile);
+                var smalltalkGlobals = configuration.globals;
+                var packageObject = smalltalkGlobals.Package._named_(category);
+                packageObject._transport()._namespace_(configuration.amd_namespace);
+                fs.writeFile(jsFile, smalltalkGlobals.String._streamContents_(function (stream) {
+                    smalltalkGlobals.AmdExporter._new()._exportPackage_on_(packageObject, stream);
+                }), function (err) {
+                    if (err)
+                        reject(err);
+                    else
+                        resolve(true);
+                });
+            });
+        })
+    )
+        .then(function () {
+            return configuration;
+        });
 }
 
 
@@ -467,22 +470,22 @@ function category_export(configuration) {
  * Returns a Promise() that resolves into the configuration object.
  */
 function verify(configuration) {
-	console.log('Verifying if all .st files were compiled');
-	return Promise.all(
-		configuration.compiled.map(function(file) {
-			return new Promise(function(resolve, reject) {
-				fs.exists(file, function(exists) {
-					if (exists)
-						resolve(true);
-					else
-						reject(Error('Compilation failed of: ' + file));
-				});
-			});
-		})
-	)
-	.then(function() {
-		return configuration;
-	});
+    console.log('Verifying if all .st files were compiled');
+    return Promise.all(
+        configuration.compiled.map(function (file) {
+            return new Promise(function (resolve, reject) {
+                fs.exists(file, function (exists) {
+                    if (exists)
+                        resolve(true);
+                    else
+                        reject(Error('Compilation failed of: ' + file));
+                });
+            });
+        })
+    )
+        .then(function () {
+            return configuration;
+        });
 }
 
 

+ 58 - 58
external/amber-dev/tasks/grunt-amberc.js

@@ -1,10 +1,10 @@
-module.exports = function(grunt) {
+module.exports = function (grunt) {
 
-  var path = require('path');
-  var fs = require('fs');
-  var amberc = require('../lib/amberc.js');
+    var path = require('path');
+    var fs = require('fs');
+    var amberc = require('../lib/amberc.js');
 
-  /**
+    /**
      A full example entry for a Gruntfile.js is available below.
      Please note that the verbose level is either specified globally
      or on a target specific level.
@@ -34,67 +34,67 @@ module.exports = function(grunt) {
        },
      },
 
-   */
-  grunt.registerMultiTask('amberc', 'Compile Smalltalk files with the amberc compiler', function() {
-    // mark task as async task
-    var done = this.async();
+     */
+    grunt.registerMultiTask('amberc', 'Compile Smalltalk files with the amberc compiler', function () {
+        // mark task as async task
+        var done = this.async();
 
-    var options = this.options({
-      amber_dir: undefined,
-      library_dirs: [],
-      verbose: grunt.option('verbose') || false
-    });
-    this.data.verbose = options.verbose;
-    this.data.library_dirs = options.library_dirs;
+        var options = this.options({
+            amber_dir: undefined,
+            library_dirs: [],
+            verbose: grunt.option('verbose') || false
+        });
+        this.data.verbose = options.verbose;
+        this.data.library_dirs = options.library_dirs;
 
-    // mark required properties
-    this.requiresConfig('amberc.options.amber_dir');
-    // raise error on missing source files
-    if (this.filesSrc.length === 0) {
-        grunt.fail.fatal('No source files to compile or link.');
-    }
+        // mark required properties
+        this.requiresConfig('amberc.options.amber_dir');
+        // raise error on missing source files
+        if (this.filesSrc.length === 0) {
+            grunt.fail.fatal('No source files to compile or link.');
+        }
 
-    // create and initialize amberc
-    var compiler = new amberc.Compiler(grunt.config('amberc.options.amber_dir'));
+        // create and initialize amberc
+        var compiler = new amberc.Compiler(grunt.config('amberc.options.amber_dir'));
 
-    // generate the amberc configuration out of the given target properties
-    var configuration = generateCompilerConfiguration(this.data, this.filesSrc);
+        // generate the amberc configuration out of the given target properties
+        var configuration = generateCompilerConfiguration(this.data, this.filesSrc);
 
-    // run the compiler and call the async callback once finished
-    var self = this;
-    compiler.main(configuration, function(){
-      // signal that task has finished
-      done();
+        // run the compiler and call the async callback once finished
+        var self = this;
+        compiler.main(configuration, function () {
+            // signal that task has finished
+            done();
+        });
     });
-  });
 
 
-  function generateCompilerConfiguration(data, sourceFiles) {
-    var configuration = amberc.createDefaultConfiguration();
-    var parameters = [];
+    function generateCompilerConfiguration(data, sourceFiles) {
+        var configuration = amberc.createDefaultConfiguration();
+        var parameters = [];
 
-    var libraries = data.libraries;
-    if (undefined !== libraries) {
-      configuration.load = libraries;
-    }
-    var library_dirs = data.library_dirs;
-    if (undefined !== library_dirs) {
-      configuration.jsLibraryDirs = library_dirs;
-    }
-    if (undefined !== sourceFiles) {
-      configuration.stFiles = sourceFiles;
-    }
-    var amdNamespace = data.amd_namespace;
-    if (undefined !== amdNamespace) {
-      configuration.amd_namespace = amdNamespace;
-    }
-    if (undefined !== data.output_dir) {
-      configuration.output_dir = data.output_dir;
-    }
-    if (undefined !== data.jsGlobals) {
-      configuration.jsGlobals.push.apply(configuration.jsGlobals, data.jsGlobals);
+        var libraries = data.libraries;
+        if (undefined !== libraries) {
+            configuration.load = libraries;
+        }
+        var library_dirs = data.library_dirs;
+        if (undefined !== library_dirs) {
+            configuration.jsLibraryDirs = library_dirs;
+        }
+        if (undefined !== sourceFiles) {
+            configuration.stFiles = sourceFiles;
+        }
+        var amdNamespace = data.amd_namespace;
+        if (undefined !== amdNamespace) {
+            configuration.amd_namespace = amdNamespace;
+        }
+        if (undefined !== data.output_dir) {
+            configuration.output_dir = data.output_dir;
+        }
+        if (undefined !== data.jsGlobals) {
+            configuration.jsGlobals.push.apply(configuration.jsGlobals, data.jsGlobals);
+        }
+        configuration.verbose = data.verbose;
+        return configuration;
     }
-    configuration.verbose = data.verbose;
-    return configuration;
-  }
 };

+ 1155 - 1099
support/boot.js

@@ -39,1104 +39,1160 @@
 
 //jshint eqnull:true
 
-define("amber/boot", [ 'require', './browser-compatibility' ], function (require) {
-
-	/* Reconfigurable micro composition system, https://github.com/amber-smalltalk/brikz */
-
-	function Brikz(api, apiKey, initKey) {
-		var brikz = this, backup = {};
-		apiKey = apiKey || 'exports';
-		initKey = initKey || '__init__';
-
-		function mixin(src, target, what) {
-			for (var keys = Object.keys(what||src), l=keys.length, i=0; i<l; ++i) {
-				if (src == null) { target[keys[i]] = undefined; } else {
-					var value = src[keys[i]];
-					if (typeof value !== "undefined") { target[keys[i]] = value; }
-				}
-			}
-			return target;
-		}
-
-		var d={value: null, enumerable: false, configurable: true, writable: true};
-		Object.defineProperties(this, { ensure: d, rebuild: d });
-		var exclude = mixin(this, {});
-
-		this.rebuild = function () {
-			Object.keys(backup).forEach(function (key) {
-				mixin(null, api, (backup[key]||0)[apiKey]||{});
-			});
-			var oapi = mixin(api, {}), order = [], chk = {};
-			brikz.ensure = function(key) {
-				if (key in exclude) { return null; }
-				var b = brikz[key], bak = backup[key];
-				mixin(null, api, api);
-				while (typeof b === "function") { b = new b(brikz, api, bak); }
-				if (b && !chk[key]) { chk[key]=true; order.push(b); }
-				if (b && !b[apiKey]) { b[apiKey] = mixin(api, {}); }
-				brikz[key] = b;
-				return b;
-			};
-			Object.keys(brikz).forEach(function (key) { brikz.ensure(key); });
-			brikz.ensure = null;
-			mixin(oapi, mixin(null, api, api));
-			order.forEach(function(brik) { mixin(brik[apiKey] || {}, api); });
-			order.forEach(function(brik) { if (brik[initKey]) brik[initKey](); });
-			backup = mixin(brikz, {});
-		};
-	}
-
-	/* Brikz end */
-
-	function inherits(child, parent) {
-		child.prototype = Object.create(parent.prototype, {
-			constructor: { value: child,
-						   enumerable: false, configurable: true, writable: true }
-		});
-		return child;
-	}
-
-	var globals = {};
-	globals.SmalltalkSettings = {};
-	var api = {};
-	var brikz = new Brikz(api);
-
-	function RootBrik(brikz, st) {
-
-		/* Smalltalk foundational objects */
-
-		/* SmalltalkRoot is the hidden root of the Amber hierarchy.
-		 All objects including `Object` inherit from SmalltalkRoot */
-		function SmalltalkRoot() {}
-		function SmalltalkProtoObject() {}
-		inherits(SmalltalkProtoObject, SmalltalkRoot);
-		function SmalltalkObject() {}
-		inherits(SmalltalkObject, SmalltalkProtoObject);
-		function SmalltalkNil() {}
-		inherits(SmalltalkNil, SmalltalkObject);
-
-		this.Object = SmalltalkObject;
-		this.nil = new SmalltalkNil();
-
-		// Adds an `isNil` property to the `nil` object.  When sending
-		// nil objects from one environment to another, doing
-		// `anObject == nil` (in JavaScript) does not always answer
-		// true as the referenced nil object might come from the other
-		// environment.
-		Object.defineProperty(this.nil, 'isNil', {
-			value: true,
-			enumerable: false, configurable: false, writable: false
-		});
-
-		// Hidden root class of the system.
-		this.rootAsClass = {fn: SmalltalkRoot};
-
-		this.__init__ = function () {
-			st.addPackage("Kernel-Objects");
-			st.wrapClassName("ProtoObject", "Kernel-Objects", SmalltalkProtoObject, undefined, false);
-			st.wrapClassName("Object", "Kernel-Objects", SmalltalkObject, globals.ProtoObject, false);
-			st.wrapClassName("UndefinedObject", "Kernel-Objects", SmalltalkNil, globals.Object, false);
-		};
-	}
-
-	function OrganizeBrik(brikz, st) {
-
-		brikz.ensure("augments");
-		var SmalltalkObject = brikz.ensure("root").Object;
-
-		function SmalltalkOrganizer () {}
-		function SmalltalkPackageOrganizer () {
-			this.elements = [];
-		}
-		function SmalltalkClassOrganizer () {
-			this.elements = [];
-		}
-
-		inherits(SmalltalkOrganizer, SmalltalkObject);
-		inherits(SmalltalkPackageOrganizer, SmalltalkOrganizer);
-		inherits(SmalltalkClassOrganizer, SmalltalkOrganizer);
-
-		this.__init__ = function () {
-			st.addPackage("Kernel-Infrastructure");
-			st.wrapClassName("Organizer", "Kernel-Infrastructure", SmalltalkOrganizer, globals.Object, false);
-			st.wrapClassName("PackageOrganizer", "Kernel-Infrastructure", SmalltalkPackageOrganizer, globals.Organizer, false);
-			st.wrapClassName("ClassOrganizer", "Kernel-Infrastructure", SmalltalkClassOrganizer, globals.Organizer, false);
-		};
-
-		this.setupClassOrganization = function (klass) {
-			klass.organization = new SmalltalkClassOrganizer();
-			klass.organization.theClass = klass;
-		};
-
-		this.setupPackageOrganization = function (pkg) {
-			pkg.organization = new SmalltalkPackageOrganizer();
-		};
-
-		this.addOrganizationElement = function (owner, element) {
-			owner.organization.elements.addElement(element);
-		};
-
-		this.removeOrganizationElement = function (owner, element) {
-			owner.organization.elements.removeElement(element);
-		};
-	}
-
-	function DNUBrik(brikz, st) {
-
-		brikz.ensure("selectorConversion");
-		brikz.ensure("messageSend");
-		var manip = brikz.ensure("manipulation");
-		var rootAsClass = brikz.ensure("root").rootAsClass;
-
-		/* Method not implemented handlers */
-
-		var methods = [], methodDict = Object.create(null);
-		this.selectors = [];
-		this.jsSelectors = [];
-
-		this.make = function (stSelector, targetClasses) {
-			var method = methodDict[stSelector];
-			if(method) return;
-			var jsSelector = st.st2js(stSelector);
-			this.selectors.push(stSelector);
-			this.jsSelectors.push(jsSelector);
-			method = {jsSelector: jsSelector, fn: createHandler(stSelector)};
-			methodDict[stSelector] = method;
-			methods.push(method);
-			manip.installMethod(method, rootAsClass);
-			targetClasses.forEach(function (target) {
-				manip.installMethod(method, target);
-			});
-			return method;
-		};
-
-		/* Dnu handler method */
-
-		function createHandler(stSelector) {
-			return function() {
-				return brikz.messageSend.messageNotUnderstood(this, stSelector, arguments);
-			};
-		}
-	}
-
-	function ClassInitBrik(brikz, st) {
-
-		var dnu = brikz.ensure("dnu");
-		var manip = brikz.ensure("manipulation");
-
-		/* Initialize a class in its class hierarchy. Handle both classes and
-		 metaclasses. */
-
-		st.init = function(klass) {
-			initClass(klass);
-			if(klass.klass && !klass.meta) {
-				initClass(klass.klass);
-			}
-		};
-
-		function initClass(klass) {
-			if(klass.wrapped) {
-				copySuperclass(klass);
-			}
-		}
-
-		this.initClass = initClass;
-
-		function copySuperclass(klass) {
-			var superclass = klass.superclass,
-				localMethods = klass.methods,
-				localMethodsByJsSelector = {};
-			Object.keys(localMethods).forEach(function (each) {
-				var localMethod = localMethods[each];
+define("amber/boot", ['require', './browser-compatibility'], function (require) {
+
+    /* Reconfigurable micro composition system, https://github.com/amber-smalltalk/brikz */
+
+    function Brikz(api, apiKey, initKey) {
+        var brikz = this, backup = {};
+        apiKey = apiKey || 'exports';
+        initKey = initKey || '__init__';
+
+        function mixin(src, target, what) {
+            for (var keys = Object.keys(what || src), l = keys.length, i = 0; i < l; ++i) {
+                if (src == null) {
+                    target[keys[i]] = undefined;
+                } else {
+                    var value = src[keys[i]];
+                    if (typeof value !== "undefined") {
+                        target[keys[i]] = value;
+                    }
+                }
+            }
+            return target;
+        }
+
+        var d = {value: null, enumerable: false, configurable: true, writable: true};
+        Object.defineProperties(this, {ensure: d, rebuild: d});
+        var exclude = mixin(this, {});
+
+        this.rebuild = function () {
+            Object.keys(backup).forEach(function (key) {
+                mixin(null, api, (backup[key] || 0)[apiKey] || {});
+            });
+            var oapi = mixin(api, {}), order = [], chk = {};
+            brikz.ensure = function (key) {
+                if (key in exclude) {
+                    return null;
+                }
+                var b = brikz[key], bak = backup[key];
+                mixin(null, api, api);
+                while (typeof b === "function") {
+                    b = new b(brikz, api, bak);
+                }
+                if (b && !chk[key]) {
+                    chk[key] = true;
+                    order.push(b);
+                }
+                if (b && !b[apiKey]) {
+                    b[apiKey] = mixin(api, {});
+                }
+                brikz[key] = b;
+                return b;
+            };
+            Object.keys(brikz).forEach(function (key) {
+                brikz.ensure(key);
+            });
+            brikz.ensure = null;
+            mixin(oapi, mixin(null, api, api));
+            order.forEach(function (brik) {
+                mixin(brik[apiKey] || {}, api);
+            });
+            order.forEach(function (brik) {
+                if (brik[initKey]) brik[initKey]();
+            });
+            backup = mixin(brikz, {});
+        };
+    }
+
+    /* Brikz end */
+
+    function inherits(child, parent) {
+        child.prototype = Object.create(parent.prototype, {
+            constructor: {
+                value: child,
+                enumerable: false, configurable: true, writable: true
+            }
+        });
+        return child;
+    }
+
+    var globals = {};
+    globals.SmalltalkSettings = {};
+    var api = {};
+    var brikz = new Brikz(api);
+
+    function RootBrik(brikz, st) {
+
+        /* Smalltalk foundational objects */
+
+        /* SmalltalkRoot is the hidden root of the Amber hierarchy.
+         All objects including `Object` inherit from SmalltalkRoot */
+        function SmalltalkRoot() {
+        }
+
+        function SmalltalkProtoObject() {
+        }
+
+        inherits(SmalltalkProtoObject, SmalltalkRoot);
+        function SmalltalkObject() {
+        }
+
+        inherits(SmalltalkObject, SmalltalkProtoObject);
+        function SmalltalkNil() {
+        }
+
+        inherits(SmalltalkNil, SmalltalkObject);
+
+        this.Object = SmalltalkObject;
+        this.nil = new SmalltalkNil();
+
+        // Adds an `isNil` property to the `nil` object.  When sending
+        // nil objects from one environment to another, doing
+        // `anObject == nil` (in JavaScript) does not always answer
+        // true as the referenced nil object might come from the other
+        // environment.
+        Object.defineProperty(this.nil, 'isNil', {
+            value: true,
+            enumerable: false, configurable: false, writable: false
+        });
+
+        // Hidden root class of the system.
+        this.rootAsClass = {fn: SmalltalkRoot};
+
+        this.__init__ = function () {
+            st.addPackage("Kernel-Objects");
+            st.wrapClassName("ProtoObject", "Kernel-Objects", SmalltalkProtoObject, undefined, false);
+            st.wrapClassName("Object", "Kernel-Objects", SmalltalkObject, globals.ProtoObject, false);
+            st.wrapClassName("UndefinedObject", "Kernel-Objects", SmalltalkNil, globals.Object, false);
+        };
+    }
+
+    function OrganizeBrik(brikz, st) {
+
+        brikz.ensure("augments");
+        var SmalltalkObject = brikz.ensure("root").Object;
+
+        function SmalltalkOrganizer() {
+        }
+
+        function SmalltalkPackageOrganizer() {
+            this.elements = [];
+        }
+
+        function SmalltalkClassOrganizer() {
+            this.elements = [];
+        }
+
+        inherits(SmalltalkOrganizer, SmalltalkObject);
+        inherits(SmalltalkPackageOrganizer, SmalltalkOrganizer);
+        inherits(SmalltalkClassOrganizer, SmalltalkOrganizer);
+
+        this.__init__ = function () {
+            st.addPackage("Kernel-Infrastructure");
+            st.wrapClassName("Organizer", "Kernel-Infrastructure", SmalltalkOrganizer, globals.Object, false);
+            st.wrapClassName("PackageOrganizer", "Kernel-Infrastructure", SmalltalkPackageOrganizer, globals.Organizer, false);
+            st.wrapClassName("ClassOrganizer", "Kernel-Infrastructure", SmalltalkClassOrganizer, globals.Organizer, false);
+        };
+
+        this.setupClassOrganization = function (klass) {
+            klass.organization = new SmalltalkClassOrganizer();
+            klass.organization.theClass = klass;
+        };
+
+        this.setupPackageOrganization = function (pkg) {
+            pkg.organization = new SmalltalkPackageOrganizer();
+        };
+
+        this.addOrganizationElement = function (owner, element) {
+            owner.organization.elements.addElement(element);
+        };
+
+        this.removeOrganizationElement = function (owner, element) {
+            owner.organization.elements.removeElement(element);
+        };
+    }
+
+    function DNUBrik(brikz, st) {
+
+        brikz.ensure("selectorConversion");
+        brikz.ensure("messageSend");
+        var manip = brikz.ensure("manipulation");
+        var rootAsClass = brikz.ensure("root").rootAsClass;
+
+        /* Method not implemented handlers */
+
+        var methods = [], methodDict = Object.create(null);
+        this.selectors = [];
+        this.jsSelectors = [];
+
+        this.make = function (stSelector, targetClasses) {
+            var method = methodDict[stSelector];
+            if (method) return;
+            var jsSelector = st.st2js(stSelector);
+            this.selectors.push(stSelector);
+            this.jsSelectors.push(jsSelector);
+            method = {jsSelector: jsSelector, fn: createHandler(stSelector)};
+            methodDict[stSelector] = method;
+            methods.push(method);
+            manip.installMethod(method, rootAsClass);
+            targetClasses.forEach(function (target) {
+                manip.installMethod(method, target);
+            });
+            return method;
+        };
+
+        /* Dnu handler method */
+
+        function createHandler(stSelector) {
+            return function () {
+                return brikz.messageSend.messageNotUnderstood(this, stSelector, arguments);
+            };
+        }
+    }
+
+    function ClassInitBrik(brikz, st) {
+
+        var dnu = brikz.ensure("dnu");
+        var manip = brikz.ensure("manipulation");
+
+        /* Initialize a class in its class hierarchy. Handle both classes and
+         metaclasses. */
+
+        st.init = function (klass) {
+            initClass(klass);
+            if (klass.klass && !klass.meta) {
+                initClass(klass.klass);
+            }
+        };
+
+        function initClass(klass) {
+            if (klass.wrapped) {
+                copySuperclass(klass);
+            }
+        }
+
+        this.initClass = initClass;
+
+        function copySuperclass(klass) {
+            var superclass = klass.superclass,
+                localMethods = klass.methods,
+                localMethodsByJsSelector = {};
+            Object.keys(localMethods).forEach(function (each) {
+                var localMethod = localMethods[each];
                 localMethodsByJsSelector[localMethod.jsSelector] = localMethod;
-			});
-			var myproto = klass.fn.prototype,
-				superproto = superclass.fn.prototype;
-			dnu.jsSelectors.forEach(function (selector) {
-				if (!localMethodsByJsSelector[selector]) {
-					manip.installMethod({
-						jsSelector: selector,
-						fn: superproto[selector]
-					}, klass);
-				} else if (!myproto[selector]) {
-					manip.installMethod(localMethodsByJsSelector[selector], klass);
-				}
-			});
-		}
-	}
-
-	function ManipulationBrik(brikz, st) {
-		this.installMethod = function (method, klass) {
-			Object.defineProperty(klass.fn.prototype, method.jsSelector, {
-				value: method.fn,
-				enumerable: false, configurable: true, writable: true
-			});
-		};
-	}
-
-
-	function PackagesBrik(brikz, st) {
-
-		var org = brikz.ensure("organize");
-		var root = brikz.ensure("root");
-		var nil = root.nil;
-		var SmalltalkObject = root.Object;
-
-		function SmalltalkPackage() {}
-
-		inherits(SmalltalkPackage, SmalltalkObject);
-
-		this.__init__ = function () {
-			st.addPackage("Kernel-Infrastructure");
-			st.wrapClassName("Package", "Kernel-Infrastructure", SmalltalkPackage, globals.Object, false);
-		};
-
-		st.packages = {};
-
-		/* Smalltalk package creation. To add a Package, use smalltalk.addPackage() */
-
-		function pkg(spec) {
-			var that = new SmalltalkPackage();
-			that.pkgName = spec.pkgName;
-			org.setupPackageOrganization(that);
-			that.properties = spec.properties || {};
-			return that;
-		}
-
-		/* Add a package to the smalltalk.packages object, creating a new one if needed.
-		 If pkgName is null or empty we return nil, which is an allowed package for a class.
-		 If package already exists we still update the properties of it. */
-
-		st.addPackage = function(pkgName, properties) {
-			if(!pkgName) {return nil;}
-			if(!(st.packages[pkgName])) {
-				st.packages[pkgName] = pkg({
-					pkgName: pkgName,
-					properties: properties
-				});
-			} else {
-				if(properties) {
-					st.packages[pkgName].properties = properties;
-				}
-			}
-			return st.packages[pkgName];
-		};
-	}
-
-	function ClassesBrik(brikz, st) {
-
-		var org = brikz.ensure("organize");
-		var root = brikz.ensure("root");
-		var classInit = brikz.ensure("classInit");
-		var nil = root.nil;
-		var rootAsClass = root.rootAsClass;
-		var SmalltalkObject = root.Object;
-		rootAsClass.klass = {fn: SmalltalkClass};
-
-		function SmalltalkBehavior() {}
-		function SmalltalkClass() {}
-		function SmalltalkMetaclass() {}
-
-		inherits(SmalltalkBehavior, SmalltalkObject);
-		inherits(SmalltalkClass, SmalltalkBehavior);
-		inherits(SmalltalkMetaclass, SmalltalkBehavior);
-
-		SmalltalkMetaclass.prototype.meta = true;
-
-		this.__init__ = function () {
-			st.addPackage("Kernel-Classes");
-			st.wrapClassName("Behavior", "Kernel-Classes", SmalltalkBehavior, globals.Object, false);
-			st.wrapClassName("Metaclass", "Kernel-Classes", SmalltalkMetaclass, globals.Behavior, false);
-			st.wrapClassName("Class", "Kernel-Classes", SmalltalkClass, globals.Behavior, false);
-
-			// Manually bootstrap the metaclass hierarchy
-			globals.ProtoObject.klass.superclass = rootAsClass.klass = globals.Class;
-			addSubclass(globals.ProtoObject.klass);
-		};
-
-		/* Smalltalk classes */
-
-		var classes = [];
-		var wrappedClasses = [];
-
-		/* Smalltalk class creation. A class is an instance of an automatically
-		 created metaclass object. Newly created classes (not their metaclass)
-		 should be added to the smalltalk object, see smalltalk.addClass().
-		 Superclass linking is *not* handled here, see smalltalk.init()  */
-
-		function klass(spec) {
-			spec = spec || {};
-			var setSuperClass = spec.superclass;
-			if(!spec.superclass) {
-				spec.superclass = rootAsClass;
-			}
-
-			var meta = metaclass(spec);
-			var that = meta.instanceClass;
-
-			that.superclass = setSuperClass;
-
-			that.fn = spec.fn || inherits(function () {}, spec.superclass.fn);
-			that.subclasses = [];
-
-			setupClass(that, spec);
-
-			that.className = spec.className;
-			that.wrapped   = spec.wrapped || false;
-			meta.className = spec.className + ' class';
-			meta.superclass = spec.superclass.klass;
-			return that;
-		}
-
-		function metaclass(spec) {
-			spec = spec || {};
-			var that = new SmalltalkMetaclass();
-			that.fn = inherits(function () {}, spec.superclass.klass.fn);
-			that.instanceClass = new that.fn();
-			setupClass(that);
-			return that;
-		}
-
-		SmalltalkBehavior.prototype.toString = function () {
-			return 'Smalltalk ' + this.className;
-		};
-
-		function wireKlass(klass) {
-			Object.defineProperty(klass.fn.prototype, "klass", {
-				value: klass,
-				enumerable: false, configurable: true, writable: true
-			});
-		}
-
-		function setupClass(klass, spec) {
-			spec = spec || {};
-			klass.iVarNames = spec.iVarNames || [];
-			klass.pkg = spec.pkg;
-
-			org.setupClassOrganization(klass);
-			Object.defineProperty(klass, "methods", {
-				value: Object.create(null),
-				enumerable: false, configurable: true, writable: true
-			});
-			wireKlass(klass);
-		}
-
-		/* Add a class to the smalltalk object, creating a new one if needed.
-		 A Package is lazily created if it does not exist with given name. */
-
-		st.addClass = function(className, superclass, iVarNames, pkgName) {
-			// While subclassing nil is allowed, it might be an error, so
-			// warn about it.
-			if (typeof superclass == 'undefined' || superclass == nil) {
-				console.warn('Compiling ' + className + ' as a subclass of `nil`. A dependency might be missing.');
-			}
-			rawAddClass(pkgName, className, superclass, iVarNames, false, null);
-		};
-
-		function rawAddClass(pkgName, className, superclass, iVarNames, wrapped, fn) {
-			var pkg = st.packages[pkgName];
-
-			if (!pkg) {
-				throw new Error("Missing package "+pkgName);
-			}
-
-			if (!superclass || superclass == nil) { superclass = null; }
-			if(globals[className] && globals[className].superclass == superclass) {
-				//            globals[className].superclass = superclass;
-				globals[className].iVarNames = iVarNames || [];
-				if (pkg) globals[className].pkg = pkg;
-				if (fn) {
-					fn.prototype = globals[className].fn.prototype;
-					globals[className].fn = fn;
-					fn.prototype.constructor = fn;
-				}
-			} else {
-				if(globals[className]) {
-					st.removeClass(globals[className]);
-				}
-				globals[className] = klass({
-					className: className,
-					superclass: superclass,
-					pkg: pkg,
-					iVarNames: iVarNames,
-					fn: fn,
-					wrapped: wrapped
-				});
-
-				addSubclass(globals[className]);
-			}
-
-			classes.addElement(globals[className]);
-			org.addOrganizationElement(pkg, globals[className]);
-		}
-
-		st.removeClass = function(klass) {
-			org.removeOrganizationElement(klass.pkg, klass);
-			classes.removeElement(klass);
-			removeSubclass(klass);
-			delete globals[klass.className];
-		};
-
-		function addSubclass(klass) {
-			if(klass.superclass) {
-				klass.superclass.subclasses.addElement(klass);
-			}
-		}
-
-		function removeSubclass(klass) {
-			if(klass.superclass) {
-				klass.superclass.subclasses.removeElement(klass);
-			}
-		}
-
-		/* Create a new class wrapping a JavaScript constructor, and add it to the
-		 global smalltalk object. Package is lazily created if it does not exist with given name. */
-
-		st.wrapClassName = function(className, pkgName, fn, superclass, wrapped) {
-			wrapped = wrapped !== false;
-			rawAddClass(pkgName, className, superclass, globals[className] && globals[className].iVarNames, wrapped, fn);
-			if(wrapped) {
-				wrappedClasses.addElement(globals[className]);
-			}
-		};
-
-		/* Manually set the constructor of an existing Smalltalk klass, making it a wrapped class. */
-
-		st.setClassConstructor = function(klass, constructor) {
-			wrappedClasses.addElement(klass);
-			klass.wrapped = true;
-			klass.fn = constructor;
-
-			// The fn property changed. We need to add back the klass property to the prototype
-			wireKlass(klass);
-
-			classInit.initClass(klass);
-		};
-
-		/* Create an alias for an existing class */
-
-		st.alias = function(klass, alias) {
-			globals[alias] = klass;
-		};
-
-		/* Answer all registered Smalltalk classes */
-		//TODO: remove the function and make smalltalk.classes an array
-
-		st.classes = function() {
-			return classes;
-		};
-
-		st.wrappedClasses = function() {
-			return wrappedClasses;
-		};
-
-		// Still used, but could go away now that subclasses are stored
-		// into classes directly.
-		st.allSubclasses = function(klass) {
-			return klass._allSubclasses();
-		};
-
-	}
-
-	function MethodsBrik(brikz, st) {
-
-		var manip = brikz.ensure("manipulation");
-		var org = brikz.ensure("organize");
-		var stInit = brikz.ensure("stInit");
-		var dnu = brikz.ensure("dnu");
-		var SmalltalkObject = brikz.ensure("root").Object;
-		brikz.ensure("selectorConversion");
-		brikz.ensure("classes");
-
-		function SmalltalkMethod() {}
-		inherits(SmalltalkMethod, SmalltalkObject);
-
-		this.__init__ = function () {
-			st.addPackage("Kernel-Methods");
-			st.wrapClassName("CompiledMethod", "Kernel-Methods", SmalltalkMethod, globals.Object, false);
-		};
-
-		/* Smalltalk method object. To add a method to a class,
-		 use smalltalk.addMethod() */
-
-		st.method = function(spec) {
-			var that = new SmalltalkMethod();
-			that.selector          = spec.selector;
-			that.jsSelector        = spec.jsSelector;
-			that.args              = spec.args || {};
-			that.protocol          = spec.protocol;
-			that.source            = spec.source;
-			that.messageSends      = spec.messageSends || [];
-			that.referencedClasses = spec.referencedClasses || [];
-			that.fn                = spec.fn;
-			return that;
-		};
-
-		function ensureJsSelector(method) {
-			if (!(method.jsSelector)) {
-				method.jsSelector = st.st2js(method.selector);
-			}
-		}
-
-		/* Add/remove a method to/from a class */
-
-		st.addMethod = function (method, klass) {
-			ensureJsSelector(method);
-			manip.installMethod(method, klass);
-			klass.methods[method.selector] = method;
-			method.methodClass = klass;
-
-			// During the bootstrap, #addCompiledMethod is not used.
-			// Therefore we populate the organizer here too
-			org.addOrganizationElement(klass, method.protocol);
-
-			propagateMethodChange(klass, method);
-
-			var usedSelectors = method.messageSends,
-				targetClasses = stInit.initialized() ? st.wrappedClasses() : [];
-
-			dnu.make(method.selector, targetClasses);
-
-			for(var i=0; i<usedSelectors.length; i++) {
-				dnu.make(usedSelectors[i], targetClasses);
-			}
-		};
-
-		function propagateMethodChange(klass, method) {
-			// If already initialized (else it will be done later anyway),
-			// re-initialize all subclasses to ensure the method change
-			// propagation (for wrapped classes, not using the prototype
-			// chain).
-
-			if (stInit.initialized()) {
-				st.allSubclasses(klass).forEach(function (subclass) {
-					initMethodInClass(subclass, method);
-				});
-			}
-		}
-
-		function initMethodInClass (klass, method) {
-			if (klass.wrapped && !klass.methods[method.selector]) {
-				var jsSelector = method.jsSelector;
-				manip.installMethod({
-					jsSelector: jsSelector,
-					fn: klass.superclass.fn.prototype[jsSelector]
-				}, klass);
-			}
-		}
-
-		st.removeMethod = function(method, klass) {
-			if (klass !== method.methodClass) {
-				throw new Error(
-						"Refusing to remove method " +
-						method.methodClass.className + ">>" + method.selector +
-						" from different class " +
-						klass.className);
-			}
-
-			ensureJsSelector(method);
-			delete klass.fn.prototype[method.jsSelector];
-			delete klass.methods[method.selector];
-
-			initMethodInClass(klass, method);
-			propagateMethodChange(klass, method);
-
-			// Do *not* delete protocols from here.
-			// This is handled by #removeCompiledMethod
-		};
-
-		/* Answer all method selectors based on dnu handlers */
-
-		st.allSelectors = function() {
-			return dnu.selectors;
-		};
-
-	}
-
-	function AugmentsBrik(brikz, st) {
-
-		/* Array extensions */
-
-		Array.prototype.addElement = function(el) {
-			if(typeof el === 'undefined') { return; }
-			if(this.indexOf(el) == -1) {
-				this.push(el);
-			}
-		};
-
-		Array.prototype.removeElement = function(el) {
-			var i = this.indexOf(el);
-			if (i !== -1) { this.splice(i, 1); }
-		};
-	}
-
-	function SmalltalkInitBrik(brikz, st) {
-
-		brikz.ensure("classInit");
-		brikz.ensure("classes");
-
-		var initialized = false;
-
-		/* Smalltalk initialization. Called on page load */
-
-		st.initialize = function() {
-			if(initialized) { return; }
-
-			st.classes().forEach(function(klass) {
-				st.init(klass);
-			});
-
-			runnable();
-
-			st.classes().forEach(function(klass) {
-				klass._initialize();
-			});
-
-			initialized = true;
-		};
-
-		this.initialized = function () {
-			return initialized;
-		};
-
-		this.__init__ = function () {
-			st.addPackage("Kernel-Methods");
-			st.wrapClassName("Number", "Kernel-Objects", Number, globals.Object);
-			st.wrapClassName("BlockClosure", "Kernel-Methods", Function, globals.Object);
-			st.wrapClassName("Boolean", "Kernel-Objects", Boolean, globals.Object);
-			st.wrapClassName("Date", "Kernel-Objects", Date, globals.Object);
-
-			st.addPackage("Kernel-Collections");
-			st.addClass("Collection", globals.Object, null, "Kernel-Collections");
-			st.addClass("IndexableCollection", globals.Collection, null, "Kernel-Collections");
-			st.addClass("SequenceableCollection", globals.IndexableCollection, null, "Kernel-Collections");
-			st.addClass("CharacterArray", globals.SequenceableCollection, null, "Kernel-Collections");
-			st.wrapClassName("String", "Kernel-Collections", String, globals.CharacterArray);
-			st.wrapClassName("Array", "Kernel-Collections", Array, globals.SequenceableCollection);
-			st.wrapClassName("RegularExpression", "Kernel-Collections", RegExp, globals.Object);
-
-			st.addPackage("Kernel-Exceptions");
-			st.wrapClassName("Error", "Kernel-Exceptions", Error, globals.Object);
-
-			/* Alias definitions */
-
-			st.alias(globals.Array, "OrderedCollection");
-			st.alias(globals.Date, "Time");
-
-		};
-	}
-
-	function PrimitivesBrik(brikz, st) {
-
-		/* Unique ID number generator */
-
-		var oid = 0;
-		st.nextId = function() {
-			oid += 1;
-			return oid;
-		};
-
-		/* Converts a JavaScript object to valid Smalltalk Object */
-		st.readJSObject = function(js) {
-			var readObject = js.constructor === Object;
-			var readArray = js.constructor === Array;
-			var object = readObject ? globals.Dictionary._new() : readArray ? [] : js;
-
-			for(var i in js) {
-				if(readObject) {
-					object._at_put_(i, st.readJSObject(js[i]));
-				}
-				if(readArray) {
-					object[i] = st.readJSObject(js[i]);
-				}
-			}
-			return object;
-		};
-
-		/* Boolean assertion */
-		st.assert = function(shouldBeBoolean) {
-			if (typeof shouldBeBoolean === "boolean") return shouldBeBoolean;
-			else if (shouldBeBoolean != null && typeof shouldBeBoolean === "object") {
-				shouldBeBoolean = shouldBeBoolean.valueOf();
-				if (typeof shouldBeBoolean === "boolean") return shouldBeBoolean;
-			}
-			globals.NonBooleanReceiver._new()._object_(shouldBeBoolean)._signal();
-		};
-
-		/* List of all reserved words in JavaScript. They may not be used as variables
-		 in Smalltalk. */
-
-		// list of reserved JavaScript keywords as of
-		//   http://es5.github.com/#x7.6.1.1
-		// and
-		//   http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.6.1
-		st.reservedWords = ['break', 'case', 'catch', 'continue', 'debugger',
-							'default', 'delete', 'do', 'else', 'finally', 'for', 'function',
-							'if', 'in', 'instanceof', 'new', 'return', 'switch', 'this', 'throw',
-							'try', 'typeof', 'var', 'void', 'while', 'with',
-							// Amber protected words: these should not be compiled as-is when in code
-							'arguments',
-							// ES5: future use: http://es5.github.com/#x7.6.1.2
-							'class', 'const', 'enum', 'export', 'extends', 'import', 'super',
-							// ES5: future use in strict mode
-							'implements', 'interface', 'let', 'package', 'private', 'protected',
-							'public', 'static', 'yield'];
-
-		st.globalJsVariables = ['window', 'document', 'process', 'global'];
-
-	}
-
-	function RuntimeBrik(brikz, st) {
-
-		brikz.ensure("selectorConversion");
-		var root = brikz.ensure("root");
-		var nil = root.nil;
-		var SmalltalkObject = root.Object;
-
-		function SmalltalkMethodContext(home, setup) {
-			this.sendIdx     = {};
-			this.homeContext = home;
-			this.setup       = setup || function() {};
-
-			this.supercall = false;
-		}
-
-		inherits(SmalltalkMethodContext, SmalltalkObject);
-
-		this.__init__ = function () {
-			st.addPackage("Kernel-Methods");
-			st.wrapClassName("MethodContext", "Kernel-Methods", SmalltalkMethodContext, globals.Object, false);
-
-			// Fallbacks
-			SmalltalkMethodContext.prototype.locals = {};
-			SmalltalkMethodContext.prototype.receiver = null;
-			SmalltalkMethodContext.prototype.selector = null;
-			SmalltalkMethodContext.prototype.lookupClass = null;
-
-			SmalltalkMethodContext.prototype.fill = function(receiver, selector, locals, lookupClass) {
-				this.receiver    = receiver;
-				this.selector    = selector;
-				this.locals      = locals || {};
-				this.lookupClass = lookupClass;
-				if(this.homeContext) {
-					this.homeContext.evaluatedSelector = selector;
-				}
-			};
-
-			SmalltalkMethodContext.prototype.fillBlock = function(locals, ctx, index) {
-				this.locals        = locals || {};
-				this.outerContext  = ctx;
-				this.index         = index || 0;
-			};
-
-			SmalltalkMethodContext.prototype.init = function() {
-				var home = this.homeContext;
-				if(home) {
-					home.init();
-				}
-
-				this.setup(this);
-			};
-
-			SmalltalkMethodContext.prototype.method = function() {
-				var method;
-				var lookup = this.lookupClass || this.receiver.klass;
-				while(!method && lookup) {
-					method = lookup.methods[st.js2st(this.selector)];
-					lookup = lookup.superclass;
-				}
-				return method;
-			};
-		};
-
-		/* This is the current call context object. While it is publicly available,
-		 Use smalltalk.getThisContext() instead which will answer a safe copy of
-		 the current context */
-
-		var thisContext = null;
-
-		st.withContext = function(worker, setup) {
-			if(thisContext) {
-				return inContext(worker, setup);
-			} else {
-				return inContextWithErrorHandling(worker, setup);
-			}
-		};
-
-		function inContextWithErrorHandling(worker, setup) {
-			try {
-				return inContext(worker, setup);
-			} catch (error) {
-				handleError(error);
-				thisContext = null;
-				// Rethrow the error in any case.
-				error.amberHandled = true;
-				throw error;
-			}
-		}
-
-		function inContext(worker, setup) {
-			var oldContext = thisContext;
-			thisContext = new SmalltalkMethodContext(thisContext, setup);
-			var result = worker(thisContext);
-			thisContext = oldContext;
-			return result;
-		}
-
-		/* Wrap a JavaScript exception in a Smalltalk Exception.
-
-		 In case of a RangeError, stub the stack after 100 contexts to
-		 avoid another RangeError later when the stack is manipulated. */
-		function wrappedError(error) {
-			var errorWrapper = globals.JavaScriptException._on_(error);
-			// Add the error to the context, so it is visible in the stack
-			try { errorWrapper._signal(); } catch (ex) {}
-			var context = st.getThisContext();
-			if(isRangeError(error)) {
-				stubContextStack(context);
-			}
-			errorWrapper._context_(context);
-			return errorWrapper;
-		}
-
-		/* Stub the context stack after 100 contexts */
-		function stubContextStack(context) {
-			var currentContext = context;
-			var contexts = 0;
-			while(contexts < 100) {
-				if(currentContext) {
-					currentContext = currentContext.homeContext;
-				}
-				contexts++;
-			}
-			if(currentContext) {
-				currentContext.homeContext = undefined;
-			}
-		}
-
-		function isRangeError(error) {
-			return error instanceof RangeError;
-		}
-
-
-		/* Handles Smalltalk errors. Triggers the registered ErrorHandler
-		 (See the Smalltalk class ErrorHandler and its subclasses */
-
-		function handleError(error) {
-			if (!error.smalltalkError) {
-				error = wrappedError(error);
-			}
-			globals.ErrorHandler._handleError_(error);
-		}
-
-		/* Handle thisContext pseudo variable */
-
-		st.getThisContext = function() {
-			if(thisContext) {
-				thisContext.init();
-				return thisContext;
-			} else {
-				return nil;
-			}
-		};
-	}
-
-	function MessageSendBrik(brikz, st) {
-
-		brikz.ensure("selectorConversion");
-		var nil = brikz.ensure("root").nil;
-
-		/* Handles unhandled errors during message sends */
-		// simply send the message and handle #dnu:
-
-		st.send = function(receiver, jsSelector, args, klass) {
-			var method;
-			if(receiver == null) {
-				receiver = nil;
-			}
-			method = klass ? klass.fn.prototype[jsSelector] : receiver.klass && receiver[jsSelector];
-			if(method) {
-				return method.apply(receiver, args || []);
-			} else {
-				return messageNotUnderstood(receiver, st.js2st(jsSelector), args);
-			}
-		};
-
-		function invokeDnuMethod(receiver, stSelector, args) {
-			return receiver._doesNotUnderstand_(
-				globals.Message._new()
-					._selector_(stSelector)
-					._arguments_([].slice.call(args))
-			);
-		}
-
-		/* Handles #dnu: *and* JavaScript method calls.
-		 if the receiver has no klass, we consider it a JS object (outside of the
-		 Amber system). Else assume that the receiver understands #doesNotUnderstand: */
-		function messageNotUnderstood(receiver, stSelector, args) {
-			if (receiver.klass != null && !receiver.allowJavaScriptCalls) {
-				return invokeDnuMethod(receiver, stSelector, args);
-			}
-			/* Call a method of a JS object, or answer a property if it exists.
-			 Else try wrapping a JSObjectProxy around the receiver. */
-			var propertyName = st.st2prop(stSelector);
-			if (!(propertyName in receiver)) {
-				return invokeDnuMethod(globals.JSObjectProxy._on_(receiver), stSelector, args);
-			}
-			return accessJavaScript(receiver, propertyName, args);
-		}
-
-		/* If the object property is a function, then call it, except if it starts with
-		 an uppercase character (we probably want to answer the function itself in this
-		 case and send it #new from Amber).
-
-		 Converts keyword-based selectors by using the first
-		 keyword only, but keeping all message arguments.
-
-		 Example:
-		 "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
-		function accessJavaScript(receiver, propertyName, args) {
-			var propertyValue = receiver[propertyName];
-			if (typeof propertyValue === "function" && !/^[A-Z]/.test(propertyName)) {
-				return propertyValue.apply(receiver, args || []);
-			} else if (args.length > 0) {
-				receiver[propertyName] = args[0];
-				return nil;
-			} else {
-				return propertyValue;
-			}
-		}
-
-		st.accessJavaScript = accessJavaScript;
-		this.messageNotUnderstood = messageNotUnderstood;
-	}
-
-	function SelectorConversionBrik(brikz, st) {
-
-		/* Convert a Smalltalk selector into a JS selector */
-		st.st2js = function(string) {
-			var selector = '_' + string;
-			selector = selector.replace(/:/g, '_');
-			selector = selector.replace(/[\&]/g, '_and');
-			selector = selector.replace(/[\|]/g, '_or');
-			selector = selector.replace(/[+]/g, '_plus');
-			selector = selector.replace(/-/g, '_minus');
-			selector = selector.replace(/[*]/g ,'_star');
-			selector = selector.replace(/[\/]/g ,'_slash');
-			selector = selector.replace(/[\\]/g ,'_backslash');
-			selector = selector.replace(/[\~]/g ,'_tild');
-			selector = selector.replace(/>/g ,'_gt');
-			selector = selector.replace(/</g ,'_lt');
-			selector = selector.replace(/=/g ,'_eq');
-			selector = selector.replace(/,/g ,'_comma');
-			selector = selector.replace(/[@]/g ,'_at');
-			return selector;
-		};
-
-		/* Convert a string to a valid smalltalk selector.
-		 if you modify the following functions, also change st2js
-		 accordingly */
-		st.js2st = function(selector) {
-			if(selector.match(/__/)) {
-				return binaryJsToSt(selector);
-			} else {
-				return keywordJsToSt(selector);
-			}
-		};
-
-		function keywordJsToSt(selector) {
-			return selector.replace(/^_/, '').replace(/_/g, ':');
-		}
-
-		function binaryJsToSt(selector) {
-			return selector
-				.replace(/^_/, '')
-				.replace(/_and/g, '&')
-				.replace(/_or/g, '|')
-				.replace(/_plus/g, '+')
-				.replace(/_minus/g, '-')
-				.replace(/_star/g, '*')
-				.replace(/_slash/g, '/')
-				.replace(/_backslash/g, '\\')
-				.replace(/_tild/g, '~')
-				.replace(/_gt/g, '>')
-				.replace(/_lt/g, '<')
-				.replace(/_eq/g, '=')
-				.replace(/_comma/g, ',')
-				.replace(/_at/g, '@');
-		}
-
-		st.st2prop = function (stSelector) {
-			var colonPosition = stSelector.indexOf(':');
-			return colonPosition === -1 ? stSelector : stSelector.slice(0, colonPosition);
-		};
-	}
-
-	/* Adds AMD and requirejs related methods to the smalltalk object */
-	function AMDBrik(brikz, st) {
-		this.__init__ = function () {
-			st.amdRequire = require;
-			st.defaultTransportType = st.defaultTransportType || "amd";
-			st.defaultAmdNamespace = st.defaultAmdNamespace || "amber_core";
-		};
-	}
-
-	/* Defines asReceiver to be present at load time */
-	/* (logically it belongs more to PrimitiveBrik) */
-	function AsReceiverBrik(brikz, st) {
-
-		var nil = brikz.ensure("root").nil;
-
-		/**
-		 * This function is used all over the compiled amber code.
-		 * It takes any value (JavaScript or Smalltalk)
-		 * and returns a proper Amber Smalltalk receiver.
-		 *
-		 * null or undefined -> nil,
-		 * plain JS object -> wrapped JS object,
-		 * otherwise unchanged
-		 */
-		this.asReceiver = function (o) {
-			if (o == null) return nil;
-			if (typeof o === "object" || typeof o === "function") {
-				return o.klass != null ? o : globals.JSObjectProxy._on_(o);
-			}
-			// IMPORTANT: This optimization (return o if typeof !== "object")
-			// assumes all primitive types are wrapped by some Smalltalk class
-			// so they can be returned as-is, without boxing and looking for .klass.
-			// KEEP THE primitives-are-wrapped INVARIANT!
-			return o;
-		};
-	}
-
-
-	/* Making smalltalk that can load */
-
-	brikz.root = RootBrik;
-	brikz.dnu = DNUBrik;
-	brikz.organize = OrganizeBrik;
-	brikz.selectorConversion = SelectorConversionBrik;
-	brikz.classInit = ClassInitBrik;
-	brikz.manipulation = ManipulationBrik;
-	brikz.packages = PackagesBrik;
-	brikz.classes = ClassesBrik;
-	brikz.methods = MethodsBrik;
-	brikz.stInit = SmalltalkInitBrik;
-	brikz.augments = AugmentsBrik;
-	brikz.asReceiver = AsReceiverBrik;
-	brikz.amd = AMDBrik;
-
-	brikz.rebuild();
-
-	/* Making smalltalk that can run */
-
-	function runnable () {
-		brikz.messageSend = MessageSendBrik;
-		brikz.runtime = RuntimeBrik;
-		brikz.primitives = PrimitivesBrik;
-
-		brikz.rebuild();
-	}
-
-	return { api: api, nil: brikz.root.nil, globals: globals, asReceiver: brikz.asReceiver.asReceiver };
+            });
+            var myproto = klass.fn.prototype,
+                superproto = superclass.fn.prototype;
+            dnu.jsSelectors.forEach(function (selector) {
+                if (!localMethodsByJsSelector[selector]) {
+                    manip.installMethod({
+                        jsSelector: selector,
+                        fn: superproto[selector]
+                    }, klass);
+                } else if (!myproto[selector]) {
+                    manip.installMethod(localMethodsByJsSelector[selector], klass);
+                }
+            });
+        }
+    }
+
+    function ManipulationBrik(brikz, st) {
+        this.installMethod = function (method, klass) {
+            Object.defineProperty(klass.fn.prototype, method.jsSelector, {
+                value: method.fn,
+                enumerable: false, configurable: true, writable: true
+            });
+        };
+    }
+
+
+    function PackagesBrik(brikz, st) {
+
+        var org = brikz.ensure("organize");
+        var root = brikz.ensure("root");
+        var nil = root.nil;
+        var SmalltalkObject = root.Object;
+
+        function SmalltalkPackage() {
+        }
+
+        inherits(SmalltalkPackage, SmalltalkObject);
+
+        this.__init__ = function () {
+            st.addPackage("Kernel-Infrastructure");
+            st.wrapClassName("Package", "Kernel-Infrastructure", SmalltalkPackage, globals.Object, false);
+        };
+
+        st.packages = {};
+
+        /* Smalltalk package creation. To add a Package, use smalltalk.addPackage() */
+
+        function pkg(spec) {
+            var that = new SmalltalkPackage();
+            that.pkgName = spec.pkgName;
+            org.setupPackageOrganization(that);
+            that.properties = spec.properties || {};
+            return that;
+        }
+
+        /* Add a package to the smalltalk.packages object, creating a new one if needed.
+         If pkgName is null or empty we return nil, which is an allowed package for a class.
+         If package already exists we still update the properties of it. */
+
+        st.addPackage = function (pkgName, properties) {
+            if (!pkgName) {
+                return nil;
+            }
+            if (!(st.packages[pkgName])) {
+                st.packages[pkgName] = pkg({
+                    pkgName: pkgName,
+                    properties: properties
+                });
+            } else {
+                if (properties) {
+                    st.packages[pkgName].properties = properties;
+                }
+            }
+            return st.packages[pkgName];
+        };
+    }
+
+    function ClassesBrik(brikz, st) {
+
+        var org = brikz.ensure("organize");
+        var root = brikz.ensure("root");
+        var classInit = brikz.ensure("classInit");
+        var nil = root.nil;
+        var rootAsClass = root.rootAsClass;
+        var SmalltalkObject = root.Object;
+        rootAsClass.klass = {fn: SmalltalkClass};
+
+        function SmalltalkBehavior() {
+        }
+
+        function SmalltalkClass() {
+        }
+
+        function SmalltalkMetaclass() {
+        }
+
+        inherits(SmalltalkBehavior, SmalltalkObject);
+        inherits(SmalltalkClass, SmalltalkBehavior);
+        inherits(SmalltalkMetaclass, SmalltalkBehavior);
+
+        SmalltalkMetaclass.prototype.meta = true;
+
+        this.__init__ = function () {
+            st.addPackage("Kernel-Classes");
+            st.wrapClassName("Behavior", "Kernel-Classes", SmalltalkBehavior, globals.Object, false);
+            st.wrapClassName("Metaclass", "Kernel-Classes", SmalltalkMetaclass, globals.Behavior, false);
+            st.wrapClassName("Class", "Kernel-Classes", SmalltalkClass, globals.Behavior, false);
+
+            // Manually bootstrap the metaclass hierarchy
+            globals.ProtoObject.klass.superclass = rootAsClass.klass = globals.Class;
+            addSubclass(globals.ProtoObject.klass);
+        };
+
+        /* Smalltalk classes */
+
+        var classes = [];
+        var wrappedClasses = [];
+
+        /* Smalltalk class creation. A class is an instance of an automatically
+         created metaclass object. Newly created classes (not their metaclass)
+         should be added to the smalltalk object, see smalltalk.addClass().
+         Superclass linking is *not* handled here, see smalltalk.init()  */
+
+        function klass(spec) {
+            spec = spec || {};
+            var setSuperClass = spec.superclass;
+            if (!spec.superclass) {
+                spec.superclass = rootAsClass;
+            }
+
+            var meta = metaclass(spec);
+            var that = meta.instanceClass;
+
+            that.superclass = setSuperClass;
+
+            that.fn = spec.fn || inherits(function () {
+                }, spec.superclass.fn);
+            that.subclasses = [];
+
+            setupClass(that, spec);
+
+            that.className = spec.className;
+            that.wrapped = spec.wrapped || false;
+            meta.className = spec.className + ' class';
+            meta.superclass = spec.superclass.klass;
+            return that;
+        }
+
+        function metaclass(spec) {
+            spec = spec || {};
+            var that = new SmalltalkMetaclass();
+            that.fn = inherits(function () {
+            }, spec.superclass.klass.fn);
+            that.instanceClass = new that.fn();
+            setupClass(that);
+            return that;
+        }
+
+        SmalltalkBehavior.prototype.toString = function () {
+            return 'Smalltalk ' + this.className;
+        };
+
+        function wireKlass(klass) {
+            Object.defineProperty(klass.fn.prototype, "klass", {
+                value: klass,
+                enumerable: false, configurable: true, writable: true
+            });
+        }
+
+        function setupClass(klass, spec) {
+            spec = spec || {};
+            klass.iVarNames = spec.iVarNames || [];
+            klass.pkg = spec.pkg;
+
+            org.setupClassOrganization(klass);
+            Object.defineProperty(klass, "methods", {
+                value: Object.create(null),
+                enumerable: false, configurable: true, writable: true
+            });
+            wireKlass(klass);
+        }
+
+        /* Add a class to the smalltalk object, creating a new one if needed.
+         A Package is lazily created if it does not exist with given name. */
+
+        st.addClass = function (className, superclass, iVarNames, pkgName) {
+            // While subclassing nil is allowed, it might be an error, so
+            // warn about it.
+            if (typeof superclass == 'undefined' || superclass == nil) {
+                console.warn('Compiling ' + className + ' as a subclass of `nil`. A dependency might be missing.');
+            }
+            rawAddClass(pkgName, className, superclass, iVarNames, false, null);
+        };
+
+        function rawAddClass(pkgName, className, superclass, iVarNames, wrapped, fn) {
+            var pkg = st.packages[pkgName];
+
+            if (!pkg) {
+                throw new Error("Missing package " + pkgName);
+            }
+
+            if (!superclass || superclass == nil) {
+                superclass = null;
+            }
+            if (globals[className] && globals[className].superclass == superclass) {
+                //            globals[className].superclass = superclass;
+                globals[className].iVarNames = iVarNames || [];
+                if (pkg) globals[className].pkg = pkg;
+                if (fn) {
+                    fn.prototype = globals[className].fn.prototype;
+                    globals[className].fn = fn;
+                    fn.prototype.constructor = fn;
+                }
+            } else {
+                if (globals[className]) {
+                    st.removeClass(globals[className]);
+                }
+                globals[className] = klass({
+                    className: className,
+                    superclass: superclass,
+                    pkg: pkg,
+                    iVarNames: iVarNames,
+                    fn: fn,
+                    wrapped: wrapped
+                });
+
+                addSubclass(globals[className]);
+            }
+
+            classes.addElement(globals[className]);
+            org.addOrganizationElement(pkg, globals[className]);
+        }
+
+        st.removeClass = function (klass) {
+            org.removeOrganizationElement(klass.pkg, klass);
+            classes.removeElement(klass);
+            removeSubclass(klass);
+            delete globals[klass.className];
+        };
+
+        function addSubclass(klass) {
+            if (klass.superclass) {
+                klass.superclass.subclasses.addElement(klass);
+            }
+        }
+
+        function removeSubclass(klass) {
+            if (klass.superclass) {
+                klass.superclass.subclasses.removeElement(klass);
+            }
+        }
+
+        /* Create a new class wrapping a JavaScript constructor, and add it to the
+         global smalltalk object. Package is lazily created if it does not exist with given name. */
+
+        st.wrapClassName = function (className, pkgName, fn, superclass, wrapped) {
+            wrapped = wrapped !== false;
+            rawAddClass(pkgName, className, superclass, globals[className] && globals[className].iVarNames, wrapped, fn);
+            if (wrapped) {
+                wrappedClasses.addElement(globals[className]);
+            }
+        };
+
+        /* Manually set the constructor of an existing Smalltalk klass, making it a wrapped class. */
+
+        st.setClassConstructor = function (klass, constructor) {
+            wrappedClasses.addElement(klass);
+            klass.wrapped = true;
+            klass.fn = constructor;
+
+            // The fn property changed. We need to add back the klass property to the prototype
+            wireKlass(klass);
+
+            classInit.initClass(klass);
+        };
+
+        /* Create an alias for an existing class */
+
+        st.alias = function (klass, alias) {
+            globals[alias] = klass;
+        };
+
+        /* Answer all registered Smalltalk classes */
+        //TODO: remove the function and make smalltalk.classes an array
+
+        st.classes = function () {
+            return classes;
+        };
+
+        st.wrappedClasses = function () {
+            return wrappedClasses;
+        };
+
+        // Still used, but could go away now that subclasses are stored
+        // into classes directly.
+        st.allSubclasses = function (klass) {
+            return klass._allSubclasses();
+        };
+
+    }
+
+    function MethodsBrik(brikz, st) {
+
+        var manip = brikz.ensure("manipulation");
+        var org = brikz.ensure("organize");
+        var stInit = brikz.ensure("stInit");
+        var dnu = brikz.ensure("dnu");
+        var SmalltalkObject = brikz.ensure("root").Object;
+        brikz.ensure("selectorConversion");
+        brikz.ensure("classes");
+
+        function SmalltalkMethod() {
+        }
+
+        inherits(SmalltalkMethod, SmalltalkObject);
+
+        this.__init__ = function () {
+            st.addPackage("Kernel-Methods");
+            st.wrapClassName("CompiledMethod", "Kernel-Methods", SmalltalkMethod, globals.Object, false);
+        };
+
+        /* Smalltalk method object. To add a method to a class,
+         use smalltalk.addMethod() */
+
+        st.method = function (spec) {
+            var that = new SmalltalkMethod();
+            that.selector = spec.selector;
+            that.jsSelector = spec.jsSelector;
+            that.args = spec.args || {};
+            that.protocol = spec.protocol;
+            that.source = spec.source;
+            that.messageSends = spec.messageSends || [];
+            that.referencedClasses = spec.referencedClasses || [];
+            that.fn = spec.fn;
+            return that;
+        };
+
+        function ensureJsSelector(method) {
+            if (!(method.jsSelector)) {
+                method.jsSelector = st.st2js(method.selector);
+            }
+        }
+
+        /* Add/remove a method to/from a class */
+
+        st.addMethod = function (method, klass) {
+            ensureJsSelector(method);
+            manip.installMethod(method, klass);
+            klass.methods[method.selector] = method;
+            method.methodClass = klass;
+
+            // During the bootstrap, #addCompiledMethod is not used.
+            // Therefore we populate the organizer here too
+            org.addOrganizationElement(klass, method.protocol);
+
+            propagateMethodChange(klass, method);
+
+            var usedSelectors = method.messageSends,
+                targetClasses = stInit.initialized() ? st.wrappedClasses() : [];
+
+            dnu.make(method.selector, targetClasses);
+
+            for (var i = 0; i < usedSelectors.length; i++) {
+                dnu.make(usedSelectors[i], targetClasses);
+            }
+        };
+
+        function propagateMethodChange(klass, method) {
+            // If already initialized (else it will be done later anyway),
+            // re-initialize all subclasses to ensure the method change
+            // propagation (for wrapped classes, not using the prototype
+            // chain).
+
+            if (stInit.initialized()) {
+                st.allSubclasses(klass).forEach(function (subclass) {
+                    initMethodInClass(subclass, method);
+                });
+            }
+        }
+
+        function initMethodInClass(klass, method) {
+            if (klass.wrapped && !klass.methods[method.selector]) {
+                var jsSelector = method.jsSelector;
+                manip.installMethod({
+                    jsSelector: jsSelector,
+                    fn: klass.superclass.fn.prototype[jsSelector]
+                }, klass);
+            }
+        }
+
+        st.removeMethod = function (method, klass) {
+            if (klass !== method.methodClass) {
+                throw new Error(
+                    "Refusing to remove method " +
+                    method.methodClass.className + ">>" + method.selector +
+                    " from different class " +
+                    klass.className);
+            }
+
+            ensureJsSelector(method);
+            delete klass.fn.prototype[method.jsSelector];
+            delete klass.methods[method.selector];
+
+            initMethodInClass(klass, method);
+            propagateMethodChange(klass, method);
+
+            // Do *not* delete protocols from here.
+            // This is handled by #removeCompiledMethod
+        };
+
+        /* Answer all method selectors based on dnu handlers */
+
+        st.allSelectors = function () {
+            return dnu.selectors;
+        };
+
+    }
+
+    function AugmentsBrik(brikz, st) {
+
+        /* Array extensions */
+
+        Array.prototype.addElement = function (el) {
+            if (typeof el === 'undefined') {
+                return;
+            }
+            if (this.indexOf(el) == -1) {
+                this.push(el);
+            }
+        };
+
+        Array.prototype.removeElement = function (el) {
+            var i = this.indexOf(el);
+            if (i !== -1) {
+                this.splice(i, 1);
+            }
+        };
+    }
+
+    function SmalltalkInitBrik(brikz, st) {
+
+        brikz.ensure("classInit");
+        brikz.ensure("classes");
+
+        var initialized = false;
+
+        /* Smalltalk initialization. Called on page load */
+
+        st.initialize = function () {
+            if (initialized) {
+                return;
+            }
+
+            st.classes().forEach(function (klass) {
+                st.init(klass);
+            });
+
+            runnable();
+
+            st.classes().forEach(function (klass) {
+                klass._initialize();
+            });
+
+            initialized = true;
+        };
+
+        this.initialized = function () {
+            return initialized;
+        };
+
+        this.__init__ = function () {
+            st.addPackage("Kernel-Methods");
+            st.wrapClassName("Number", "Kernel-Objects", Number, globals.Object);
+            st.wrapClassName("BlockClosure", "Kernel-Methods", Function, globals.Object);
+            st.wrapClassName("Boolean", "Kernel-Objects", Boolean, globals.Object);
+            st.wrapClassName("Date", "Kernel-Objects", Date, globals.Object);
+
+            st.addPackage("Kernel-Collections");
+            st.addClass("Collection", globals.Object, null, "Kernel-Collections");
+            st.addClass("IndexableCollection", globals.Collection, null, "Kernel-Collections");
+            st.addClass("SequenceableCollection", globals.IndexableCollection, null, "Kernel-Collections");
+            st.addClass("CharacterArray", globals.SequenceableCollection, null, "Kernel-Collections");
+            st.wrapClassName("String", "Kernel-Collections", String, globals.CharacterArray);
+            st.wrapClassName("Array", "Kernel-Collections", Array, globals.SequenceableCollection);
+            st.wrapClassName("RegularExpression", "Kernel-Collections", RegExp, globals.Object);
+
+            st.addPackage("Kernel-Exceptions");
+            st.wrapClassName("Error", "Kernel-Exceptions", Error, globals.Object);
+
+            /* Alias definitions */
+
+            st.alias(globals.Array, "OrderedCollection");
+            st.alias(globals.Date, "Time");
+
+        };
+    }
+
+    function PrimitivesBrik(brikz, st) {
+
+        /* Unique ID number generator */
+
+        var oid = 0;
+        st.nextId = function () {
+            oid += 1;
+            return oid;
+        };
+
+        /* Converts a JavaScript object to valid Smalltalk Object */
+        st.readJSObject = function (js) {
+            var readObject = js.constructor === Object;
+            var readArray = js.constructor === Array;
+            var object = readObject ? globals.Dictionary._new() : readArray ? [] : js;
+
+            for (var i in js) {
+                if (readObject) {
+                    object._at_put_(i, st.readJSObject(js[i]));
+                }
+                if (readArray) {
+                    object[i] = st.readJSObject(js[i]);
+                }
+            }
+            return object;
+        };
+
+        /* Boolean assertion */
+        st.assert = function (shouldBeBoolean) {
+            if (typeof shouldBeBoolean === "boolean") return shouldBeBoolean;
+            else if (shouldBeBoolean != null && typeof shouldBeBoolean === "object") {
+                shouldBeBoolean = shouldBeBoolean.valueOf();
+                if (typeof shouldBeBoolean === "boolean") return shouldBeBoolean;
+            }
+            globals.NonBooleanReceiver._new()._object_(shouldBeBoolean)._signal();
+        };
+
+        /* List of all reserved words in JavaScript. They may not be used as variables
+         in Smalltalk. */
+
+        // list of reserved JavaScript keywords as of
+        //   http://es5.github.com/#x7.6.1.1
+        // and
+        //   http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.6.1
+        st.reservedWords = ['break', 'case', 'catch', 'continue', 'debugger',
+            'default', 'delete', 'do', 'else', 'finally', 'for', 'function',
+            'if', 'in', 'instanceof', 'new', 'return', 'switch', 'this', 'throw',
+            'try', 'typeof', 'var', 'void', 'while', 'with',
+            // Amber protected words: these should not be compiled as-is when in code
+            'arguments',
+            // ES5: future use: http://es5.github.com/#x7.6.1.2
+            'class', 'const', 'enum', 'export', 'extends', 'import', 'super',
+            // ES5: future use in strict mode
+            'implements', 'interface', 'let', 'package', 'private', 'protected',
+            'public', 'static', 'yield'];
+
+        st.globalJsVariables = ['window', 'document', 'process', 'global'];
+
+    }
+
+    function RuntimeBrik(brikz, st) {
+
+        brikz.ensure("selectorConversion");
+        var root = brikz.ensure("root");
+        var nil = root.nil;
+        var SmalltalkObject = root.Object;
+
+        function SmalltalkMethodContext(home, setup) {
+            this.sendIdx = {};
+            this.homeContext = home;
+            this.setup = setup || function () {
+                };
+
+            this.supercall = false;
+        }
+
+        inherits(SmalltalkMethodContext, SmalltalkObject);
+
+        this.__init__ = function () {
+            st.addPackage("Kernel-Methods");
+            st.wrapClassName("MethodContext", "Kernel-Methods", SmalltalkMethodContext, globals.Object, false);
+
+            // Fallbacks
+            SmalltalkMethodContext.prototype.locals = {};
+            SmalltalkMethodContext.prototype.receiver = null;
+            SmalltalkMethodContext.prototype.selector = null;
+            SmalltalkMethodContext.prototype.lookupClass = null;
+
+            SmalltalkMethodContext.prototype.fill = function (receiver, selector, locals, lookupClass) {
+                this.receiver = receiver;
+                this.selector = selector;
+                this.locals = locals || {};
+                this.lookupClass = lookupClass;
+                if (this.homeContext) {
+                    this.homeContext.evaluatedSelector = selector;
+                }
+            };
+
+            SmalltalkMethodContext.prototype.fillBlock = function (locals, ctx, index) {
+                this.locals = locals || {};
+                this.outerContext = ctx;
+                this.index = index || 0;
+            };
+
+            SmalltalkMethodContext.prototype.init = function () {
+                var home = this.homeContext;
+                if (home) {
+                    home.init();
+                }
+
+                this.setup(this);
+            };
+
+            SmalltalkMethodContext.prototype.method = function () {
+                var method;
+                var lookup = this.lookupClass || this.receiver.klass;
+                while (!method && lookup) {
+                    method = lookup.methods[st.js2st(this.selector)];
+                    lookup = lookup.superclass;
+                }
+                return method;
+            };
+        };
+
+        /* This is the current call context object. While it is publicly available,
+         Use smalltalk.getThisContext() instead which will answer a safe copy of
+         the current context */
+
+        var thisContext = null;
+
+        st.withContext = function (worker, setup) {
+            if (thisContext) {
+                return inContext(worker, setup);
+            } else {
+                return inContextWithErrorHandling(worker, setup);
+            }
+        };
+
+        function inContextWithErrorHandling(worker, setup) {
+            try {
+                return inContext(worker, setup);
+            } catch (error) {
+                handleError(error);
+                thisContext = null;
+                // Rethrow the error in any case.
+                error.amberHandled = true;
+                throw error;
+            }
+        }
+
+        function inContext(worker, setup) {
+            var oldContext = thisContext;
+            thisContext = new SmalltalkMethodContext(thisContext, setup);
+            var result = worker(thisContext);
+            thisContext = oldContext;
+            return result;
+        }
+
+        /* Wrap a JavaScript exception in a Smalltalk Exception.
+
+         In case of a RangeError, stub the stack after 100 contexts to
+         avoid another RangeError later when the stack is manipulated. */
+        function wrappedError(error) {
+            var errorWrapper = globals.JavaScriptException._on_(error);
+            // Add the error to the context, so it is visible in the stack
+            try {
+                errorWrapper._signal();
+            } catch (ex) {
+            }
+            var context = st.getThisContext();
+            if (isRangeError(error)) {
+                stubContextStack(context);
+            }
+            errorWrapper._context_(context);
+            return errorWrapper;
+        }
+
+        /* Stub the context stack after 100 contexts */
+        function stubContextStack(context) {
+            var currentContext = context;
+            var contexts = 0;
+            while (contexts < 100) {
+                if (currentContext) {
+                    currentContext = currentContext.homeContext;
+                }
+                contexts++;
+            }
+            if (currentContext) {
+                currentContext.homeContext = undefined;
+            }
+        }
+
+        function isRangeError(error) {
+            return error instanceof RangeError;
+        }
+
+
+        /* Handles Smalltalk errors. Triggers the registered ErrorHandler
+         (See the Smalltalk class ErrorHandler and its subclasses */
+
+        function handleError(error) {
+            if (!error.smalltalkError) {
+                error = wrappedError(error);
+            }
+            globals.ErrorHandler._handleError_(error);
+        }
+
+        /* Handle thisContext pseudo variable */
+
+        st.getThisContext = function () {
+            if (thisContext) {
+                thisContext.init();
+                return thisContext;
+            } else {
+                return nil;
+            }
+        };
+    }
+
+    function MessageSendBrik(brikz, st) {
+
+        brikz.ensure("selectorConversion");
+        var nil = brikz.ensure("root").nil;
+
+        /* Handles unhandled errors during message sends */
+        // simply send the message and handle #dnu:
+
+        st.send = function (receiver, jsSelector, args, klass) {
+            var method;
+            if (receiver == null) {
+                receiver = nil;
+            }
+            method = klass ? klass.fn.prototype[jsSelector] : receiver.klass && receiver[jsSelector];
+            if (method) {
+                return method.apply(receiver, args || []);
+            } else {
+                return messageNotUnderstood(receiver, st.js2st(jsSelector), args);
+            }
+        };
+
+        function invokeDnuMethod(receiver, stSelector, args) {
+            return receiver._doesNotUnderstand_(
+                globals.Message._new()
+                    ._selector_(stSelector)
+                    ._arguments_([].slice.call(args))
+            );
+        }
+
+        /* Handles #dnu: *and* JavaScript method calls.
+         if the receiver has no klass, we consider it a JS object (outside of the
+         Amber system). Else assume that the receiver understands #doesNotUnderstand: */
+        function messageNotUnderstood(receiver, stSelector, args) {
+            if (receiver.klass != null && !receiver.allowJavaScriptCalls) {
+                return invokeDnuMethod(receiver, stSelector, args);
+            }
+            /* Call a method of a JS object, or answer a property if it exists.
+             Else try wrapping a JSObjectProxy around the receiver. */
+            var propertyName = st.st2prop(stSelector);
+            if (!(propertyName in receiver)) {
+                return invokeDnuMethod(globals.JSObjectProxy._on_(receiver), stSelector, args);
+            }
+            return accessJavaScript(receiver, propertyName, args);
+        }
+
+        /* If the object property is a function, then call it, except if it starts with
+         an uppercase character (we probably want to answer the function itself in this
+         case and send it #new from Amber).
+
+         Converts keyword-based selectors by using the first
+         keyword only, but keeping all message arguments.
+
+         Example:
+         "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
+        function accessJavaScript(receiver, propertyName, args) {
+            var propertyValue = receiver[propertyName];
+            if (typeof propertyValue === "function" && !/^[A-Z]/.test(propertyName)) {
+                return propertyValue.apply(receiver, args || []);
+            } else if (args.length > 0) {
+                receiver[propertyName] = args[0];
+                return nil;
+            } else {
+                return propertyValue;
+            }
+        }
+
+        st.accessJavaScript = accessJavaScript;
+        this.messageNotUnderstood = messageNotUnderstood;
+    }
+
+    function SelectorConversionBrik(brikz, st) {
+
+        /* Convert a Smalltalk selector into a JS selector */
+        st.st2js = function (string) {
+            var selector = '_' + string;
+            selector = selector.replace(/:/g, '_');
+            selector = selector.replace(/[\&]/g, '_and');
+            selector = selector.replace(/[\|]/g, '_or');
+            selector = selector.replace(/[+]/g, '_plus');
+            selector = selector.replace(/-/g, '_minus');
+            selector = selector.replace(/[*]/g, '_star');
+            selector = selector.replace(/[\/]/g, '_slash');
+            selector = selector.replace(/[\\]/g, '_backslash');
+            selector = selector.replace(/[\~]/g, '_tild');
+            selector = selector.replace(/>/g, '_gt');
+            selector = selector.replace(/</g, '_lt');
+            selector = selector.replace(/=/g, '_eq');
+            selector = selector.replace(/,/g, '_comma');
+            selector = selector.replace(/[@]/g, '_at');
+            return selector;
+        };
+
+        /* Convert a string to a valid smalltalk selector.
+         if you modify the following functions, also change st2js
+         accordingly */
+        st.js2st = function (selector) {
+            if (selector.match(/__/)) {
+                return binaryJsToSt(selector);
+            } else {
+                return keywordJsToSt(selector);
+            }
+        };
+
+        function keywordJsToSt(selector) {
+            return selector.replace(/^_/, '').replace(/_/g, ':');
+        }
+
+        function binaryJsToSt(selector) {
+            return selector
+                .replace(/^_/, '')
+                .replace(/_and/g, '&')
+                .replace(/_or/g, '|')
+                .replace(/_plus/g, '+')
+                .replace(/_minus/g, '-')
+                .replace(/_star/g, '*')
+                .replace(/_slash/g, '/')
+                .replace(/_backslash/g, '\\')
+                .replace(/_tild/g, '~')
+                .replace(/_gt/g, '>')
+                .replace(/_lt/g, '<')
+                .replace(/_eq/g, '=')
+                .replace(/_comma/g, ',')
+                .replace(/_at/g, '@');
+        }
+
+        st.st2prop = function (stSelector) {
+            var colonPosition = stSelector.indexOf(':');
+            return colonPosition === -1 ? stSelector : stSelector.slice(0, colonPosition);
+        };
+    }
+
+    /* Adds AMD and requirejs related methods to the smalltalk object */
+    function AMDBrik(brikz, st) {
+        this.__init__ = function () {
+            st.amdRequire = require;
+            st.defaultTransportType = st.defaultTransportType || "amd";
+            st.defaultAmdNamespace = st.defaultAmdNamespace || "amber_core";
+        };
+    }
+
+    /* Defines asReceiver to be present at load time */
+    /* (logically it belongs more to PrimitiveBrik) */
+    function AsReceiverBrik(brikz, st) {
+
+        var nil = brikz.ensure("root").nil;
+
+        /**
+         * This function is used all over the compiled amber code.
+         * It takes any value (JavaScript or Smalltalk)
+         * and returns a proper Amber Smalltalk receiver.
+         *
+         * null or undefined -> nil,
+         * plain JS object -> wrapped JS object,
+         * otherwise unchanged
+         */
+        this.asReceiver = function (o) {
+            if (o == null) return nil;
+            if (typeof o === "object" || typeof o === "function") {
+                return o.klass != null ? o : globals.JSObjectProxy._on_(o);
+            }
+            // IMPORTANT: This optimization (return o if typeof !== "object")
+            // assumes all primitive types are wrapped by some Smalltalk class
+            // so they can be returned as-is, without boxing and looking for .klass.
+            // KEEP THE primitives-are-wrapped INVARIANT!
+            return o;
+        };
+    }
+
+
+    /* Making smalltalk that can load */
+
+    brikz.root = RootBrik;
+    brikz.dnu = DNUBrik;
+    brikz.organize = OrganizeBrik;
+    brikz.selectorConversion = SelectorConversionBrik;
+    brikz.classInit = ClassInitBrik;
+    brikz.manipulation = ManipulationBrik;
+    brikz.packages = PackagesBrik;
+    brikz.classes = ClassesBrik;
+    brikz.methods = MethodsBrik;
+    brikz.stInit = SmalltalkInitBrik;
+    brikz.augments = AugmentsBrik;
+    brikz.asReceiver = AsReceiverBrik;
+    brikz.amd = AMDBrik;
+
+    brikz.rebuild();
+
+    /* Making smalltalk that can run */
+
+    function runnable() {
+        brikz.messageSend = MessageSendBrik;
+        brikz.runtime = RuntimeBrik;
+        brikz.primitives = PrimitivesBrik;
+
+        brikz.rebuild();
+    }
+
+    return {api: api, nil: brikz.root.nil, globals: globals, asReceiver: brikz.asReceiver.asReceiver};
 });

+ 1 - 1
support/helpers.js

@@ -65,5 +65,5 @@ define("amber/helpers", ["amber/boot", "require"], function (boot, require) {
 
     // Exports
 
-    return  exports;
+    return exports;
 });