Browse Source

Merge pull request #280 from mkroehnert/amberc

new amberc.js compiler + small fixes for server and repl projects
Nicolas Petton 12 years ago
parent
commit
c4f4a88495
10 changed files with 1464 additions and 596 deletions
  1. 10 350
      bin/amberc
  2. 761 0
      bin/amberc.js
  3. 353 0
      bin/amberc.sh
  4. 1 1
      js/Kernel-Objects.deploy.js
  5. 1 1
      js/Kernel-Objects.js
  6. 1 1
      repl/Makefile
  7. 1 1
      repl/REPL.js
  8. 322 228
      repl/amber.js
  9. 6 6
      server/FileServer.st
  10. 8 8
      server/server.js

+ 10 - 350
bin/amberc

@@ -1,353 +1,13 @@
-#!/bin/bash
-#
-# This is a "compiler" for Amber code. Run without arguments for help.
-#
-# Get Amber root directory from the location of this script so that
-# we can find the st and js directories etc.
+#!/usr/bin/env node
 
-# Earlier we used this but it does not work on Mac
-# Amber=$(readlink -f `dirname ${0}`/..)
-TARGET=`dirname ${0}`/..
-pushd . >/dev/null
-cd $TARGET
-AMBER="`\pwd -P`"
-popd >/dev/null
+var path = require('path');
+var amberc = require('./amberc.js');
 
-function usage {
-	cat <<ENDOFHELP
-Usage: $0 [-l lib1,lib2...] [-i file] [-m class] [-M file]
-          [-o] [-O|-A] [-d] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]
-
-   Will compile Amber files - either separately or into a runnable complete
-   program. If no .st files are listed only a linking stage is performed.
-   Files listed will be handled using these rules:
-
-   *.js
-     Files are linked (concatenated) in listed order.
-     If not found we look in $AMBER/js
-
-   *.st
-     Files are compiled into .js files before concatenated.
-     If not found we look in $AMBER/st.
-
-     NOTE: Each file is currently considered to be a fileout of a single class
-     category of the same name as the file!
-
-   If no Program is specified each given .st file will be compiled into
-   a .js file. Otherwise a <Program>.js file is linked together based on
-   the options:
-
-  -l library1,library2
-     Additionally add listed libraries (no spaces or .js) in listed order.
-
-  -i file
-     Add library initializer <file> instead of default $AMBER/js/init.js 
-
-  -m class
-     Add at end a call to #main in class <class>. 
-
-  -M file
-     Add at end javascript file <file> acting as main.
-        
-  -o
-     Optimize each js file using the Google closure compiler.
-     Using Closure compiler found at ~/compiler.jar    
-
-  -O
-     Optimize final <Program>.js using the Google closure compiler.
-     Using Closure compiler found at ~/compiler.jar
-
-  -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS
-
-  -d
-     Additionally export code for deploy - stripped from source etc.
-     Uses suffix ".deploy.js" in addition to any explicit given suffic using -s.
-
-  -s suffix
-     Add <suffix> to compiled js files so that File.st is compiled into
-     File.<suffix>.js.
-
-  -S suffix
-     Use <suffix> for all libraries accessed using -L or -l. This makes it possible
-     to have multiple flavors of Amber and libraries in the same place.
-
-
-     Example invocations:
-
-     Just compile Kernel-Objects.st to Kernel-Objects.js:
-
-        amberc Kernel-Objects.st
-
-     Compile Hello.st to Hello.js and create complete program called
-     Program.js and adding a call to class method #main in class Hello:
-
-        amberc -m Hello Hello.st Program
-
-     Compile two .st files into corresponding .js files,
-     and link with specific myboot.js, myKernel.js, myinit.js
-     and main.js and create complete program called Program.js:
-
-        amberc -M main.js myinit.js myboot.js myKernel.js Cat1.st Cat2.st Program
-
-ENDOFHELP
-	exit 1;
-}
-
-# Check we at least got one argument
-if [ -z $1 ] ; then
-   usage
-fi
-
-# Define our predefined library combinations
-KERNEL="boot Kernel-Objects Kernel-Classes Kernel-Methods Kernel-Collections Kernel-Exceptions Kernel-Transcript Kernel-Announcements"
-COMPILER="$KERNEL parser Compiler Compiler-Exceptions"
-
-# Predefined initializer
-INITIALIZER="$AMBER/js/init.js"
-
-# Default values
-ENV=
-INIT=$INITIALIZER
-MAIN=
-MAINFILE=
-BASE=$KERNEL
-LOAD=
-CLOSUREOPTS=
-# Ok, bad coding practice but hey, who would use such a suffix?
-SUFFIX=no-silly-suffix
-SUFFIXUSED=
-DEPLOY=false
-NODECOMPILE=nodecompile
-
-# Read options and shift them away
-while getopts "l:i:m:M:oOAds:S:h?" o; do
-case "$o" in
-   l) LOAD=$OPTARG;;
-   i) INIT=$OPTARG;;
-   m) MAIN=$OPTARG;;
-   M) MAINFILE=$OPTARG;;
-   o) CLOSURE=true
-      CLOSUREPARTS=true;;
-   O) CLOSURE=true
-      CLOSUREFULL=true;;
-   A) CLOSURE=true
-      CLOSUREOPTS="$CLOSUREOPTS --compilation_level ADVANCED_OPTIMIZATIONS"
-      CLOSUREFULL=true;;
-   d) DEPLOY=true;;
-   s) SUFFIX=$OPTARG
-      SUFFIXUSED=$SUFFIX;;
-   S) LOADSUFFIX=$OPTARG
-      SUFFIXUSED=$SUFFIX;;
-   h) usage;;
-   [?])  usage;;
-   esac
-done
-shift $(($OPTIND - 1))
-
-# Check for Closure compiler and Java
-if [ ! -z $CLOSURE ]; then
-  java > /dev/null
-  if [ $? -eq 0 ]; then 
-    if [ ! -f ~/compiler.jar ]; then
-      echo "Can not find Closure compiler at ~/compiler.jar"
-      exit 1
-    fi
-  else
-   echo "java is not installed and is needed for -O, -A or -o (Closure compiler)."
-   exit 1
-  fi
-fi
-
-# Function for looking up listed js files
-function resolvejs {
-  FNAME="$1$LOADSUFFIX.js"
-  if [ -f $FNAME ]; then
-    RESOLVED="$FNAME" 
-  else
-    if [ -f $AMBER/js/$FNAME ]; then
-      RESOLVED="$AMBER/js/$FNAME"
-    else
-      echo "Javascript file not found: $FNAME"
-      exit 1
-    fi
-  fi
-}
-
-# Resolve listed libraries in $BASE deparated by spaces
-for FILE in $BASE
-do
-   resolvejs $FILE
-   TOBASE="$TOBASE $RESOLVED"
-done
-
-# Resolve listed libraries in $LOAD separated by ,
-LOAD=${LOAD//,/\ }
-for FILE in $LOAD
-do
-   resolvejs $FILE
-   TOLOAD="$TOLOAD $RESOLVED"
-done
-
-# Resolve COMPILER
-for FILE in $COMPILER
-do
-   resolvejs $FILE
-   TOCOMPILER="$TOCOMPILER $RESOLVED"
-done
-
-# Add supplied libraries we have not already loaded (they are already resolved)
-#for FILE in $EXTRA
-#do
-#   resolvejs $FILE
-#   TOEXTRA="$TOEXTRA $RESOLVED"
-#done
-
-TOCOMPILER="$TOCOMPILER$TOLOAD"
-
-# Resolve init and nodecompile
-THEREST="init $AMBER/bin/$NODECOMPILE"
-for FILE in $THEREST
-do
-   resolvejs $FILE
-   TOCOMPILER="$TOCOMPILER $RESOLVED"
-done
-
-# Add supplied libraries
-LIBS="$TOBASE $TOLOAD"
-
-# Get a unique tempdir and make it get auto removed on exit
-TMPDIR=`mktemp -d amberc.XXXXXX 2>>/dev/null` ||\
-    TMPDIR=/tmp/amberc.$$.`date +%s` && mkdir -p $TMPDIR
-trap "rm -rf $TMPDIR" EXIT
-
-
-# --------------------------------------------------
-# Collect libraries and Smalltalk files looking
-# both locally and in $AMBER/js and $AMBER/st 
-# --------------------------------------------------
-PROGRAM=
-until [ "$*" = "" ]
-do
-  case $1 in
-     *.st)
-        CATEGORY=`basename $1 .st`
-        if [ -f "$1" ]; then
-           COMPILE="$COMPILE $1 $CATEGORY"
-           COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
-        else
-           if [ -f $AMBER/st/$1 ]; then
-             COMPILE="$COMPILE $AMBER/st/$1 $CATEGORY"
-             COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
-           else
-             echo "Amber file not found: $1"
-             exit 1
-           fi
-        fi
-        ;;
-
-     *.js)
-        resolvejs $1
-	LIBS="$LIBS $RESOLVED" 
-        ;;
-      *)
-        # Will end up being the last non js/st argument
-        PROGRAM=$1
-        ;;
-  esac
-  shift
-done
-
-# --------------------------------------------------
-# Actual compilation phase of collected .st files
-# --------------------------------------------------
-
-# Create compiler dynamically
-cat $TOCOMPILER > $TMPDIR/compiler.js
- 
-# Compile all collected .st files to .js
-echo "Loading libraries$TOCOMPILER and compiling ..."
-node $TMPDIR/compiler.js $DEPLOY $SUFFIX $COMPILE
-
-# Verify all .js files corresponding to .st files were created, otherwise exit
-IFS=" "
-for FILE in $COMPILED
-do
-  if [ ! -f "$FILE" ]; then
-    echo "Failed compilation of $FILE, exiting."
-    exit 1
-  fi 
-done
-
-if [ ! -z $CLOSUREPARTS ]; then
-  echo "Compiling all js files using Google closure compiler."
-
-  ALLJSFILES="$COMPILED $LIBS"
-  for FILE in $ALLJSFILES
-  do
-    mv $FILE $FILE.original
-    java -jar ~/compiler.jar $CLOSUREOPTS --js $FILE.original --js_output_file $FILE
-    rm $FILE.original
-  done
-fi
-
-
-if [ -z $PROGRAM ]; then
-  echo "Done."
-  exit 0
-fi
-
-# --------------------------------------------------
-# Now we start composing resulting javascript file.
-# --------------------------------------------------
-
-# Add collected libraries to libs.js file.
-if [ ! -z "$LIBS" ]; then
-  echo "Adding libraries $LIBS ..."
-  cat $LIBS > $TMPDIR/libs.js
-  LIBS=$TMPDIR/libs.js
-fi
-
-echo "Adding Amber code$COMPILED ..."
-
-# Check for init file
-if [ ! -z "$INIT" ]; then
-   if [ -f "$INIT" ]; then
-      echo "Adding initializer $INIT ..."
-   else
-      echo "Can not find init file $INIT, exiting."
-      exit 1
-   fi 
-fi
-
-# Check for adding main
-if [ ! -z "$MAIN" ]; then
-  echo "Adding call to $MAIN class >> main ..."
-  echo "smalltalk.$MAIN._main()" > $TMPDIR/main.js
-  MAIN=$TMPDIR/main.js
-fi
-
-# Check for adding main file
-if [ ! -z "$MAINFILE" ]; then
-   if [ -f "$MAINFILE" ]; then
-      echo "Adding main as $MAINFILE ..."
-   else
-      echo "Can not find main file $MAINFILE, exiting."
-      exit 1
-   fi 
-   MAIN=$MAINFILE
-fi
-
-# And finally concatenate Program.js
-echo "Writing $PROGRAM.js ..."
-cat $LIBS $COMPILED $INIT $MAIN > $PROGRAM.js
-echo "Done."
-
-
-if [ ! -z $CLOSUREFULL ]; then
-  echo "Compiling $PROGRAM.js file using Google closure compiler."
-  mv $PROGRAM.js $PROGRAM.js.original
-  java -jar ~/compiler.jar $CLOSUREOPTS --js $PROGRAM.js.original --js_output_file $PROGRAM.js
-  rm $PROGRAM.js.original
-  echo "Done."
-fi
+// Get Amber root directory from the location of this script so that
+// we can find the st and js directories etc.
+var amber_dir = path.normalize(path.join(path.dirname(process.argv[1]), '..'));
+// Get default location of compiler.jar
+var closure_jar = path.resolve(path.join(process.env['HOME'], 'compiler.jar'));
 
+var compiler = new amberc.Compiler(amber_dir, closure_jar);
+compiler.main();

+ 761 - 0
bin/amberc.js

@@ -0,0 +1,761 @@
+/**
+ * This is a "compiler" for Amber code.
+ * Put the following code into compiler.js:
+ *     var amberc = require('amberc');
+ *     var compiler = new amberc.Compiler('path/to/amber', ['/optional/path/to/compiler.jar]);
+ *     compiler.main();
+ *
+ * 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();
+}
+
+
+/**
+ * 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, 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'),
+	util = require('util'),
+	fs = require('fs'),
+	exec = require('child_process').exec;
+
+/**
+ * AmberC constructor function.
+ * amber_dir: points to the location of an amber installation
+ * closure_jar: location of compiler.jar (can be left undefined)
+ */
+function AmberC(amber_dir, closure_jar) {
+	this.amber_dir = amber_dir;
+	this.closure_jar = closure_jar;
+	this.kernel_libraries = ['boot', 'Kernel-Objects', 'Kernel-Classes', 'Kernel-Methods',
+	                         'Kernel-Collections', 'Kernel-Exceptions', 'Kernel-Transcript',
+	                         'Kernel-Announcements'];
+	this.compiler_libraries = this.kernel_libraries.concat(['parser', 'Compiler', 'Compiler-Exceptions']);
+	                          //, 'Compiler-Core', 'Compiler-AST', 'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic'];
+}
+
+
+/**
+ * Default values.
+ */
+var createDefaults = function(amber_dir, finished_callback){
+	return {
+		'smalltalk': {}, // the evaluated compiler will be stored in this variable (see create_compiler)
+		'load': [],
+		'init': path.join(amber_dir, 'js', 'init.js'),
+		'main': undefined,
+		'mainfile': undefined,
+		'closure': false,
+		'closure_parts': false,
+		'closure_full': false,
+		'closure_options': '',
+		'suffix': '',
+		'loadsuffix': '',
+		'suffix_used': '',
+		'deploy': false,
+		'libraries': [],
+		'compile': [],
+		'compiled_categories': [],
+		'compiled': [],
+		'program': undefined,
+		'finished_callback': finished_callback
+	};
+};
+
+
+/**
+ * Main function for executing the compiler.
+ */
+AmberC.prototype.main = function(parameters, finished_callback) {
+	console.time('Compile Time');
+	var options = parameters || process.argv.slice(2);
+
+	if (1 > options.length) {
+		this.usage();
+	} else {
+		this.defaults = createDefaults(this.amber_dir, finished_callback);
+		this.handle_options(options);
+	}
+};
+
+
+/**
+ * Process given program options and update defaults values.
+ * Followed by check_for_closure_compiler() and then collect_files().
+ */
+AmberC.prototype.handle_options = function(optionsArray) {
+	var stFiles = [];
+	var jsFiles = [];
+	var programName = [];
+	var currentItem = optionsArray.shift();
+	var defaults = this.defaults;
+
+	while(undefined !== currentItem) {
+		switch(currentItem) {
+			case '-l':
+				defaults.load.push.apply(defaults.load, optionsArray.shift().split(','));
+				break;
+			case '-i':
+				defaults.init = optionsArray.shift();
+				break;
+			case '-m':
+				defaults.main = optionsArray.shift();
+				break;
+			case '-M':
+				defaults.mainfile = optionsArray.shift();
+				break;
+			case '-o':
+				defaults.closure = true;
+				defaults.closure_parts = true;
+				break;
+			case '-O':
+				defaults.closure = true;
+				defaults.closure_full = true;
+				break;
+			case '-A':
+				defaults.closure = true;
+				defaults.closure_options = defaults.closure_options + ' --compilation_level ADVANCED_OPTIMIZATIONS';
+				defaults.closure_full = true;
+				break;
+			case '-d':
+				defaults.deploy = true;
+				break;
+			case '-s':
+				defaults.suffix = optionsArray.shift();
+				defaults.suffix_used = defaults.suffix;
+				break;
+			case '-S':
+				defaults.loadsuffix = optionsArray.shift();
+				defaults.suffix_used = defaults.suffix;
+				break;
+			case '-h':
+			case '--help':
+			case '?':
+				this.usage();
+				break;
+			default:
+				var fileSuffix = path.extname(currentItem);
+				switch (fileSuffix) {
+					case '.st':
+						stFiles.push(currentItem);
+						break;
+					case '.js':
+						jsFiles.push(currentItem);
+						break;
+					default:
+						// Will end up being the last non js/st argument
+						programName.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];
+	}
+
+	var self = this;
+	this.check_for_closure_compiler(function(){
+		self.collect_files(stFiles, jsFiles)
+	});
+};
+
+
+/**
+ * Print usage options and exit.
+ */
+AmberC.prototype.usage = function() {
+	console.log('Usage: amberc [-l lib1,lib2...] [-i init_file] [-m main_class] [-M main_file]');
+	console.log('          [-o] [-O|-A] [-d] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]');
+	console.log('');
+	console.log('   amberc compiles Amber files - either separately or into a complete runnable');
+	console.log('   program. If no .st files are listed only a linking stage is performed.');
+	console.log('   Files listed will be handled using the following rules:');
+	console.log('');
+	console.log('   *.js');
+	console.log('     Files are linked (concatenated) in listed order.');
+	console.log('     If not found we look in $AMBER/js/');
+	console.log('');
+	console.log('   *.st');
+	console.log('     Files are compiled into .js files before concatenation.');
+	console.log('     If not found we look in $AMBER/st/.');
+	console.log('');
+	console.log('     NOTE: Each .st file is currently considered to be a fileout of a single class');
+	console.log('     category of the same name as the file!');
+	console.log('');
+	console.log('   If no <Program> is specified each given .st file will be compiled into');
+	console.log('   a matching .js file. Otherwise a <Program>.js file is linked together based on');
+	console.log('   the given options:');
+	console.log('  -l library1,library2');
+	console.log('     Add listed JavaScript libraries in listed order.');
+	console.log('     Libraries are not separated by spaces or end with .js.');
+	console.log('');
+	console.log('  -i init_file');
+	console.log('     Add library initializer <init_file> instead of default $AMBER/js/init.js ');
+	console.log('');
+	console.log('  -m main_class');
+	console.log('     Add a call to the class method main_class>>main at the end of <Program>.');
+	console.log('');
+	console.log('  -M main_file');
+	console.log('     Add <main_file> at the end of <Program.js> acting as #main.');
+	console.log('');
+	console.log('  -o');
+	console.log('     Optimize each .js file using the Google closure compiler.');
+	console.log('     Using Closure compiler found at ~/compiler.jar');
+	console.log('');
+	console.log('  -O');
+	console.log('     Optimize final <Program>.js using the Google closure compiler.');
+	console.log('     Using Closure compiler found at ~/compiler.jar');
+	console.log('');
+	console.log('  -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS');
+	console.log('');
+	console.log('  -d');
+	console.log('     Additionally export code for deploy - stripped from source etc.');
+	console.log('     Uses suffix ".deploy.js" in addition to any explicit suffic set by -s.');
+	console.log('');
+	console.log('  -s suffix');
+	console.log('     Add <suffix> to compiled .js files. File.st is then compiled into');
+	console.log('     File.<suffix>.js.');
+	console.log('');
+	console.log('  -S suffix');
+	console.log('     Use <suffix> for all libraries accessed using -l. This makes it possible');
+	console.log('     to have multiple flavors of Amber and libraries in the same place.');
+	console.log('');
+	console.log('');
+	console.log('     Example invocations:');
+	console.log('');
+	console.log('     Just compile Kernel-Objects.st to Kernel-Objects.js:');
+	console.log('');
+	console.log('        amberc Kernel-Objects.st');
+	console.log('');
+	console.log('     Compile Hello.st to Hello.js and create complete program called Program.js.');
+	console.log('     Additionally add a call to the class method Hello>>main:');
+	console.log('');
+	console.log('        amberc -m Hello Hello.st Program');
+	console.log('');
+	console.log('     Compile Cat1.st and Cat2.st files into corresponding .js files.');
+	console.log('     Link them with myboot.js and myKernel.js and add myinit.js as custom');
+	console.log('     initializer file. Add main.js last which contains the startup code');
+	console.log('      and merge everything into a complete program named Program.js:');
+	console.log('');
+	console.log('        amberc -M main.js -i myinit.js myboot.js myKernel.js Cat1.st Cat2.st Program');
+
+	process.exit();
+};
+
+
+/**
+ * Checks if the java executable exists and afterwards,
+ * if compiler.jar exists at the path stored in this.closure_jar.
+ * All closure related entries are set to false upon failure.
+ *
+ * callback gets called in any case.
+ */
+AmberC.prototype.check_for_closure_compiler = function(callback) {
+	var defaults = this.defaults;
+	var self = this;
+	if (defaults.closure) {
+		exec('which java', function(error, stdout, stderr) {
+			// stdout contains path to java executable
+			if (null !== error) {
+				console.warn('java is not installed but is needed for -O, -A or -o (Closure compiler).');
+				defaults.closure = false;
+				defaults.closure_parts = false;
+				defaults.closure_full = false;
+				callback();
+				return;
+			}
+			path.exists(self.closure_jar, function(exists) {
+				if (!exists) {
+					console.warn('Can not find Closure compiler at: ' + self.closure_jar);
+					defaults.closure = false;
+					defaults.closure_parts = false;
+					defaults.closure_full = false;
+					callback();
+					return;
+				}
+			});
+		});
+	} else {
+		callback();
+	}
+};
+
+
+/**
+ * Check if the file given as parameter exists in the local directory or in $AMBER/js/.
+ * '.js' is appended first.
+ *
+ * @param filename name of a file without '.js' prefix
+ * @param callback gets called on success with path to .js file as parameter
+ */
+AmberC.prototype.resolve_js = function(filename, callback) {
+	var baseName = path.basename(filename, '.js');
+	var jsFile = baseName + this.defaults.loadsuffix + '.js';
+	var amberJsFile = path.join(this.amber_dir, 'js', jsFile);
+	console.log('Resolving: ' + jsFile);
+	path.exists(jsFile, function(exists) {
+		if (exists) {
+			callback(jsFile);
+		} else {
+			path.exists(amberJsFile, function(exists) {
+				if (exists) {
+					callback(amberJsFile);
+				} else {
+					throw(new Error('JavaScript file not found: ' + jsFile));
+				}
+			});
+		}
+	});
+};
+
+
+/**
+ * Collect libraries and Smalltalk files looking
+ * both locally and in $AMBER/js and $AMBER/st.
+ * Followed by resolve_libraries().
+ */
+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());
+	}
+};
+
+
+/**
+ * Resolve st files given by stFiles and add them to defaults.compile.
+ * Respective categories get added to defaults.compile_categories.
+ * callback is evaluated afterwards.
+ */
+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];
+			var stCategory = data[1];
+			defaults.compile.push(stFile);
+			defaults.compiled_categories.push(stCategory);
+			defaults.compiled.push(stCategory + defaults.suffix_used + '.js');
+		});
+		callback();
+	});
+
+	stFiles.forEach(function(stFile) {
+		var _callback = collected_st_files.add();
+		console.log('Checking: ' + stFile);
+		var category = path.basename(stFile, '.st');
+		var amberStFile = path.join(self.amber_dir, 'st', stFile);
+		path.exists(stFile, function(exists) {
+			if (exists) {
+				_callback(stFile, category);
+			} else {
+				path.exists(amberStFile, function(exists) {
+					if (exists) {
+						_callback(amberStFile, category);
+					} else {
+						throw(new Error('Smalltalk file not found: ' + amberStFile));
+					}
+				});
+			}
+		});
+	});
+};
+
+
+/**
+ * Resolve js files given by jsFiles and add them to defaults.libraries.
+ * callback is evaluated afterwards.
+ */
+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]);
+		});
+		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_library_files, resolved_compiler_files) {
+		self.resolve_init(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.
+ */
+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() {
+		Array.prototype.slice.call(arguments).forEach(function(file) {
+			if (undefined !== file[0]) {
+				self.defaults.libraries.push(file[0]);
+			}
+		});
+		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.
+ */
+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]);
+			}
+		});
+		callback(compilerFiles);
+	});
+	var self = this
+	compiler_files.forEach(function(file) {
+		self.resolve_js(file, compiler_resolved.add());
+	});
+
+	always_resolve(compiler_resolved.add());
+};
+
+
+/**
+ * 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.
+ * Followed by compile().
+ */
+AmberC.prototype.create_compiler = function(compilerFilesArray) {
+	var self = this;
+	var compiler_files = new Combo(function() {
+		var content = '(function() {';
+		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
+			content += data[1];
+		});
+		content = content + 'return smalltalk;})();';
+		self.defaults.smalltalk = eval(content);
+		console.log('Compiler loaded');
+
+		self.compile();
+	});
+
+	compilerFilesArray.forEach(function(file) {
+		console.log('Loading file: ' + file);
+		fs.readFile(file, compiler_files.add());
+	});
+};
+
+
+/**
+ * Compile all given .st files by importing them.
+ * Followed by category_export().
+ */
+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
+				self.defaults.smalltalk.Importer._new()._import_(code[0]._stream());
+			}
+		});
+		self.category_export();
+	});
+
+	this.defaults.compile.forEach(function(stFile) {
+		var callback = imports.add();
+		if (/\.st/.test(stFile)) {
+			console.log('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.
+ * Followed by verify().
+ */
+AmberC.prototype.category_export = function() {
+	var defaults = this.defaults;
+	var self = this;
+	// export categories as .js
+	async_map(defaults.compiled_categories, function(category, callback) {
+		var jsFile = category + defaults.suffix_used + '.js';
+		var jsFileDeploy = category + defaults.suffix_used + '.deploy.js';
+		console.log('Exporting ' + (defaults.deploy ? '(debug + deploy)' : '(debug)')
+			+ ' category ' + category + ' as ' + jsFile
+			+ (defaults.deploy ? ' and ' + jsFileDeploy : ''));
+		fs.writeFile(jsFile, defaults.smalltalk.Exporter._new()._exportPackage_(category), function(err) {
+			if (defaults.deploy) {
+				fs.writeFile(jsFileDeploy, defaults.smalltalk.StrippedExporter._new()._exportPackage_(category), callback);
+			} else {
+				callback(null, null);
+			}
+		});
+	}, function(err, result){
+		self.verify();
+	});
+};
+
+
+/**
+ * Verify if all .st files have been compiled.
+ * Followed by compose_js_files() and optimize().
+ */
+AmberC.prototype.verify = function() {
+	console.log('Verifying if all .st files were compiled');
+	var self = this;
+	async_map(this.defaults.compiled, function(file, callback) {
+			path.exists(file, function(exists) {
+				if (exists)
+					callback(null, null);
+				else
+					throw(new Error('Compilation failed of: ' + file));
+			});
+		}, function(err, result) {
+			self.compose_js_files();
+	});
+};
+
+
+/**
+ * Synchronous function.
+ * 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).
+ */
+AmberC.prototype.compose_js_files = function() {
+	var defaults = this.defaults;
+	if (undefined === defaults.program) {
+		return;
+	}
+	var program_files = [];
+
+	if (0 !== defaults.libraries.length) {
+		console.log('Collecting libraries: ' + defaults.libraries);
+		program_files.push.apply(program_files, defaults.libraries);
+	}
+
+	if (0 !== defaults.compiled.length) {
+		console.log('Collecting compiled files: ' + defaults.compiled);
+		program_files.push.apply(program_files, defaults.compiled);
+	}
+
+	if (undefined !== defaults.init) {
+		console.log('Adding initializer ' + defaults.init);
+		program_files.push(defaults.init);
+	}
+
+	console.log('Writing program file: %s.js', defaults.program);
+
+	var fileStream = fs.createWriteStream(defaults.program + defaults.suffix_used + '.js');
+	fileStream.on('error', function(error) {
+		fileStream.end();
+		console.log(error);
+	});
+	var self = this;
+	fileStream.on('close', function(){
+		self.optimize();
+	});
+
+	program_files.forEach(function(file) {
+		if(path.existsSync(file)) {
+			console.log('Adding : ' + file);
+			console.log(fileStream.write(fs.readFileSync(file)));
+		} else {
+			fileStream.end();
+			throw(new Error('Can not find file ' + file));
+		}
+	});
+	if (undefined !== defaults.main) {
+		console.log('Adding call to: %s>>main', defaults.main);
+		fileStream.write('smalltalk.' + defaults.main + '._main()');
+	}
+
+	if (undefined !== defaults.mainfile && path.existsSync(defaults.mainfile)) {
+		console.log('Adding main file: ' + defaults.mainfile);
+		fileStream.write(fs.readFileSync(defaults.mainfile));
+	}
+
+	console.log('Done.');
+	fileStream.end();
+};
+
+
+/**
+ * Optimize created JavaScript files with Google Closure compiler depending
+ * on the flags: defaults.closure_parts, defaults.closure_full.
+ */
+AmberC.prototype.optimize = function() {
+	var defaults = this.defaults;
+	var self = this;
+	var optimization_done = new Combo(function() {
+		console.timeEnd('Compile Time');
+		if (undefined !== defaults.finished_callback) {
+			defaults.finished_callback();
+		}
+	});
+
+	if (defaults.closure_parts) {
+		console.log('Compiling all js files using Google closure compiler.');
+		var allJsFiles = defaults.compiled.concat(defaults.libraries);
+		allJsFiles.forEach(function(file) {
+			var minifiedName = path.basename(file, '.js') + '.min.js';
+			self.closure_compile(file, minifiedName, optimization_done.add());
+		});
+	}
+	if (defaults.closure_full) {
+		console.log('Compiling ' + defaults.program + '.js file using Google closure compiler.');
+		self.closure_compile(defaults.program + '.js', defaults.program + '.min.js', optimization_done.add());
+	}
+
+	always_resolve(optimization_done.add());
+};
+
+
+/**
+ * Compile sourceFile into minifiedFile with Google Closure compiler.
+ * callback gets executed once finished.
+ */
+AmberC.prototype.closure_compile = function(sourceFile, minifiedFile, callback) {
+	// exec is asynchronous
+	var self = this;
+	exec(
+		'java -jar ' +
+		self.closure_jar + ' ' +
+		self.defaults.closure_options +
+		' --js '+ sourceFile +
+		' --js_output_file '+ minifiedFile,
+		function (error, stdout, stderr) {
+			if (error) {
+				console.log(stderr);
+			} else {
+				console.log(stdout);
+				console.log('Minified: '+ minifiedFile);
+			}
+			callback();
+		}
+	);
+};
+
+module.exports.Compiler = AmberC;
+module.exports.Combo = Combo;
+module.exports.map = async_map;

+ 353 - 0
bin/amberc.sh

@@ -0,0 +1,353 @@
+#!/bin/bash
+#
+# This is a "compiler" for Amber code. Run without arguments for help.
+#
+# Get Amber root directory from the location of this script so that
+# we can find the st and js directories etc.
+
+# Earlier we used this but it does not work on Mac
+# Amber=$(readlink -f `dirname ${0}`/..)
+TARGET=`dirname ${0}`/..
+pushd . >/dev/null
+cd $TARGET
+AMBER="`\pwd -P`"
+popd >/dev/null
+
+function usage {
+	cat <<ENDOFHELP
+Usage: $0 [-l lib1,lib2...] [-i file] [-m class] [-M file]
+          [-o] [-O|-A] [-d] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]
+
+   Will compile Amber files - either separately or into a runnable complete
+   program. If no .st files are listed only a linking stage is performed.
+   Files listed will be handled using these rules:
+
+   *.js
+     Files are linked (concatenated) in listed order.
+     If not found we look in $AMBER/js
+
+   *.st
+     Files are compiled into .js files before concatenated.
+     If not found we look in $AMBER/st.
+
+     NOTE: Each file is currently considered to be a fileout of a single class
+     category of the same name as the file!
+
+   If no Program is specified each given .st file will be compiled into
+   a .js file. Otherwise a <Program>.js file is linked together based on
+   the options:
+
+  -l library1,library2
+     Additionally add listed libraries (no spaces or .js) in listed order.
+
+  -i file
+     Add library initializer <file> instead of default $AMBER/js/init.js 
+
+  -m class
+     Add at end a call to #main in class <class>. 
+
+  -M file
+     Add at end javascript file <file> acting as main.
+        
+  -o
+     Optimize each js file using the Google closure compiler.
+     Using Closure compiler found at ~/compiler.jar    
+
+  -O
+     Optimize final <Program>.js using the Google closure compiler.
+     Using Closure compiler found at ~/compiler.jar
+
+  -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS
+
+  -d
+     Additionally export code for deploy - stripped from source etc.
+     Uses suffix ".deploy.js" in addition to any explicit given suffic using -s.
+
+  -s suffix
+     Add <suffix> to compiled js files so that File.st is compiled into
+     File.<suffix>.js.
+
+  -S suffix
+     Use <suffix> for all libraries accessed using -L or -l. This makes it possible
+     to have multiple flavors of Amber and libraries in the same place.
+
+
+     Example invocations:
+
+     Just compile Kernel-Objects.st to Kernel-Objects.js:
+
+        amberc Kernel-Objects.st
+
+     Compile Hello.st to Hello.js and create complete program called
+     Program.js and adding a call to class method #main in class Hello:
+
+        amberc -m Hello Hello.st Program
+
+     Compile two .st files into corresponding .js files,
+     and link with specific myboot.js, myKernel.js, myinit.js
+     and main.js and create complete program called Program.js:
+
+        amberc -M main.js myinit.js myboot.js myKernel.js Cat1.st Cat2.st Program
+
+ENDOFHELP
+	exit 1;
+}
+
+# Check we at least got one argument
+if [ -z $1 ] ; then
+   usage
+fi
+
+# Define our predefined library combinations
+KERNEL="boot Kernel-Objects Kernel-Classes Kernel-Methods Kernel-Collections Kernel-Exceptions Kernel-Transcript Kernel-Announcements"
+COMPILER="$KERNEL parser Compiler Compiler-Exceptions"
+
+# Predefined initializer
+INITIALIZER="$AMBER/js/init.js"
+
+# Default values
+ENV=
+INIT=$INITIALIZER
+MAIN=
+MAINFILE=
+BASE=$KERNEL
+LOAD=
+CLOSUREOPTS=
+# Ok, bad coding practice but hey, who would use such a suffix?
+SUFFIX=no-silly-suffix
+SUFFIXUSED=
+DEPLOY=false
+NODECOMPILE=nodecompile
+
+# Read options and shift them away
+while getopts "l:i:m:M:oOAds:S:h?" o; do
+case "$o" in
+   l) LOAD=$OPTARG;;
+   i) INIT=$OPTARG;;
+   m) MAIN=$OPTARG;;
+   M) MAINFILE=$OPTARG;;
+   o) CLOSURE=true
+      CLOSUREPARTS=true;;
+   O) CLOSURE=true
+      CLOSUREFULL=true;;
+   A) CLOSURE=true
+      CLOSUREOPTS="$CLOSUREOPTS --compilation_level ADVANCED_OPTIMIZATIONS"
+      CLOSUREFULL=true;;
+   d) DEPLOY=true;;
+   s) SUFFIX=$OPTARG
+      SUFFIXUSED=$SUFFIX;;
+   S) LOADSUFFIX=$OPTARG
+      SUFFIXUSED=$SUFFIX;;
+   h) usage;;
+   [?])  usage;;
+   esac
+done
+shift $(($OPTIND - 1))
+
+# Check for Closure compiler and Java
+if [ ! -z $CLOSURE ]; then
+  java > /dev/null
+  if [ $? -eq 0 ]; then 
+    if [ ! -f ~/compiler.jar ]; then
+      echo "Can not find Closure compiler at ~/compiler.jar"
+      exit 1
+    fi
+  else
+   echo "java is not installed and is needed for -O, -A or -o (Closure compiler)."
+   exit 1
+  fi
+fi
+
+# Function for looking up listed js files
+function resolvejs {
+  FNAME="$1$LOADSUFFIX.js"
+  if [ -f $FNAME ]; then
+    RESOLVED="$FNAME" 
+  else
+    if [ -f $AMBER/js/$FNAME ]; then
+      RESOLVED="$AMBER/js/$FNAME"
+    else
+      echo "Javascript file not found: $FNAME"
+      exit 1
+    fi
+  fi
+}
+
+# Resolve listed libraries in $BASE deparated by spaces
+for FILE in $BASE
+do
+   resolvejs $FILE
+   TOBASE="$TOBASE $RESOLVED"
+done
+
+# Resolve listed libraries in $LOAD separated by ,
+LOAD=${LOAD//,/\ }
+for FILE in $LOAD
+do
+   resolvejs $FILE
+   TOLOAD="$TOLOAD $RESOLVED"
+done
+
+# Resolve COMPILER
+for FILE in $COMPILER
+do
+   resolvejs $FILE
+   TOCOMPILER="$TOCOMPILER $RESOLVED"
+done
+
+# Add supplied libraries we have not already loaded (they are already resolved)
+#for FILE in $EXTRA
+#do
+#   resolvejs $FILE
+#   TOEXTRA="$TOEXTRA $RESOLVED"
+#done
+
+TOCOMPILER="$TOCOMPILER$TOLOAD"
+
+# Resolve init and nodecompile
+THEREST="init $AMBER/bin/$NODECOMPILE"
+for FILE in $THEREST
+do
+   resolvejs $FILE
+   TOCOMPILER="$TOCOMPILER $RESOLVED"
+done
+
+# Add supplied libraries
+LIBS="$TOBASE $TOLOAD"
+
+# Get a unique tempdir and make it get auto removed on exit
+TMPDIR=`mktemp -d amberc.XXXXXX 2>>/dev/null` ||\
+    TMPDIR=/tmp/amberc.$$.`date +%s` && mkdir -p $TMPDIR
+trap "rm -rf $TMPDIR" EXIT
+
+
+# --------------------------------------------------
+# Collect libraries and Smalltalk files looking
+# both locally and in $AMBER/js and $AMBER/st 
+# --------------------------------------------------
+PROGRAM=
+until [ "$*" = "" ]
+do
+  case $1 in
+     *.st)
+        CATEGORY=`basename $1 .st`
+        if [ -f "$1" ]; then
+           COMPILE="$COMPILE $1 $CATEGORY"
+           COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
+        else
+           if [ -f $AMBER/st/$1 ]; then
+             COMPILE="$COMPILE $AMBER/st/$1 $CATEGORY"
+             COMPILED="$COMPILED $CATEGORY$SUFFIXUSED.js"
+           else
+             echo "Amber file not found: $1"
+             exit 1
+           fi
+        fi
+        ;;
+
+     *.js)
+        resolvejs $1
+	LIBS="$LIBS $RESOLVED" 
+        ;;
+      *)
+        # Will end up being the last non js/st argument
+        PROGRAM=$1
+        ;;
+  esac
+  shift
+done
+
+# --------------------------------------------------
+# Actual compilation phase of collected .st files
+# --------------------------------------------------
+
+# Create compiler dynamically
+cat $TOCOMPILER > $TMPDIR/compiler.js
+ 
+# Compile all collected .st files to .js
+echo "Loading libraries$TOCOMPILER and compiling ..."
+node $TMPDIR/compiler.js $DEPLOY $SUFFIX $COMPILE
+
+# Verify all .js files corresponding to .st files were created, otherwise exit
+IFS=" "
+for FILE in $COMPILED
+do
+  if [ ! -f "$FILE" ]; then
+    echo "Failed compilation of $FILE, exiting."
+    exit 1
+  fi 
+done
+
+if [ ! -z $CLOSUREPARTS ]; then
+  echo "Compiling all js files using Google closure compiler."
+
+  ALLJSFILES="$COMPILED $LIBS"
+  for FILE in $ALLJSFILES
+  do
+    mv $FILE $FILE.original
+    java -jar ~/compiler.jar $CLOSUREOPTS --js $FILE.original --js_output_file $FILE
+    rm $FILE.original
+  done
+fi
+
+
+if [ -z $PROGRAM ]; then
+  echo "Done."
+  exit 0
+fi
+
+# --------------------------------------------------
+# Now we start composing resulting javascript file.
+# --------------------------------------------------
+
+# Add collected libraries to libs.js file.
+if [ ! -z "$LIBS" ]; then
+  echo "Adding libraries $LIBS ..."
+  cat $LIBS > $TMPDIR/libs.js
+  LIBS=$TMPDIR/libs.js
+fi
+
+echo "Adding Amber code$COMPILED ..."
+
+# Check for init file
+if [ ! -z "$INIT" ]; then
+   if [ -f "$INIT" ]; then
+      echo "Adding initializer $INIT ..."
+   else
+      echo "Can not find init file $INIT, exiting."
+      exit 1
+   fi 
+fi
+
+# Check for adding main
+if [ ! -z "$MAIN" ]; then
+  echo "Adding call to $MAIN class >> main ..."
+  echo "smalltalk.$MAIN._main()" > $TMPDIR/main.js
+  MAIN=$TMPDIR/main.js
+fi
+
+# Check for adding main file
+if [ ! -z "$MAINFILE" ]; then
+   if [ -f "$MAINFILE" ]; then
+      echo "Adding main as $MAINFILE ..."
+   else
+      echo "Can not find main file $MAINFILE, exiting."
+      exit 1
+   fi 
+   MAIN=$MAINFILE
+fi
+
+# And finally concatenate Program.js
+echo "Writing $PROGRAM.js ..."
+cat $LIBS $COMPILED $INIT $MAIN > $PROGRAM.js
+echo "Done."
+
+
+if [ ! -z $CLOSUREFULL ]; then
+  echo "Compiling $PROGRAM.js file using Google closure compiler."
+  mv $PROGRAM.js $PROGRAM.js.original
+  java -jar ~/compiler.jar $CLOSUREOPTS --js $PROGRAM.js.original --js_output_file $PROGRAM.js
+  rm $PROGRAM.js.original
+  echo "Done."
+fi
+

+ 1 - 1
js/Kernel-Objects.deploy.js

@@ -203,7 +203,7 @@ smalltalk.method({
 selector: "deprecatedAPI",
 fn: function () {
     var self = this;
-    smalltalk.send(console, "_warn_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(thisContext, "_home", []), "_asString", []), "__comma", [" is deprecated! (in "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(thisContext, "_home", []), "_home", []), "_asString", [])]), "__comma", [")"])]);
+    smalltalk.send(console, "_warn_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.getThisContext(), "_home", []), "_asString", []), "__comma", [" is deprecated! (in "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.getThisContext(), "_home", []), "_home", []), "_asString", [])]), "__comma", [")"])]);
     return self;
 }
 }),

+ 1 - 1
js/Kernel-Objects.js

@@ -280,7 +280,7 @@ selector: "deprecatedAPI",
 category: 'error handling',
 fn: function () {
     var self = this;
-    smalltalk.send(console, "_warn_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(thisContext, "_home", []), "_asString", []), "__comma", [" is deprecated! (in "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(thisContext, "_home", []), "_home", []), "_asString", [])]), "__comma", [")"])]);
+    smalltalk.send(console, "_warn_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.getThisContext(), "_home", []), "_asString", []), "__comma", [" is deprecated! (in "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.getThisContext(), "_home", []), "_home", []), "_asString", [])]), "__comma", [")"])]);
     return self;
 },
 args: [],

+ 1 - 1
repl/Makefile

@@ -1,5 +1,5 @@
 repl.js: REPL.st
-	../bin/amberc -m Repl -l Compiler,parser REPL.st amber
+	../bin/amberc -m Repl REPL.st amber
 
 run: repl.js
 	../bin/amber

+ 1 - 1
repl/REPL.js

@@ -61,7 +61,7 @@ selector: "initialize",
 category: 'initialization',
 fn: function (){
 var self=this;
-smalltalk.send(self, "_initialize", [], smalltalk.Object);
+smalltalk.send(self, "_initialize", [], smalltalk.Repl.superclass || nil);
 (self['@readline']=smalltalk.send((typeof require == 'undefined' ? nil : require), "_value_", ["readline"]));
 (self['@util']=smalltalk.send((typeof require == 'undefined' ? nil : require), "_value_", ["util"]));
 return self;},

File diff suppressed because it is too large
+ 322 - 228
repl/amber.js


+ 6 - 6
server/FileServer.st

@@ -71,8 +71,8 @@ handleGETRequest: aRequest respondTo: aResponse
 	| uri filename |
 	uri := (url parse: aRequest url) pathname.
 	filename := path join: self basePath with: uri.
-	path exists: filename do: [:boolean | 
-		boolean 
+	path exists: filename do: [:aBoolean |
+		aBoolean
 			ifFalse: [self respondNotFoundTo: aResponse]
 			ifTrue: [self respondFileNamed: filename to: aResponse]]
 !
@@ -595,15 +595,15 @@ mimeTypeFor: aString
 !FileServer class methodsFor: 'initialization'!
 
 main
-	| fileServer arguments portOption port|
+	| fileServer arguments portOption portNumber|
 	fileServer := self new.
 	fileServer checkDirectoryLayout.
 
 	arguments := process argv.
 	portOption := arguments at: 3 ifAbsent: [nil].
-	port := arguments at: 4 ifAbsent: [nil].
-	('-p' = portOption and: [port notNil]) ifTrue: [
-		fileServer port: port.
+	portNumber := arguments at: 4 ifAbsent: [nil].
+	('-p' = portOption and: [portNumber notNil]) ifTrue: [
+		fileServer port: portNumber.
 	].
 	^fileServer start
 ! !

+ 8 - 8
server/server.js

@@ -932,7 +932,7 @@ selector: "deprecatedAPI",
 category: 'error handling',
 fn: function () {
     var self = this;
-    smalltalk.send(console, "_warn_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(thisContext, "_home", []), "_asString", []), "__comma", [" is deprecated! (in "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(thisContext, "_home", []), "_home", []), "_asString", [])]), "__comma", [")"])]);
+    smalltalk.send(console, "_warn_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.getThisContext(), "_home", []), "_asString", []), "__comma", [" is deprecated! (in "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.getThisContext(), "_home", []), "_home", []), "_asString", [])]), "__comma", [")"])]);
     return self;
 },
 args: [],
@@ -13988,10 +13988,10 @@ var uri=nil;
 var filename=nil;
 (uri=smalltalk.send(smalltalk.send(self['@url'], "_parse_", [smalltalk.send(aRequest, "_url", [])]), "_pathname", []));
 (filename=smalltalk.send(self['@path'], "_join_with_", [smalltalk.send(self, "_basePath", []), uri]));
-smalltalk.send(self['@path'], "_exists_do_", [filename, (function(boolean){return ((($receiver = boolean).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_respondNotFoundTo_", [aResponse]);})() : (function(){return smalltalk.send(self, "_respondFileNamed_to_", [filename, aResponse]);})()) : smalltalk.send($receiver, "_ifFalse_ifTrue_", [(function(){return smalltalk.send(self, "_respondNotFoundTo_", [aResponse]);}), (function(){return smalltalk.send(self, "_respondFileNamed_to_", [filename, aResponse]);})]));})]);
+smalltalk.send(self['@path'], "_exists_do_", [filename, (function(aBoolean){return ((($receiver = aBoolean).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_respondNotFoundTo_", [aResponse]);})() : (function(){return smalltalk.send(self, "_respondFileNamed_to_", [filename, aResponse]);})()) : smalltalk.send($receiver, "_ifFalse_ifTrue_", [(function(){return smalltalk.send(self, "_respondNotFoundTo_", [aResponse]);}), (function(){return smalltalk.send(self, "_respondFileNamed_to_", [filename, aResponse]);})]));})]);
 return self;},
 args: ["aRequest", "aResponse"],
-source: "handleGETRequest: aRequest respondTo: aResponse\x0a\x09| uri filename |\x0a\x09uri := (url parse: aRequest url) pathname.\x0a\x09filename := path join: self basePath with: uri.\x0a\x09path exists: filename do: [:boolean | \x0a\x09\x09boolean \x0a\x09\x09\x09ifFalse: [self respondNotFoundTo: aResponse]\x0a\x09\x09\x09ifTrue: [self respondFileNamed: filename to: aResponse]]",
+source: "handleGETRequest: aRequest respondTo: aResponse\x0a\x09| uri filename |\x0a\x09uri := (url parse: aRequest url) pathname.\x0a\x09filename := path join: self basePath with: uri.\x0a\x09path exists: filename do: [:aBoolean |\x0a\x09\x09aBoolean\x0a\x09\x09\x09ifFalse: [self respondNotFoundTo: aResponse]\x0a\x09\x09\x09ifTrue: [self respondFileNamed: filename to: aResponse]]",
 messageSends: ["pathname", "parse:", "url", "join:with:", "basePath", "exists:do:", "ifFalse:ifTrue:", "respondNotFoundTo:", "respondFileNamed:to:"],
 referencedClasses: []
 }),
@@ -14257,17 +14257,17 @@ var self=this;
 var fileServer=nil;
 var arguments=nil;
 var portOption=nil;
-var port=nil;
+var portNumber=nil;
 (fileServer=smalltalk.send(self, "_new", []));
 smalltalk.send(fileServer, "_checkDirectoryLayout", []);
 (arguments=smalltalk.send((typeof process == 'undefined' ? nil : process), "_argv", []));
 (portOption=smalltalk.send(arguments, "_at_ifAbsent_", [(3), (function(){return nil;})]));
-(self['@port']=smalltalk.send(arguments, "_at_ifAbsent_", [(4), (function(){return nil;})]));
-((($receiver = smalltalk.send(smalltalk.send("-p", "__eq", [portOption]), "_and_", [(function(){return smalltalk.send(self['@port'], "_notNil", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(fileServer, "_port_", [self['@port']]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(fileServer, "_port_", [self['@port']]);})]));
+(portNumber=smalltalk.send(arguments, "_at_ifAbsent_", [(4), (function(){return nil;})]));
+((($receiver = smalltalk.send(smalltalk.send("-p", "__eq", [portOption]), "_and_", [(function(){return smalltalk.send(portNumber, "_notNil", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(fileServer, "_port_", [portNumber]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(fileServer, "_port_", [portNumber]);})]));
 return smalltalk.send(fileServer, "_start", []);
 return self;},
 args: [],
-source: "main\x0a\x09| fileServer arguments portOption port|\x0a\x09fileServer := self new.\x0a\x09fileServer checkDirectoryLayout.\x0a\x0a\x09arguments := process argv.\x0a\x09portOption := arguments at: 3 ifAbsent: [nil].\x0a\x09port := arguments at: 4 ifAbsent: [nil].\x0a\x09('-p' = portOption and: [port notNil]) ifTrue: [\x0a\x09\x09fileServer port: port.\x0a\x09].\x0a\x09^fileServer start",
+source: "main\x0a\x09| fileServer arguments portOption portNumber|\x0a\x09fileServer := self new.\x0a\x09fileServer checkDirectoryLayout.\x0a\x0a\x09arguments := process argv.\x0a\x09portOption := arguments at: 3 ifAbsent: [nil].\x0a\x09portNumber := arguments at: 4 ifAbsent: [nil].\x0a\x09('-p' = portOption and: [portNumber notNil]) ifTrue: [\x0a\x09\x09fileServer port: portNumber.\x0a\x09].\x0a\x09^fileServer start",
 messageSends: ["new", "checkDirectoryLayout", "argv", "at:ifAbsent:", "ifTrue:", "and:", "=", "notNil", "port:", "start"],
 referencedClasses: []
 }),
@@ -14347,4 +14347,4 @@ smalltalk.classes()._do_(function(each) {
 if(this.smalltalkReady) {
     this.smalltalkReady();
 }
-smalltalk.FileServer._main()
+smalltalk.FileServer._main()

Some files were not shown because too many files changed in this diff