|  | @@ -43,36 +43,70 @@ function always_resolve(callback) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  | - * Helper for concatenation modules and producing output
 | 
	
		
			
				|  |  | - * that can be actually run.
 | 
	
		
			
				|  |  | + * Helper for concatenating Amber generated AMD modules.
 | 
	
		
			
				|  |  | + * The produced output can be exported and run as an independent program.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * var concatenator = createConcatenator();
 | 
	
		
			
				|  |  | + * concatenator.start(); // write the required AMD define header
 | 
	
		
			
				|  |  | + * concatenator.add(module1);
 | 
	
		
			
				|  |  | + * concatenator.addId(module1_ID);
 | 
	
		
			
				|  |  | + * //...
 | 
	
		
			
				|  |  | + * concatenator.finish("//some last code");
 | 
	
		
			
				|  |  | + * var concatenation = concatenator.toString();
 | 
	
		
			
				|  |  | + * // The variable concatenation contains the concatenated result
 | 
	
		
			
				|  |  | + * // which can either be stored in a file or interpreted with eval().
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -function makeBuilder () {
 | 
	
		
			
				|  |  | -	var defineDefine = function () {
 | 
	
		
			
				|  |  | +function createConcatenator () {
 | 
	
		
			
				|  |  | +	var defineAmdDefine = function () {
 | 
	
		
			
				|  |  |  		var path = require('path');
 | 
	
		
			
				|  |  | -		return ($SRC$)(module);
 | 
	
		
			
				|  |  | +		return ($AMDEFINE_SRC$)(module);
 | 
	
		
			
				|  |  |  	};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	// The createAmdefineString is hack to help injecting amdefine into the concatenated output.
 | 
	
		
			
				|  |  | +	//
 | 
	
		
			
				|  |  | +	// Usually, the line 'var define = require('amdefine')(module), requirejs = define.require;'
 | 
	
		
			
				|  |  | +	// is needed when using amdefine with node and npm installed.
 | 
	
		
			
				|  |  | +	// var f = require('amdefine') itself returns one big self-sufficient function which must be called
 | 
	
		
			
				|  |  | +	// as f(module) to get the define you can use.
 | 
	
		
			
				|  |  | +	//
 | 
	
		
			
				|  |  | +	// However, amdefine needs the definition of the 'path' variable (node's internal 'path' module).
 | 
	
		
			
				|  |  | +	// To create this dependency the defineAmdDefine() function is used which defines
 | 
	
		
			
				|  |  | +	// the path variable first and adds a placeholder for the amdefine function/sourcecode.
 | 
	
		
			
				|  |  | +	// The defineAmdDefine() function is then converted to its string representation
 | 
	
		
			
				|  |  | +	// and the placeholder is replaced with the actual sourcecode of the amdefine function.
 | 
	
		
			
				|  |  | +	var createAmdefineString = function() {
 | 
	
		
			
				|  |  | +		return ('' + defineAmdDefine).replace('$AMDEFINE_SRC$', '' + require('amdefine'));
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	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); },
 | 
	
		
			
				|  |  | +		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 = ('+(''+defineDefine).replace('$SRC$', ""+require('amdefine'))+')(), requirejs = define.require;',
 | 
	
		
			
				|  |  | +				'var define = (' + createAmdefineString() + ')(), requirejs = define.require;',
 | 
	
		
			
				|  |  |  				'define("amber_vm/browser-compatibility", [], {});'
 | 
	
		
			
				|  |  |  			);
 | 
	
		
			
				|  |  |  		},
 | 
	
		
			
				|  |  |  		finish: function (realWork) {
 | 
	
		
			
				|  |  |  			this.add(
 | 
	
		
			
				|  |  | -				'define("amber_vm/_init", ["amber_vm/smalltalk","'+this.ids.join('","')+'"], function (smalltalk) {',
 | 
	
		
			
				|  |  | +				'define("amber_vm/_init", ["amber_vm/smalltalk","' + this.ids.join('","') + '"], function (smalltalk) {',
 | 
	
		
			
				|  |  |  				'smalltalk.initialize();',
 | 
	
		
			
				|  |  |  				realWork,
 | 
	
		
			
				|  |  |  				'});', 'requirejs("amber_vm/_init");'
 | 
	
		
			
				|  |  |  			);
 | 
	
		
			
				|  |  |  		},
 | 
	
		
			
				|  |  | -		toString: function () { return this.elements.join('\n'); }
 | 
	
		
			
				|  |  | +		toString: function () {
 | 
	
		
			
				|  |  | +			return this.elements.join('\n');
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  |  	};
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -81,27 +115,27 @@ function makeBuilder () {
 | 
	
		
			
				|  |  |   * Taken from: http://howtonode.org/control-flow
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  function Combo(callback) {
 | 
	
		
			
				|  |  | -  this.callback = callback;
 | 
	
		
			
				|  |  | -  this.items = 0;
 | 
	
		
			
				|  |  | -  this.results = [];
 | 
	
		
			
				|  |  | +	this.callback = callback;
 | 
	
		
			
				|  |  | +	this.items = 0;
 | 
	
		
			
				|  |  | +	this.results = [];
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  Combo.prototype = {
 | 
	
		
			
				|  |  | -  add: function () {
 | 
	
		
			
				|  |  | -	var self = this,
 | 
	
		
			
				|  |  | +	add: function () {
 | 
	
		
			
				|  |  | +		var self = this,
 | 
	
		
			
				|  |  |  		id = this.items;
 | 
	
		
			
				|  |  | -	this.items++;
 | 
	
		
			
				|  |  | -	return function () {
 | 
	
		
			
				|  |  | -	  self.check(id, arguments);
 | 
	
		
			
				|  |  | -	};
 | 
	
		
			
				|  |  | -  },
 | 
	
		
			
				|  |  | -  check: function (id, arguments) {
 | 
	
		
			
				|  |  | -	this.results[id] = Array.prototype.slice.call(arguments);
 | 
	
		
			
				|  |  | -	this.items--;
 | 
	
		
			
				|  |  | -	if (this.items == 0) {
 | 
	
		
			
				|  |  | -	  this.callback.apply(this, this.results);
 | 
	
		
			
				|  |  | +		this.items++;
 | 
	
		
			
				|  |  | +		return function () {
 | 
	
		
			
				|  |  | +			self.check(id, arguments);
 | 
	
		
			
				|  |  | +		};
 | 
	
		
			
				|  |  | +	},
 | 
	
		
			
				|  |  | +	check: function (id, arguments) {
 | 
	
		
			
				|  |  | +		this.results[id] = Array.prototype.slice.call(arguments);
 | 
	
		
			
				|  |  | +		this.items--;
 | 
	
		
			
				|  |  | +		if (this.items == 0) {
 | 
	
		
			
				|  |  | +			this.callback.apply(this, this.results);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  var path = require('path'),
 | 
	
	
		
			
				|  | @@ -135,7 +169,6 @@ var createDefaults = function(amber_dir, finished_callback){
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	return {
 | 
	
		
			
				|  |  |  		'load': [],
 | 
	
		
			
				|  |  | -//		'init': path.join(amber_dir, 'js', 'init.js'),
 | 
	
		
			
				|  |  |  		'main': undefined,
 | 
	
		
			
				|  |  |  		'mainfile': undefined,
 | 
	
		
			
				|  |  |  		'stFiles': [],
 | 
	
	
		
			
				|  | @@ -199,9 +232,6 @@ AmberC.prototype.check_configuration_ok = function(configuration) {
 | 
	
		
			
				|  |  |  	if (undefined === configuration) {
 | 
	
		
			
				|  |  |  		throw new Error('AmberC.check_configuration_ok(): missing configuration object');
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	if (undefined === configuration.init) {
 | 
	
		
			
				|  |  | -//		throw new Error('AmberC.check_configuration_ok(): init value missing in configuration object');
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.lenght) {
 | 
	
		
			
				|  |  |  		throw new Error('AmberC.check_configuration_ok(): no files to compile/link specified in configuration object');
 | 
	
	
		
			
				|  | @@ -259,10 +289,12 @@ AmberC.prototype.check_for_closure_compiler = function(callback) {
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  AmberC.prototype.resolve_js = function(filename, callback) {
 | 
	
		
			
				|  |  |  	var special = filename[0] == "@";
 | 
	
		
			
				|  |  | -	if (special) { filename = filename.slice(1); }
 | 
	
		
			
				|  |  | +	if (special) {
 | 
	
		
			
				|  |  | +		filename = filename.slice(1);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  	var baseName = path.basename(filename, '.js');
 | 
	
		
			
				|  |  |  	var jsFile = baseName + this.defaults.loadsuffix + '.js';
 | 
	
		
			
				|  |  | -	var amberJsFile = path.join(this.amber_dir, special?'js/lib':'js', jsFile);
 | 
	
		
			
				|  |  | +	var amberJsFile = path.join(this.amber_dir, (special ? 'js/lib' : 'js'), jsFile);
 | 
	
		
			
				|  |  |  	console.log('Resolving: ' + jsFile);
 | 
	
		
			
				|  |  |  	fs.exists(jsFile, function(exists) {
 | 
	
		
			
				|  |  |  		if (exists) {
 | 
	
	
		
			
				|  | @@ -364,7 +396,7 @@ AmberC.prototype.resolve_libraries = function() {
 | 
	
		
			
				|  |  |  	// Resolve libraries listed in this.kernel_libraries
 | 
	
		
			
				|  |  |  	var self = this;
 | 
	
		
			
				|  |  |  	var all_resolved = new Combo(function(resolved_kernel_files, resolved_compiler_files) {
 | 
	
		
			
				|  |  | -		self.resolve_init(resolved_compiler_files[0]);
 | 
	
		
			
				|  |  | +		self.create_compiler(resolved_compiler_files[0]);
 | 
	
		
			
				|  |  |  	});
 | 
	
		
			
				|  |  |  	this.resolve_kernel(all_resolved.add());
 | 
	
		
			
				|  |  |  	this.resolve_compiler(all_resolved.add());
 | 
	
	
		
			
				|  | @@ -424,23 +456,6 @@ AmberC.prototype.resolve_compiler = function(callback) {
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * Resolves default.init and adds it to compilerFiles.
 | 
	
		
			
				|  |  | - * Followed by create_compiler().
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -AmberC.prototype.resolve_init = function(compilerFiles) {
 | 
	
		
			
				|  |  | -	// check and add init.js
 | 
	
		
			
				|  |  | -//	var initFile = this.defaults.init;
 | 
	
		
			
				|  |  | -//	if ('.js' !== path.extname(initFile)) {
 | 
	
		
			
				|  |  | -//		initFile = this.resolve_js(initFile);
 | 
	
		
			
				|  |  | -//		this.defaults.init = initFile;
 | 
	
		
			
				|  |  | -//	}
 | 
	
		
			
				|  |  | -//	compilerFiles.push(initFile);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	this.create_compiler(compilerFiles);
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * Read all .js files needed by compiler and eval() them.
 | 
	
		
			
				|  |  |   * The finished Compiler gets stored in defaults.smalltalk.
 | 
	
	
		
			
				|  | @@ -449,16 +464,20 @@ AmberC.prototype.resolve_init = function(compilerFiles) {
 | 
	
		
			
				|  |  |  AmberC.prototype.create_compiler = function(compilerFilesArray) {
 | 
	
		
			
				|  |  |  	var self = this;
 | 
	
		
			
				|  |  |  	var compiler_files = new Combo(function() {
 | 
	
		
			
				|  |  | -		var builder = makeBuilder();
 | 
	
		
			
				|  |  | +		var builder = createConcatenator();
 | 
	
		
			
				|  |  |  		builder.add('(function() {');
 | 
	
		
			
				|  |  |  		builder.start();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		Array.prototype.slice.call(arguments).forEach(function(data) {
 | 
	
		
			
				|  |  |  			// data is an array where index 0 is the error code and index 1 contains the data
 | 
	
		
			
				|  |  |  			builder.add(data[1]);
 | 
	
		
			
				|  |  | -			var match = (""+data[1]).match(/^define\("([^"]*)"/);
 | 
	
		
			
				|  |  | -			if (match) builder.addId(match[1]);
 | 
	
		
			
				|  |  | +			// matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
 | 
	
		
			
				|  |  | +			var match = ('' + data[1]).match(/^define\("([^"]*)"/);
 | 
	
		
			
				|  |  | +			if (match) {
 | 
	
		
			
				|  |  | +				builder.addId(match[1]);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  		});
 | 
	
		
			
				|  |  | +		// store the generated smalltalk env in self.defaults.smalltalk
 | 
	
		
			
				|  |  |  		builder.finish('self.defaults.smalltalk = smalltalk;');
 | 
	
		
			
				|  |  |  		builder.add('})();');
 | 
	
		
			
				|  |  |  		eval(builder.toString());
 | 
	
	
		
			
				|  | @@ -614,11 +633,6 @@ AmberC.prototype.compose_js_files = function() {
 | 
	
		
			
				|  |  |  		program_files.push.apply(program_files, compiledFiles);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if (undefined !== defaults.init) {
 | 
	
		
			
				|  |  | -//		console.log('Adding initializer ' + defaults.init);
 | 
	
		
			
				|  |  | -//		program_files.push(defaults.init);
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  	console.ambercLog('Writing program file: %s.js', programFile);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	var fileStream = fs.createWriteStream(programFile + defaults.suffix_used + '.js');
 | 
	
	
		
			
				|  | @@ -631,15 +645,18 @@ AmberC.prototype.compose_js_files = function() {
 | 
	
		
			
				|  |  |  		self.optimize();
 | 
	
		
			
				|  |  |  	});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	var builder = makeBuilder();
 | 
	
		
			
				|  |  | +	var builder = createConcatenator();
 | 
	
		
			
				|  |  |  	builder.start();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	program_files.forEach(function(file) {
 | 
	
		
			
				|  |  |  		if(fs.existsSync(file)) {
 | 
	
		
			
				|  |  |  			console.log('Adding : ' + file);
 | 
	
		
			
				|  |  |  			var buffer = fs.readFileSync(file);
 | 
	
		
			
				|  |  | +			// matches and returns the "module_id" string in the AMD define: define("module_id", ...)
 | 
	
		
			
				|  |  |  			var match = buffer.toString().match(/^define\("([^"]*)"/);
 | 
	
		
			
				|  |  | -			if (match /*&& match[1].slice(0,9) !== "amber_vm/"*/) { builder.addId(match[1]); }
 | 
	
		
			
				|  |  | +			if (match /*&& match[1].slice(0,9) !== "amber_vm/"*/) {
 | 
	
		
			
				|  |  | +				builder.addId(match[1]);
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  			builder.add(buffer);
 | 
	
		
			
				|  |  |  		} else {
 | 
	
		
			
				|  |  |  			fileStream.end();
 | 
	
	
		
			
				|  | @@ -647,22 +664,25 @@ AmberC.prototype.compose_js_files = function() {
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	var realWork = '';
 | 
	
		
			
				|  |  | +	var mainFunctionOrFile = '';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (undefined !== defaults.main) {
 | 
	
		
			
				|  |  |  		console.log('Adding call to: %s>>main', defaults.main);
 | 
	
		
			
				|  |  | -		realWork += 'smalltalk.' + defaults.main + '._main();';
 | 
	
		
			
				|  |  | +		mainFunctionOrFile += 'smalltalk.' + defaults.main + '._main();';
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (undefined !== defaults.mainfile && fs.existsSync(defaults.mainfile)) {
 | 
	
		
			
				|  |  |  		console.log('Adding main file: ' + defaults.mainfile);
 | 
	
		
			
				|  |  | -		realWork += '\n' + fs.readFileSync(defaults.mainfile);
 | 
	
		
			
				|  |  | +		mainFunctionOrFile += '\n' + fs.readFileSync(defaults.mainfile);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	builder.finish(realWork);
 | 
	
		
			
				|  |  | +	builder.finish(mainFunctionOrFile);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	console.log('Writing...');
 | 
	
		
			
				|  |  | -	builder.forEach(function (element) { fileStream.write(element); fileStream.write('\n'); });
 | 
	
		
			
				|  |  | +	builder.forEach(function (element) {
 | 
	
		
			
				|  |  | +		fileStream.write(element);
 | 
	
		
			
				|  |  | +		fileStream.write('\n');
 | 
	
		
			
				|  |  | +	});
 | 
	
		
			
				|  |  |  	console.log('Done.');
 | 
	
		
			
				|  |  |  	fileStream.end();
 | 
	
		
			
				|  |  |  };
 |