|
@@ -6,43 +6,7 @@
|
|
* var options = amberc.createDefaults();
|
|
* var options = amberc.createDefaults();
|
|
* // edit options entries
|
|
* // edit options entries
|
|
* compiler.main(options);
|
|
* compiler.main(options);
|
|
- *
|
|
|
|
- * Execute 'node compiler.js' without arguments or with -h / --help for help.
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * Map the async filter function onto array and evaluate callback, once all have finished.
|
|
|
|
- * Taken from: http://howtonode.org/control-flow-part-iii
|
|
|
|
*/
|
|
*/
|
|
-function async_map(array, filter, callback) {
|
|
|
|
- if (0 === array.length) {
|
|
|
|
- callback(null, null);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- var counter = array.length;
|
|
|
|
- var new_array = [];
|
|
|
|
- array.forEach(function (item, index) {
|
|
|
|
- filter(item, function (err, result) {
|
|
|
|
- if (err) { callback(err); return; }
|
|
|
|
- new_array[index] = result;
|
|
|
|
- counter--;
|
|
|
|
- if (counter === 0) {
|
|
|
|
- callback(null, new_array);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- });
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * Always evaluates the callback parameter.
|
|
|
|
- * Used by Combo blocks to always call the next function,
|
|
|
|
- * even if all of the other functions did not run.
|
|
|
|
- */
|
|
|
|
-function always_resolve(callback) {
|
|
|
|
- callback();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Helper for concatenating Amber generated AMD modules.
|
|
* Helper for concatenating Amber generated AMD modules.
|
|
@@ -92,38 +56,10 @@ function createConcatenator () {
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * Combine several async functions and evaluate callback once all of them have finished.
|
|
|
|
- * Taken from: http://howtonode.org/control-flow
|
|
|
|
- */
|
|
|
|
-function Combo(callback) {
|
|
|
|
- this.callback = callback;
|
|
|
|
- this.items = 0;
|
|
|
|
- this.results = [];
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-Combo.prototype = {
|
|
|
|
- add: function () {
|
|
|
|
- var self = this,
|
|
|
|
- id = this.items;
|
|
|
|
- this.items++;
|
|
|
|
- return function () {
|
|
|
|
- self.check(id, arguments);
|
|
|
|
- };
|
|
|
|
- },
|
|
|
|
- check: function (id, theArguments) {
|
|
|
|
- this.results[id] = Array.prototype.slice.call(theArguments);
|
|
|
|
- this.items--;
|
|
|
|
- if (this.items === 0) {
|
|
|
|
- this.callback.apply(this, this.results);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
|
|
|
|
var path = require('path'),
|
|
var path = require('path'),
|
|
- util = require('util'),
|
|
|
|
fs = require('fs'),
|
|
fs = require('fs'),
|
|
- exec = require('child_process').exec;
|
|
|
|
|
|
+ Promise = require('es6-promise').Promise;
|
|
|
|
|
|
/**
|
|
/**
|
|
* AmberC constructor function.
|
|
* AmberC constructor function.
|
|
@@ -146,7 +82,7 @@ function AmberC(amber_dir) {
|
|
/**
|
|
/**
|
|
* Default values.
|
|
* Default values.
|
|
*/
|
|
*/
|
|
-var createDefaults = function(finished_callback){
|
|
|
|
|
|
+var createDefaultConfiguration = function() {
|
|
return {
|
|
return {
|
|
'load': [],
|
|
'load': [],
|
|
'main': undefined,
|
|
'main': undefined,
|
|
@@ -164,23 +100,18 @@ var createDefaults = function(finished_callback){
|
|
'compiled': [],
|
|
'compiled': [],
|
|
'program': undefined,
|
|
'program': undefined,
|
|
'output_dir': undefined,
|
|
'output_dir': undefined,
|
|
- 'verbose': false,
|
|
|
|
- 'finished_callback': finished_callback
|
|
|
|
|
|
+ 'verbose': false
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Main function for executing the compiler.
|
|
* Main function for executing the compiler.
|
|
- * If check_configuration_ok() returns successfully the configuration is set on the current compiler
|
|
|
|
- * instance and check_for_closure_compiler() gets called.
|
|
|
|
- * The last step is to call collect_files().
|
|
|
|
|
|
+ * If check_configuration_ok() returns successfully
|
|
|
|
+ * the configuration is used to trigger the following compilation steps.
|
|
*/
|
|
*/
|
|
AmberC.prototype.main = function(configuration, finished_callback) {
|
|
AmberC.prototype.main = function(configuration, finished_callback) {
|
|
console.time('Compile Time');
|
|
console.time('Compile Time');
|
|
- if (undefined !== finished_callback) {
|
|
|
|
- configuration.finished_callback = finished_callback;
|
|
|
|
- }
|
|
|
|
|
|
|
|
if (configuration.amd_namespace.length === 0) {
|
|
if (configuration.amd_namespace.length === 0) {
|
|
configuration.amd_namespace = 'amber_core';
|
|
configuration.amd_namespace = 'amber_core';
|
|
@@ -196,115 +127,106 @@ AmberC.prototype.main = function(configuration, finished_callback) {
|
|
console.log = function() {};
|
|
console.log = function() {};
|
|
}
|
|
}
|
|
|
|
|
|
- if (this.check_configuration_ok(configuration)) {
|
|
|
|
- this.defaults = configuration;
|
|
|
|
- this.defaults.smalltalk = {}; // the evaluated compiler will be stored in this variable (see create_compiler)
|
|
|
|
- this.collect_files(this.defaults.stFiles, this.defaults.jsFiles)
|
|
|
|
- }
|
|
|
|
|
|
+ // the evaluated compiler will be stored in this variable (see create_compiler)
|
|
|
|
+ configuration.smalltalk = {};
|
|
|
|
+ configuration.kernel_libraries = this.kernel_libraries;
|
|
|
|
+ configuration.compiler_libraries = this.compiler_libraries;
|
|
|
|
+ configuration.amber_dir = this.amber_dir;
|
|
|
|
+
|
|
|
|
+ function logError(error) {
|
|
|
|
+ console.log(error);
|
|
|
|
+ finished_callback();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ check_configuration(configuration)
|
|
|
|
+ .then(collect_st_files, logError)
|
|
|
|
+ .then(collect_js_files, logError)
|
|
|
|
+ .then(resolve_kernel, logError)
|
|
|
|
+ .then(create_compiler, logError)
|
|
|
|
+ .then(compile, logError)
|
|
|
|
+ .then(category_export, logError)
|
|
|
|
+ .then(verify, logError)
|
|
|
|
+ .then(compose_js_files, logError)
|
|
|
|
+ .then(function() {
|
|
|
|
+ console.log = console.ambercLog;
|
|
|
|
+ console.timeEnd('Compile Time');
|
|
|
|
+ finished_callback();
|
|
|
|
+ });
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Check if the passed in configuration object has sufficient/nonconflicting values
|
|
|
|
|
|
+ * Check if the passed in configuration object has sufficient/nonconflicting values.
|
|
|
|
+ * Returns a Promise which resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.check_configuration_ok = function(configuration) {
|
|
|
|
- if (undefined === configuration) {
|
|
|
|
- throw new Error('AmberC.check_configuration_ok(): missing configuration object');
|
|
|
|
- }
|
|
|
|
|
|
+function check_configuration(configuration) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ if (undefined === configuration) {
|
|
|
|
+ reject(Error('AmberC.check_configuration_ok(): missing configuration object'));
|
|
|
|
+ }
|
|
|
|
|
|
- if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.length) {
|
|
|
|
- throw new Error('AmberC.check_configuration_ok(): no files to compile/link specified in configuration object');
|
|
|
|
- }
|
|
|
|
- return true;
|
|
|
|
|
|
+ if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.length) {
|
|
|
|
+ reject(Error('AmberC.check_configuration_ok(): no files to compile/link specified in configuration object'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ resolve(configuration);
|
|
|
|
+ });
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Check if the file given as parameter exists in any of the following directories:
|
|
* Check if the file given as parameter exists in any of the following directories:
|
|
* 1. current local directory
|
|
* 1. current local directory
|
|
- * 2. defauls.jsLibraryDirs
|
|
|
|
|
|
+ * 2. configuration.jsLibraryDirs
|
|
* 3. $AMBER/js/
|
|
* 3. $AMBER/js/
|
|
* 3. $AMBER/support/
|
|
* 3. $AMBER/support/
|
|
*
|
|
*
|
|
* @param filename name of a file without '.js' prefix
|
|
* @param filename name of a file without '.js' prefix
|
|
- * @param callback gets called on success with path to .js file as parameter
|
|
|
|
|
|
+ * @param configuration the main amberc configuration object
|
|
*/
|
|
*/
|
|
-AmberC.prototype.resolve_js = function(filename, callback) {
|
|
|
|
|
|
+function resolve_js(filename, configuration) {
|
|
var baseName = path.basename(filename, '.js');
|
|
var baseName = path.basename(filename, '.js');
|
|
- var jsFile = baseName + this.defaults.loadsuffix + '.js';
|
|
|
|
- var defaults = this.defaults;
|
|
|
|
- console.log('Resolving: ' + jsFile);
|
|
|
|
- fs.exists(jsFile, function(exists) {
|
|
|
|
- if (exists) {
|
|
|
|
- callback(jsFile);
|
|
|
|
- } else {
|
|
|
|
- var amberJsFile = '';
|
|
|
|
- // check for specified .js file in any of the directories from jsLibraryDirs
|
|
|
|
- var found = defaults.jsLibraryDirs.some(function(directory) {
|
|
|
|
- amberJsFile = path.join(directory, jsFile);
|
|
|
|
- return fs.existsSync(amberJsFile);
|
|
|
|
- });
|
|
|
|
- if (found) {
|
|
|
|
- callback(amberJsFile);
|
|
|
|
- } else {
|
|
|
|
- throw(new Error('JavaScript file not found: ' + jsFile));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ var jsFile = baseName + configuration.loadsuffix + '.js';
|
|
|
|
+ return resolve_file(jsFile, configuration.jsLibraryDirs);
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Collect libraries and Smalltalk files looking
|
|
|
|
- * both locally and in $AMBER/js and $AMBER/st.
|
|
|
|
- * Followed by resolve_libraries().
|
|
|
|
|
|
+ * Check if the file given as parameter exists in any of the following directories:
|
|
|
|
+ * 1. current local directory
|
|
|
|
+ * 2. $AMBER/
|
|
|
|
+ *
|
|
|
|
+ * @param filename name of a .st file
|
|
|
|
+ * @param configuration the main amberc configuration object
|
|
*/
|
|
*/
|
|
-AmberC.prototype.collect_files = function(stFiles, jsFiles) {
|
|
|
|
- var self = this;
|
|
|
|
- var collected_files = new Combo(function() {
|
|
|
|
- self.resolve_libraries();
|
|
|
|
- });
|
|
|
|
- if (0 !== stFiles.length) {
|
|
|
|
- self.collect_st_files(stFiles, collected_files.add());
|
|
|
|
- }
|
|
|
|
- if (0 !== jsFiles.length) {
|
|
|
|
- self.collect_js_files(jsFiles, collected_files.add());
|
|
|
|
- }
|
|
|
|
|
|
+function resolve_st(filename, configuration) {
|
|
|
|
+ return resolve_file(filename, [configuration.amber_dir]);
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Resolve st files given by stFiles and add them to defaults.compile.
|
|
|
|
- * Respective categories get added to defaults.compile_categories.
|
|
|
|
- * callback is evaluated afterwards.
|
|
|
|
|
|
+ * Resolve the location of a file given as parameter filename.
|
|
|
|
+ * First check if the file exists at given location,
|
|
|
|
+ * then check in each of the directories specified in parameter searchDirectories.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.collect_st_files = function(stFiles, callback) {
|
|
|
|
- var defaults = this.defaults;
|
|
|
|
- var self = this;
|
|
|
|
- var collected_st_files = new Combo(function() {
|
|
|
|
- Array.prototype.slice.call(arguments).forEach(function(data) {
|
|
|
|
- var stFile = data[0];
|
|
|
|
- defaults.compile.push(stFile);
|
|
|
|
- });
|
|
|
|
- callback();
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- stFiles.forEach(function(stFile) {
|
|
|
|
- var _callback = collected_st_files.add();
|
|
|
|
- console.log('Checking: ' + stFile);
|
|
|
|
- var amberStFile = path.join(self.amber_dir, 'st', stFile);
|
|
|
|
- fs.exists(stFile, function(exists) {
|
|
|
|
|
|
+function resolve_file(filename, searchDirectories) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ console.log('Resolving: ' + filename);
|
|
|
|
+ fs.exists(filename, function(exists) {
|
|
if (exists) {
|
|
if (exists) {
|
|
- _callback(stFile);
|
|
|
|
|
|
+ resolve(filename);
|
|
} else {
|
|
} else {
|
|
- console.log('Checking: ' + amberStFile);
|
|
|
|
- fs.exists(amberStFile, function(exists) {
|
|
|
|
- if (exists) {
|
|
|
|
- _callback(amberStFile);
|
|
|
|
- } else {
|
|
|
|
- throw(new Error('Smalltalk file not found: ' + amberStFile));
|
|
|
|
- }
|
|
|
|
|
|
+ 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));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
@@ -312,230 +234,240 @@ AmberC.prototype.collect_st_files = function(stFiles, callback) {
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Resolve js files given by jsFiles and add them to defaults.libraries.
|
|
|
|
- * callback is evaluated afterwards.
|
|
|
|
|
|
+ * Resolve st files given by stFiles and add them to configuration.compile.
|
|
|
|
+ * Returns a Promise which resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.collect_js_files = function(jsFiles, callback) {
|
|
|
|
- var self = this;
|
|
|
|
- var collected_js_files = new Combo(function() {
|
|
|
|
- Array.prototype.slice.call(arguments).forEach(function(file) {
|
|
|
|
- self.defaults.libraries.push(file[0]);
|
|
|
|
|
|
+function collect_st_files(configuration) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ Promise.all(
|
|
|
|
+ configuration.stFiles.map(function(stFile) {
|
|
|
|
+ return resolve_st(stFile, configuration);
|
|
|
|
+ })
|
|
|
|
+ ).then(function(data) {
|
|
|
|
+ configuration.compile = configuration.compile.concat(data);
|
|
|
|
+ resolve(configuration);
|
|
|
|
+ }, function(error) {
|
|
|
|
+ reject(error);
|
|
});
|
|
});
|
|
- callback();
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- jsFiles.forEach(function(jsFile) {
|
|
|
|
- self.resolve_js(jsFile, collected_js_files.add());
|
|
|
|
- });
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * Resolve kernel and compiler files.
|
|
|
|
- * Followed by resolve_init().
|
|
|
|
- */
|
|
|
|
-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.create_compiler(resolved_compiler_files[0]);
|
|
|
|
});
|
|
});
|
|
- this.resolve_kernel(all_resolved.add());
|
|
|
|
- this.resolve_compiler(all_resolved.add());
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Resolve .js files needed by kernel
|
|
|
|
- * callback is evaluated afterwards.
|
|
|
|
|
|
+ * Resolve js files given by jsFiles and add them to configuration.libraries.
|
|
|
|
+ * Returns a Promise which resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.resolve_kernel = function(callback) {
|
|
|
|
- var self = this;
|
|
|
|
- var kernel_files = this.kernel_libraries.concat(this.defaults.load);
|
|
|
|
- var kernel_resolved = new Combo(function() {
|
|
|
|
- var foundLibraries = [];
|
|
|
|
- Array.prototype.slice.call(arguments).forEach(function(file) {
|
|
|
|
- if (undefined !== file[0]) {
|
|
|
|
- foundLibraries.push(file[0]);
|
|
|
|
- }
|
|
|
|
|
|
+function collect_js_files(configuration) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ Promise.all(
|
|
|
|
+ configuration.jsFiles.map(function(file) {
|
|
|
|
+ return resolve_js(file, configuration);
|
|
|
|
+ })
|
|
|
|
+ ).then(function(data) {
|
|
|
|
+ configuration.libraries = configuration.libraries.concat(data);
|
|
|
|
+ resolve(configuration);
|
|
|
|
+ }, function(error) {
|
|
|
|
+ reject(error);
|
|
});
|
|
});
|
|
- // boot.js and Kernel files need to be used first
|
|
|
|
- // otherwise the global smalltalk object is undefined
|
|
|
|
- self.defaults.libraries = foundLibraries.concat(self.defaults.libraries);
|
|
|
|
- callback(null);
|
|
|
|
});
|
|
});
|
|
-
|
|
|
|
- kernel_files.forEach(function(file) {
|
|
|
|
- self.resolve_js(file, kernel_resolved.add());
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- always_resolve(kernel_resolved.add());
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Resolve .js files needed by compiler.
|
|
|
|
- * callback is evaluated afterwards with resolved files as argument.
|
|
|
|
|
|
+ * Resolve .js files needed by kernel.
|
|
|
|
+ * Returns a Promise which resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.resolve_compiler = function(callback) {
|
|
|
|
- // Resolve compiler libraries
|
|
|
|
- var compiler_files = this.compiler_libraries.concat(this.defaults.load);
|
|
|
|
- var compiler_resolved = new Combo(function() {
|
|
|
|
- var compilerFiles = [];
|
|
|
|
- Array.prototype.slice.call(arguments).forEach(function(file) {
|
|
|
|
- if (undefined !== file[0]) {
|
|
|
|
- compilerFiles.push(file[0]);
|
|
|
|
- }
|
|
|
|
|
|
+function resolve_kernel(configuration) {
|
|
|
|
+ var kernel_files = configuration.kernel_libraries.concat(configuration.load);
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ Promise.all(
|
|
|
|
+ kernel_files.map(function(file) {
|
|
|
|
+ return resolve_js(file, configuration, resolve);
|
|
|
|
+ })
|
|
|
|
+ ).then(function(data) {
|
|
|
|
+ // boot.js and Kernel files need to be used first
|
|
|
|
+ // otherwise the global smalltalk object is undefined
|
|
|
|
+ configuration.libraries = data.concat(configuration.libraries);
|
|
|
|
+ resolve(configuration);
|
|
|
|
+ }, function(error) {
|
|
|
|
+ reject(error);
|
|
});
|
|
});
|
|
- callback(compilerFiles);
|
|
|
|
- });
|
|
|
|
- var self = this;
|
|
|
|
- compiler_files.forEach(function(file) {
|
|
|
|
- self.resolve_js(file, compiler_resolved.add());
|
|
|
|
});
|
|
});
|
|
-
|
|
|
|
- always_resolve(compiler_resolved.add());
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Read all .js files needed by compiler and eval() them.
|
|
|
|
- * The finished Compiler gets stored in defaults.smalltalk.
|
|
|
|
- * Followed by compile().
|
|
|
|
|
|
+ * Resolve .js files needed by compiler, read and eval() them.
|
|
|
|
+ * The finished Compiler gets stored in configuration.smalltalk.
|
|
|
|
+ * Returns a Promise object which resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.create_compiler = function(compilerFilesArray) {
|
|
|
|
- var self = this;
|
|
|
|
- var compiler_files = new Combo(function() {
|
|
|
|
- var builder = createConcatenator();
|
|
|
|
- builder.add('(function() {');
|
|
|
|
- builder.start();
|
|
|
|
|
|
+function create_compiler(configuration) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ var compiler_files = configuration.compiler_libraries.concat(configuration.load);
|
|
|
|
+ Promise.all(
|
|
|
|
+ compiler_files.map(function(file) {
|
|
|
|
+ return resolve_js(file, configuration, resolve);
|
|
|
|
+ })
|
|
|
|
+ )
|
|
|
|
+ .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) {
|
|
|
|
+ var 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(/^define\("([^"]*)"/);
|
|
|
|
+ if (match) {
|
|
|
|
+ builder.addId(match[1]);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ // store the generated smalltalk env in configuration.smalltalk
|
|
|
|
+ builder.finish('configuration.smalltalk = smalltalk;');
|
|
|
|
+ builder.add('})();');
|
|
|
|
|
|
- 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]);
|
|
|
|
- // 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());
|
|
|
|
- console.log('Compiler loaded');
|
|
|
|
- self.defaults.smalltalk.ErrorHandler._setCurrent_(self.defaults.smalltalk.RethrowErrorHandler._new());
|
|
|
|
-
|
|
|
|
- if(0 !== self.defaults.jsGlobals.length) {
|
|
|
|
- var jsGlobalVariables = self.defaults.smalltalk.globalJsVariables;
|
|
|
|
- jsGlobalVariables.push.apply(jsGlobalVariables, self.defaults.jsGlobals);
|
|
|
|
- }
|
|
|
|
|
|
+ eval(builder.toString());
|
|
|
|
+ console.log('Compiler loaded');
|
|
|
|
+ configuration.smalltalk.ErrorHandler._setCurrent_(configuration.smalltalk.RethrowErrorHandler._new());
|
|
|
|
|
|
- self.compile();
|
|
|
|
- });
|
|
|
|
|
|
+ if(0 !== configuration.jsGlobals.length) {
|
|
|
|
+ var jsGlobalVariables = configuration.smalltalk.globalJsVariables;
|
|
|
|
+ jsGlobalVariables.push.apply(jsGlobalVariables, configuration.jsGlobals);
|
|
|
|
+ }
|
|
|
|
|
|
- compilerFilesArray.forEach(function(file) {
|
|
|
|
- console.log('Loading file: ' + file);
|
|
|
|
- fs.readFile(file, compiler_files.add());
|
|
|
|
|
|
+ resolve(configuration);
|
|
|
|
+ }, function(error) {
|
|
|
|
+ reject(Error('Error creating compiler'));
|
|
|
|
+ });
|
|
});
|
|
});
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Compile all given .st files by importing them.
|
|
* Compile all given .st files by importing them.
|
|
- * Followed by category_export().
|
|
|
|
|
|
+ * Returns a Promise object that resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.compile = function() {
|
|
|
|
- console.log('Compiling collected .st files');
|
|
|
|
- // import .st files
|
|
|
|
- var self = this;
|
|
|
|
- var imports = new Combo(function() {
|
|
|
|
- Array.prototype.slice.call(arguments).forEach(function(code) {
|
|
|
|
- if (undefined !== code[0]) {
|
|
|
|
- // get element 0 of code since all return values are stored inside an array by Combo
|
|
|
|
- var importer = self.defaults.smalltalk.Importer._new();
|
|
|
|
- try {
|
|
|
|
- importer._import_(code[0]._stream());
|
|
|
|
- } catch (ex) {
|
|
|
|
- throw new Error("Import error in section:\n" +
|
|
|
|
- importer._lastSection() +
|
|
|
|
- "\n\n" +
|
|
|
|
- "while processing chunk:\n" +
|
|
|
|
- importer._lastChunk() +
|
|
|
|
- "\n\n" +
|
|
|
|
- (ex._messageText && ex._messageText() || ex.message || ex));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+function compile(configuration) {
|
|
|
|
+ // return function which does the actual work
|
|
|
|
+ // and use the compile function to reference the configuration object
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ Promise.all(
|
|
|
|
+ configuration.compile.map(function(stFile) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ if (/\.st/.test(stFile)) {
|
|
|
|
+ console.ambercLog('Importing: ' + stFile);
|
|
|
|
+ fs.readFile(stFile, 'utf8', function(err, data) {
|
|
|
|
+ if (!err)
|
|
|
|
+ resolve(data);
|
|
|
|
+ else
|
|
|
|
+ reject(Error('Could not import: ' + stFile));
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ })
|
|
|
|
+ )
|
|
|
|
+ .then(function(fileContents) {
|
|
|
|
+ console.log('Compiling collected .st files');
|
|
|
|
+ // import/compile content of .st files
|
|
|
|
+ Promise.all(
|
|
|
|
+ fileContents.map(function(code) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ var importer = configuration.smalltalk.Importer._new();
|
|
|
|
+ try {
|
|
|
|
+ importer._import_(code._stream());
|
|
|
|
+ resolve(true);
|
|
|
|
+ } catch (ex) {
|
|
|
|
+ reject(Error("Import 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() {
|
|
|
|
+ resolve(configuration);
|
|
});
|
|
});
|
|
- self.category_export();
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.defaults.compile.forEach(function(stFile) {
|
|
|
|
- var callback = imports.add();
|
|
|
|
- if (/\.st/.test(stFile)) {
|
|
|
|
- console.ambercLog('Importing: ' + stFile);
|
|
|
|
- fs.readFile(stFile, 'utf8', function(err, data) {
|
|
|
|
- if (!err)
|
|
|
|
- callback(data);
|
|
|
|
- else
|
|
|
|
- throw new Error('Could not import: ' + stFile);
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
});
|
|
});
|
|
- always_resolve(imports.add());
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Export compiled categories to JavaScript files.
|
|
* Export compiled categories to JavaScript files.
|
|
- * Followed by verify().
|
|
|
|
|
|
+ * Returns a Promise() that resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.category_export = function() {
|
|
|
|
- var defaults = this.defaults;
|
|
|
|
- var self = this;
|
|
|
|
- // export categories as .js
|
|
|
|
- async_map(defaults.compile, function(stFile, callback) {
|
|
|
|
- var category = path.basename(stFile, '.st');
|
|
|
|
- var jsFilePath = defaults.output_dir;
|
|
|
|
- if (undefined === jsFilePath) {
|
|
|
|
- jsFilePath = path.dirname(stFile);
|
|
|
|
- }
|
|
|
|
- var jsFile = category + defaults.suffix_used + '.js';
|
|
|
|
- jsFile = path.join(jsFilePath, jsFile);
|
|
|
|
- defaults.compiled.push(jsFile);
|
|
|
|
- var smalltalk = defaults.smalltalk;
|
|
|
|
- var packageObject = smalltalk.Package._named_(category);
|
|
|
|
- packageObject._transport()._namespace_(defaults.amd_namespace);
|
|
|
|
- fs.writeFile(jsFile, smalltalk.String._streamContents_(function (stream) {
|
|
|
|
- smalltalk.AmdExporter._new()._exportPackage_on_(packageObject, stream); }), function(err) {
|
|
|
|
- callback(null, null);
|
|
|
|
- });
|
|
|
|
- }, function(err, result){
|
|
|
|
- self.verify();
|
|
|
|
|
|
+function category_export(configuration) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ 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 + configuration.suffix_used + '.js';
|
|
|
|
+ jsFile = path.join(jsFilePath, jsFile);
|
|
|
|
+ configuration.compiled.push(jsFile);
|
|
|
|
+ var smalltalk = configuration.smalltalk;
|
|
|
|
+ var packageObject = smalltalk.Package._named_(category);
|
|
|
|
+ packageObject._transport()._namespace_(configuration.amd_namespace);
|
|
|
|
+ fs.writeFile(jsFile, smalltalk.String._streamContents_(function (stream) {
|
|
|
|
+ smalltalk.AmdExporter._new()._exportPackage_on_(packageObject, stream);
|
|
|
|
+ }), function(err) {
|
|
|
|
+ if (err)
|
|
|
|
+ reject(err);
|
|
|
|
+ else
|
|
|
|
+ resolve(true);
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ })
|
|
|
|
+ ).then(function() {
|
|
|
|
+ resolve(configuration);
|
|
|
|
+ });
|
|
});
|
|
});
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* Verify if all .st files have been compiled.
|
|
* Verify if all .st files have been compiled.
|
|
- * Followed by compose_js_files().
|
|
|
|
|
|
+ * Returns a Promise() that resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.verify = function() {
|
|
|
|
|
|
+function verify(configuration) {
|
|
console.log('Verifying if all .st files were compiled');
|
|
console.log('Verifying if all .st files were compiled');
|
|
- var self = this;
|
|
|
|
- // copy array
|
|
|
|
- var compiledFiles = this.defaults.compiled.slice(0);
|
|
|
|
-
|
|
|
|
- async_map(compiledFiles,
|
|
|
|
- function(file, callback) {
|
|
|
|
- fs.exists(file, function(exists) {
|
|
|
|
- if (exists)
|
|
|
|
- callback(null, null);
|
|
|
|
- else
|
|
|
|
- throw(new Error('Compilation failed of: ' + file));
|
|
|
|
- });
|
|
|
|
- }, function(err, result) {
|
|
|
|
- self.compose_js_files();
|
|
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ 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() {
|
|
|
|
+ resolve(configuration);
|
|
|
|
+ });
|
|
});
|
|
});
|
|
};
|
|
};
|
|
|
|
|
|
@@ -543,88 +475,89 @@ AmberC.prototype.verify = function() {
|
|
/**
|
|
/**
|
|
* Synchronous function.
|
|
* Synchronous function.
|
|
* Concatenates compiled JavaScript files into one file in the correct order.
|
|
* Concatenates compiled JavaScript files into one file in the correct order.
|
|
- * The name of the produced file is given by defaults.program (set by the last commandline option).
|
|
|
|
|
|
+ * The name of the produced file is given by configuration.program.
|
|
|
|
+ * Returns a Promise which resolves into the configuration object.
|
|
*/
|
|
*/
|
|
-AmberC.prototype.compose_js_files = function() {
|
|
|
|
- var defaults = this.defaults;
|
|
|
|
- var programFile = defaults.program;
|
|
|
|
- if (undefined === programFile) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- if (undefined !== defaults.output_dir) {
|
|
|
|
- programFile = path.join(defaults.output_dir, programFile);
|
|
|
|
- }
|
|
|
|
|
|
+function compose_js_files(configuration) {
|
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
|
+ var programFile = configuration.program;
|
|
|
|
+ if (undefined === programFile) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (undefined !== configuration.output_dir) {
|
|
|
|
+ programFile = path.join(configuration.output_dir, programFile);
|
|
|
|
+ }
|
|
|
|
|
|
- var program_files = [];
|
|
|
|
- if (0 !== defaults.libraries.length) {
|
|
|
|
- console.log('Collecting libraries: ' + defaults.libraries);
|
|
|
|
- program_files.push.apply(program_files, defaults.libraries);
|
|
|
|
- }
|
|
|
|
|
|
+ var program_files = [];
|
|
|
|
+ if (0 !== configuration.libraries.length) {
|
|
|
|
+ console.log('Collecting libraries: ' + configuration.libraries);
|
|
|
|
+ program_files.push.apply(program_files, configuration.libraries);
|
|
|
|
+ }
|
|
|
|
|
|
- if (0 !== defaults.compiled.length) {
|
|
|
|
- var compiledFiles = defaults.compiled.slice(0);
|
|
|
|
|
|
+ if (0 !== configuration.compiled.length) {
|
|
|
|
+ var compiledFiles = configuration.compiled.slice(0);
|
|
|
|
|
|
- console.log('Collecting compiled files: ' + compiledFiles);
|
|
|
|
- program_files.push.apply(program_files, compiledFiles);
|
|
|
|
- }
|
|
|
|
|
|
+ console.log('Collecting compiled files: ' + compiledFiles);
|
|
|
|
+ program_files.push.apply(program_files, compiledFiles);
|
|
|
|
+ }
|
|
|
|
|
|
- console.ambercLog('Writing program file: %s.js', programFile);
|
|
|
|
|
|
+ console.ambercLog('Writing program file: %s.js', programFile);
|
|
|
|
|
|
- var fileStream = fs.createWriteStream(programFile + defaults.suffix_used + '.js');
|
|
|
|
- fileStream.on('error', function(error) {
|
|
|
|
- fileStream.end();
|
|
|
|
- console.ambercLog(error);
|
|
|
|
- });
|
|
|
|
|
|
+ var fileStream = fs.createWriteStream(programFile + configuration.suffix_used + '.js');
|
|
|
|
+ fileStream.on('error', function(error) {
|
|
|
|
+ fileStream.end();
|
|
|
|
+ console.ambercLog(error);
|
|
|
|
+ });
|
|
|
|
|
|
- fileStream.on('close', function(){
|
|
|
|
- return;
|
|
|
|
- });
|
|
|
|
|
|
+ fileStream.on('close', function(){
|
|
|
|
+ return;
|
|
|
|
+ });
|
|
|
|
|
|
- var builder = createConcatenator();
|
|
|
|
- builder.add('#!/usr/bin/env node');
|
|
|
|
- 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]);
|
|
|
|
|
|
+ var builder = createConcatenator();
|
|
|
|
+ builder.add('#!/usr/bin/env node');
|
|
|
|
+ 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]);
|
|
|
|
+ }
|
|
|
|
+ builder.add(buffer);
|
|
|
|
+ } else {
|
|
|
|
+ fileStream.end();
|
|
|
|
+ reject(Error('Can not find file ' + file));
|
|
}
|
|
}
|
|
- builder.add(buffer);
|
|
|
|
- } else {
|
|
|
|
- fileStream.end();
|
|
|
|
- throw(new Error('Can not find file ' + file));
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ });
|
|
|
|
|
|
- var mainFunctionOrFile = '';
|
|
|
|
|
|
+ var mainFunctionOrFile = '';
|
|
|
|
|
|
- if (undefined !== defaults.main) {
|
|
|
|
- console.log('Adding call to: %s>>main', defaults.main);
|
|
|
|
- mainFunctionOrFile += 'smalltalk.' + defaults.main + '._main();';
|
|
|
|
- }
|
|
|
|
|
|
+ if (undefined !== configuration.main) {
|
|
|
|
+ console.log('Adding call to: %s>>main', configuration.main);
|
|
|
|
+ mainFunctionOrFile += 'smalltalk.' + configuration.main + '._main();';
|
|
|
|
+ }
|
|
|
|
|
|
- if (undefined !== defaults.mainfile && fs.existsSync(defaults.mainfile)) {
|
|
|
|
- console.log('Adding main file: ' + defaults.mainfile);
|
|
|
|
- mainFunctionOrFile += '\n' + fs.readFileSync(defaults.mainfile);
|
|
|
|
- }
|
|
|
|
|
|
+ if (undefined !== configuration.mainfile && fs.existsSync(configuration.mainfile)) {
|
|
|
|
+ console.log('Adding main file: ' + configuration.mainfile);
|
|
|
|
+ mainFunctionOrFile += '\n' + fs.readFileSync(configuration.mainfile);
|
|
|
|
+ }
|
|
|
|
|
|
- builder.finish(mainFunctionOrFile);
|
|
|
|
|
|
+ builder.finish(mainFunctionOrFile);
|
|
|
|
|
|
- console.log('Writing...');
|
|
|
|
- builder.forEach(function (element) {
|
|
|
|
- fileStream.write(element);
|
|
|
|
- fileStream.write('\n');
|
|
|
|
|
|
+ console.log('Writing...');
|
|
|
|
+ builder.forEach(function (element) {
|
|
|
|
+ fileStream.write(element);
|
|
|
|
+ fileStream.write('\n');
|
|
|
|
+ });
|
|
|
|
+ console.log('Done.');
|
|
|
|
+ fileStream.end();
|
|
|
|
+ resolve(configuration);
|
|
});
|
|
});
|
|
- console.log('Done.');
|
|
|
|
- fileStream.end();
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
module.exports.Compiler = AmberC;
|
|
module.exports.Compiler = AmberC;
|
|
-module.exports.createDefaults = createDefaults;
|
|
|
|
-module.exports.Combo = Combo;
|
|
|
|
-module.exports.map = async_map;
|
|
|
|
|
|
+module.exports.createDefaultConfiguration = createDefaultConfiguration;
|