Browse Source

Merge pull request #557 from herby/requirejs-wip

amberc now produces runnable files from AMD modules; tests are run
Herbert Vojčík 11 years ago
parent
commit
fb396a72bb

+ 54 - 28
bin/amberc.js

@@ -8,6 +8,8 @@
  * Execute 'node compiler.js' without arguments or with -h / --help for help.
  */
 
+var amdefine = require("amdefine");
+
 /**
  * Map the async filter function onto array and evaluate callback, once all have finished.
  * Taken from: http://howtonode.org/control-flow-part-iii
@@ -54,19 +56,19 @@ function Combo(callback) {
 
 Combo.prototype = {
   add: function () {
-    var self = this,
-        id = this.items;
-    this.items++;
-    return function () {
-      self.check(id, arguments);
-    };
+	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.results[id] = Array.prototype.slice.call(arguments);
+	this.items--;
+	if (this.items == 0) {
+	  this.callback.apply(this, this.results);
+	}
   }
 };
 
@@ -83,11 +85,11 @@ var path = require('path'),
 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', 'Importer-Exporter', 'Compiler-Exceptions',
-	                          'Compiler-Core', 'Compiler-AST', 'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic']);
+	this.kernel_libraries = ['boot', '@smalltalk', '@nil', '@_st', 'Kernel-Objects', 'Kernel-Classes', 'Kernel-Methods',
+							'Kernel-Collections', 'Kernel-Exceptions', 'Kernel-Transcript',
+							'Kernel-Announcements'];
+	this.compiler_libraries = this.kernel_libraries.concat(['parser', 'Importer-Exporter',
+							'Compiler-Core', 'Compiler-AST', 'Compiler-Exceptions', 'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic']);
 }
 
 
@@ -101,7 +103,7 @@ var createDefaults = function(amber_dir, finished_callback){
 
 	return {
 		'load': [],
-		'init': path.join(amber_dir, 'js', 'init.js'),
+//		'init': path.join(amber_dir, 'js', 'init.js'),
 		'main': undefined,
 		'mainfile': undefined,
 		'stFiles': [],
@@ -166,7 +168,7 @@ AmberC.prototype.check_configuration_ok = function(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');
+//		throw new Error('AmberC.check_configuration_ok(): init value missing in configuration object');
 	}
 
 	if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.lenght) {
@@ -224,9 +226,11 @@ AmberC.prototype.check_for_closure_compiler = function(callback) {
  * @param callback gets called on success with path to .js file as parameter
  */
 AmberC.prototype.resolve_js = function(filename, callback) {
+	var special = filename[0] == "@";
+	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, '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) {
@@ -394,12 +398,12 @@ AmberC.prototype.resolve_compiler = function(callback) {
  */
 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);
+//	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);
 };
@@ -413,13 +417,19 @@ AmberC.prototype.resolve_init = function(compilerFiles) {
 AmberC.prototype.create_compiler = function(compilerFilesArray) {
 	var self = this;
 	var compiler_files = new Combo(function() {
+		var define = amdefine(module), requirejs = define.require;
+		define("amber_vm/browser-compatibility", [], {});
+
 		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];
+			var match = (""+data[1]).match(/^define\("([^"]*)"/);
+			if (match) content += 'requirejs("'+match[1]+'");\n';
 		});
-		content = content + 'return smalltalk;})();';
+		content = content + 'return requirejs("amber_vm/smalltalk");})();';
 		self.defaults.smalltalk = eval(content);
+		self.defaults.smalltalk.initialize();
 		console.log('Compiler loaded');
 		self.defaults.smalltalk.ErrorHandler._setCurrent_(self.defaults.smalltalk.RethrowErrorHandler._new());
 
@@ -573,8 +583,8 @@ AmberC.prototype.compose_js_files = function() {
 	}
 
 	if (undefined !== defaults.init) {
-		console.log('Adding initializer ' + defaults.init);
-		program_files.push(defaults.init);
+//		console.log('Adding initializer ' + defaults.init);
+//		program_files.push(defaults.init);
 	}
 
 	console.ambercLog('Writing program file: %s.js', programFile);
@@ -589,6 +599,21 @@ AmberC.prototype.compose_js_files = function() {
 		self.optimize();
 	});
 
+	var defineDefine = function () {
+		var path = require('path');
+		var amdefine = $SRC$;
+		var define = amdefine(module);
+		var result = function () {
+			var id = arguments[0];
+			setTimeout(function () { define.require(id); }, 0);
+			return define.apply(this, arguments);
+		};
+		result.amd = {};
+		return result;
+	};
+
+	fileStream.write('var define = ('+(''+defineDefine).replace('$SRC$', ""+amdefine)+')();\n'
+		+ 'define("amber_vm/browser-compatibility", [], {});\n');
 	program_files.forEach(function(file) {
 		if(fs.existsSync(file)) {
 			console.log('Adding : ' + file);
@@ -598,6 +623,7 @@ AmberC.prototype.compose_js_files = function() {
 			throw(new Error('Can not find file ' + file));
 		}
 	});
+	fileStream.write('define("amber_vm/_init", ["amber_vm/smalltalk"], function (st) { st.initialize(); });\n');
 	if (undefined !== defaults.main) {
 		console.log('Adding call to: %s>>main', defaults.main);
 		fileStream.write('smalltalk.' + defaults.main + '._main()');

+ 1 - 1
grunt/tasks/grunt-peg.js

@@ -23,7 +23,7 @@ module.exports = function(grunt) {
       export_var: 'module.exports'
     });
     var parser = PEG.buildParser(grunt.file.read(this.data.src), options);
-    var content = 'define(["smalltalk","nil"],function(smalltalk,nil){\n'+options.export_var + ' = ' + parser.toSource() + ';\n});';
+    var content = 'define("amber_vm/parser", ["./smalltalk","./nil"],function(smalltalk,nil){\n'+options.export_var + ' = ' + parser.toSource() + ';\n});';
     grunt.file.write(this.data.dest, content);
   });
 };

+ 40 - 4
js/Importer-Exporter.deploy.js

@@ -756,18 +756,18 @@ messageSends: ["do:displayingProgress:", "value:", "exportPackage:", "name", "ke
 smalltalk.PackageHandler);
 
 
+smalltalk.PackageHandler.klass.iVarNames = ['registry'];
 smalltalk.addMethod(
 smalltalk.method({
 selector: "classRegisteredFor:",
 fn: function (aString){
 var self=this;
-function $LegacyPackageHandler(){return smalltalk.LegacyPackageHandler||(typeof LegacyPackageHandler=="undefined"?nil:LegacyPackageHandler)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=$LegacyPackageHandler();
+$1=_st(self["@registry"])._at_(aString);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"classRegisteredFor:",{aString:aString},smalltalk.PackageHandler.klass)})},
-messageSends: []}),
+messageSends: ["at:"]}),
 smalltalk.PackageHandler.klass);
 
 smalltalk.addMethod(
@@ -783,6 +783,41 @@ return $1;
 messageSends: ["new", "classRegisteredFor:"]}),
 smalltalk.PackageHandler.klass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+smalltalk.PackageHandler.klass.superclass.fn.prototype._initialize.apply(_st(self), []);
+self["@registry"]=smalltalk.HashedCollection._from_([]);
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.PackageHandler.klass)})},
+messageSends: ["initialize"]}),
+smalltalk.PackageHandler.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "register:for:",
+fn: function (aClass,aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@registry"])._at_put_(aString,aClass);
+return self}, function($ctx1) {$ctx1.fill(self,"register:for:",{aClass:aClass,aString:aString},smalltalk.PackageHandler.klass)})},
+messageSends: ["at:put:"]}),
+smalltalk.PackageHandler.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "registerFor:",
+fn: function (aString){
+var self=this;
+function $PackageHandler(){return smalltalk.PackageHandler||(typeof PackageHandler=="undefined"?nil:PackageHandler)}
+return smalltalk.withContext(function($ctx1) { 
+_st($PackageHandler())._register_for_(self,aString);
+return self}, function($ctx1) {$ctx1.fill(self,"registerFor:",{aString:aString},smalltalk.PackageHandler.klass)})},
+messageSends: ["register:for:"]}),
+smalltalk.PackageHandler.klass);
+
 
 smalltalk.addClass('LegacyPackageHandler', smalltalk.PackageHandler, [], 'Importer-Exporter');
 smalltalk.addMethod(
@@ -974,9 +1009,10 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 smalltalk.LegacyPackageHandler.klass.superclass.fn.prototype._initialize.apply(_st(self), []);
+self._registerFor_("unknown");
 self._commitPathsFromLoader();
 return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.LegacyPackageHandler.klass)})},
-messageSends: ["initialize", "commitPathsFromLoader"]}),
+messageSends: ["initialize", "registerFor:", "commitPathsFromLoader"]}),
 smalltalk.LegacyPackageHandler.klass);
 
 smalltalk.addMethod(

+ 58 - 7
js/Importer-Exporter.js

@@ -917,22 +917,22 @@ referencedClasses: []
 smalltalk.PackageHandler);
 
 
+smalltalk.PackageHandler.klass.iVarNames = ['registry'];
 smalltalk.addMethod(
 smalltalk.method({
 selector: "classRegisteredFor:",
 category: 'accessing',
 fn: function (aString){
 var self=this;
-function $LegacyPackageHandler(){return smalltalk.LegacyPackageHandler||(typeof LegacyPackageHandler=="undefined"?nil:LegacyPackageHandler)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=$LegacyPackageHandler();
+$1=_st(self["@registry"])._at_(aString);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"classRegisteredFor:",{aString:aString},smalltalk.PackageHandler.klass)})},
 args: ["aString"],
-source: "classRegisteredFor: aString\x0a\x09\x22Temporary. Should return instance of appropriate\x0a\x09package handler for supplied transport type.\x22\x0a\x09^LegacyPackageHandler",
-messageSends: [],
-referencedClasses: ["LegacyPackageHandler"]
+source: "classRegisteredFor: aString\x0a\x09^registry at: aString",
+messageSends: ["at:"],
+referencedClasses: []
 }),
 smalltalk.PackageHandler.klass);
 
@@ -954,6 +954,56 @@ referencedClasses: []
 }),
 smalltalk.PackageHandler.klass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "initialize",
+category: 'initialization',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+smalltalk.PackageHandler.klass.superclass.fn.prototype._initialize.apply(_st(self), []);
+self["@registry"]=smalltalk.HashedCollection._from_([]);
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.PackageHandler.klass)})},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a\x09registry := #{}",
+messageSends: ["initialize"],
+referencedClasses: []
+}),
+smalltalk.PackageHandler.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "register:for:",
+category: 'registry',
+fn: function (aClass,aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@registry"])._at_put_(aString,aClass);
+return self}, function($ctx1) {$ctx1.fill(self,"register:for:",{aClass:aClass,aString:aString},smalltalk.PackageHandler.klass)})},
+args: ["aClass", "aString"],
+source: "register: aClass for: aString\x0a\x09registry at: aString put: aClass",
+messageSends: ["at:put:"],
+referencedClasses: []
+}),
+smalltalk.PackageHandler.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "registerFor:",
+category: 'registry',
+fn: function (aString){
+var self=this;
+function $PackageHandler(){return smalltalk.PackageHandler||(typeof PackageHandler=="undefined"?nil:PackageHandler)}
+return smalltalk.withContext(function($ctx1) { 
+_st($PackageHandler())._register_for_(self,aString);
+return self}, function($ctx1) {$ctx1.fill(self,"registerFor:",{aString:aString},smalltalk.PackageHandler.klass)})},
+args: ["aString"],
+source: "registerFor: aString\x0a\x09PackageHandler register: self for: aString",
+messageSends: ["register:for:"],
+referencedClasses: ["PackageHandler"]
+}),
+smalltalk.PackageHandler.klass);
+
 
 smalltalk.addClass('LegacyPackageHandler', smalltalk.PackageHandler, [], 'Importer-Exporter');
 smalltalk.LegacyPackageHandler.comment="I am responsible for handling package loading and committing.\x0a\x0aI should not be used directly. Instead, use the corresponding `Package` methods.";
@@ -1202,11 +1252,12 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 smalltalk.LegacyPackageHandler.klass.superclass.fn.prototype._initialize.apply(_st(self), []);
+self._registerFor_("unknown");
 self._commitPathsFromLoader();
 return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.LegacyPackageHandler.klass)})},
 args: [],
-source: "initialize\x0a\x09super initialize.\x0a\x09self commitPathsFromLoader",
-messageSends: ["initialize", "commitPathsFromLoader"],
+source: "initialize\x0a\x09super initialize.\x0a\x09self registerFor: 'unknown'.\x0a\x09self commitPathsFromLoader",
+messageSends: ["initialize", "registerFor:", "commitPathsFromLoader"],
 referencedClasses: []
 }),
 smalltalk.LegacyPackageHandler.klass);

+ 1 - 1
js/boot.js

@@ -34,7 +34,7 @@
    ==================================================================== */
 
 
-define([ './ensure-console', './es5-shim-2.0.2/es5-shim.min', './es5-shim-2.0.2/es5-sham.min' ], function () {
+define("amber_vm/boot", [ './browser-compatibility' ], function () {
 
 /* Array extensions */
 

+ 1 - 1
js/lib/_st.js

@@ -1,3 +1,3 @@
-define(['./boot'], function (boot) {
+define("amber_vm/_st", ["./boot"], function (boot) {
     return boot._st;
 });

+ 5 - 0
js/lib/browser-compatibility.js

@@ -0,0 +1,5 @@
+define([
+    './ensure-console',
+    './es5-shim-2.0.2/es5-shim.min',
+    './es5-shim-2.0.2/es5-sham.min'
+], {});

+ 1 - 1
js/lib/nil.js

@@ -1,3 +1,3 @@
-define(['./boot'], function (boot) {
+define("amber_vm/nil", ["./boot"], function (boot) {
     return boot.nil;
 });

+ 1 - 1
js/lib/smalltalk.js

@@ -1,3 +1,3 @@
-define(['./boot'], function (boot) {
+define("amber_vm/smalltalk", ["./boot"], function (boot) {
     return boot.smalltalk;
 });

+ 1 - 1
js/parser.js

@@ -1,4 +1,4 @@
-define(["./smalltalk","./nil"],function(smalltalk,nil){
+define("amber_vm/parser", ["./smalltalk","./nil"],function(smalltalk,nil){
 smalltalk.parser = (function(){
   /*
    * Generated by PEG.js 0.7.0.

+ 42 - 35
package.json

@@ -1,37 +1,44 @@
 {
-    "name": "amber",
-    "version": "0.11.0",
-    "description": "An implementation of the Smalltalk language that runs on top of the JS runtime.",
-    "homepage": "http://amber-lang.net",
-    "keywords": [ "javascript", "smalltalk", "language", "compiler", "web" ],
-    "author": {
-        "name": "Nicolas Petton",
-        "email": "petton.nicolas@gmail.com",
-        "url": "http://www.nicolas-petton.fr"
-    },
-    "license": {
-        "type": "MIT"
-    },
-    "repository": {
-        "type": "git",
-        "url": "git://github.com/amber-smalltalk/amber.git#0.11.0"
-    },
-    "engines": {
-        "node": "0.8.x"
-    },
-    "bin": {
-        "amber": "./bin/amber",
-        "amberc": "./bin/amberc",
-        "ambers": "./bin/server"
-    },
-    "scripts": {
-        "test": "sh -c 'grunt amberc:amber_test_runner' && node ./test/amber_test_runner.js"
-    },
-    "devDependencies": {
-        "pegjs": "~0.7.0",
-        "grunt": "~0.4.0",
-        "grunt-contrib-jshint": "~0.3.0",
-        "grunt-image-embed": "~0.1.3",
-        "grunt-contrib-mincss": "~0.3.2"
-    }
+  "name": "amber",
+  "version": "0.11.0",
+  "description": "An implementation of the Smalltalk language that runs on top of the JS runtime.",
+  "homepage": "http://amber-lang.net",
+  "keywords": [
+    "javascript",
+    "smalltalk",
+    "language",
+    "compiler",
+    "web"
+  ],
+  "author": {
+    "name": "Nicolas Petton",
+    "email": "petton.nicolas@gmail.com",
+    "url": "http://www.nicolas-petton.fr"
+  },
+  "license": {
+    "type": "MIT"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/amber-smalltalk/amber.git#0.11.0"
+  },
+  "engines": {
+    "node": "0.8.x"
+  },
+  "bin": {
+    "amber": "./bin/amber",
+    "amberc": "./bin/amberc",
+    "ambers": "./bin/server"
+  },
+  "scripts": {
+    "test": "sh -c 'grunt amberc:amber_test_runner' && node ./test/amber_test_runner.js"
+  },
+  "devDependencies": {
+    "pegjs": "~0.7.0",
+    "grunt": "~0.4.0",
+    "grunt-contrib-jshint": "~0.3.0",
+    "grunt-image-embed": "~0.1.3",
+    "grunt-contrib-mincss": "~0.3.2",
+    "amdefine": "0.0.5"
+  }
 }

+ 21 - 3
st/Importer-Exporter.st

@@ -432,18 +432,35 @@ ajaxPutAt: aURL data: aString
 			'error' -> [ :xhr | self error: 'Commiting ' , aURL , ' failed with reason: "' , (xhr responseText) , '"'] }
 ! !
 
+PackageHandler class instanceVariableNames: 'registry'!
+
 !PackageHandler class methodsFor: 'accessing'!
 
 classRegisteredFor: aString
-	"Temporary. Should return instance of appropriate
-	package handler for supplied transport type."
-	^LegacyPackageHandler
+	^registry at: aString
 !
 
 for: aString
 	^(self classRegisteredFor: aString) new
 ! !
 
+!PackageHandler class methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	registry := #{}
+! !
+
+!PackageHandler class methodsFor: 'registry'!
+
+register: aClass for: aString
+	registry at: aString put: aClass
+!
+
+registerFor: aString
+	PackageHandler register: self for: aString
+! !
+
 PackageHandler subclass: #LegacyPackageHandler
 	instanceVariableNames: ''
 	package: 'Importer-Exporter'!
@@ -540,6 +557,7 @@ resetCommitPaths
 
 initialize
 	super initialize.
+	self registerFor: 'unknown'.
 	self commitPathsFromLoader
 ! !
 

+ 1 - 1
test/Test.js

@@ -1,4 +1,4 @@
-define(["smalltalk","nil","_st"], function(smalltalk,nil,_st){
+define("amber/Test", ["amber_vm/smalltalk","amber_vm/nil","amber_vm/_st"], function(smalltalk,nil,_st){
 smalltalk.addPackage('Test');
 smalltalk.addClass('NodeTestRunner', smalltalk.Object, [], 'Test');