Browse Source

new bootstrap

Nicolas Petton 12 years ago
parent
commit
8988103417
1 changed files with 243 additions and 74 deletions
  1. 243 74
      js/boot.js

+ 243 - 74
js/boot.js

@@ -50,10 +50,11 @@ if (typeof console === "undefined") {
 function SmalltalkObject(){};
 function SmalltalkBehavior(){};
 function SmalltalkClass(){};
-function SmalltalkPackage(){};
 function SmalltalkMetaclass(){
 	this.meta = true;
 };
+
+function SmalltalkPackage(){};
 function SmalltalkMethod(){};
 function SmalltalkNil(){};
 
@@ -65,6 +66,15 @@ function SmalltalkOrganizer() {
     this.elements = [];
 };
 
+SmalltalkBehavior.prototype  = new SmalltalkObject();
+SmalltalkClass.prototype     = new SmalltalkBehavior();
+SmalltalkMetaclass.prototype = new SmalltalkBehavior();
+
+SmalltalkNil.prototype       = new SmalltalkObject();
+SmalltalkMethod.prototype    = new SmalltalkObject();
+SmalltalkPackage.prototype   = new SmalltalkObject();
+SmalltalkOrganizer.prototype = new SmalltalkObject();
+
 SmalltalkOrganizer.prototype.addElement = function(el) {
     if(typeof el === 'undefined' || el === nil) {
         return false;
@@ -99,10 +109,30 @@ function Smalltalk(){
 
 	st.reservedWords = ['break', 'case', 'catch', 'char', 'class', 'continue', 'debugger', 
 		'default', 'delete', 'do', 'else', 'finally', 'for', 'function', 
-		'if', 'in', 'instanceof', 'new', 'private', 'protected', 
+		'if', 'in', 'instanceof', 'native', 'new', 'private', 'protected', 
 		'public', 'return', 'static', 'switch', 'this', 'throw',
 		'try', 'typeof', 'var', 'void', 'while', 'with', 'yield'];
 
+    
+    /* Method not implemented handlers selectors */
+
+    var dnuHandlers = [];
+
+    var addDnuHandler = function(string) {
+        if(dnuHandlers.indexOf(string) == -1) {
+            dnuHandlers.push(string);
+        }
+    };
+    
+    /* DNU handler method */
+
+    var dnu = function(selector) {
+        return function() {
+            var args = Array.prototype.slice.call(arguments);
+            return messageNotUnderstood(this, selector, args);
+        };
+    };
+
 	/* The symbol table ensures symbol unicity */
 
 	symbolTable = {};
@@ -144,8 +174,11 @@ function Smalltalk(){
 	function klass(spec) {
 		var spec = spec || {};
 		var meta = metaclass();
-		var that = setupClass(meta.instanceClass, spec);
-		that.className = spec.className;
+		var that = meta.instanceClass;
+        setupClass(that, spec);
+		
+        that.className = spec.className;
+        that.wrapped   = spec.wrapped || false;
 		meta.className = spec.className + ' class';
         that.organization = new SmalltalkOrganizer();
 		if(spec.superclass) {
@@ -156,26 +189,34 @@ function Smalltalk(){
 	}
 	
 	function metaclass() {
-		var meta = setupClass(new SmalltalkMetaclass(), {})
-        meta.organization = new SmalltalkOrganizer();
-		meta.instanceClass = new meta.fn;
-		return meta;
+		var metaclass = new SmalltalkMetaclass();
+        setupClass(metaclass)
+        metaclass.organization = new SmalltalkOrganizer();
+        metaclass.fn.prototype = new SmalltalkClass();
+		metaclass.instanceClass = new metaclass.fn;
+		return metaclass;
 	}
 	
-	function setupClass(that, spec) {
-		that.fn = spec.fn || function(){};
-		that.iVarNames = spec.iVarNames || [];
-		Object.defineProperty(that, "toString", {
+	function setupClass(klass, spec) {
+        spec = spec || {};
+        if(!klass.fn) {
+		    klass.fn = spec.fn || function(){};
+        }
+		klass.iVarNames = spec.iVarNames || [];
+		klass.pkg = spec.pkg;
+
+		Object.defineProperty(klass, "toString", {
 			value: function() { return 'Smalltalk ' + this.className; }, 
-            configurable: true // no writable - in par with ES6 methods
+            configurable: true
 		});
-		that.pkg = spec.pkg;
-		Object.defineProperties(that.fn.prototype, {
-			methods: { value: {}, enumerable: false, configurable: true, writable: true },
-			inheritedMethods: { value: {}, enumerable: false, configurable: true, writable: true },
-			klass: { value: that, enumerable: false, configurable: true, writable: true }
+
+		Object.defineProperties(klass, {
+			methods: { value: {}, enumerable: false, configurable: true, writable: true }
+		});
+
+        Object.defineProperties(klass.fn.prototype, {
+			klass: { value: klass, enumerable: false, configurable: true, writable: true }
 		});
-		return that;
 	};
 
 	/* Smalltalk method object. To add a method to a class,
@@ -194,7 +235,7 @@ function Smalltalk(){
 		return that;
 	};
 
-	/* Initialize a class in its class hierarchy. Handle both class and
+	/* Initialize a class in its class hierarchy. Handle both classes and
 	   metaclasses. */
 	   
 	st.init = function(klass) {
@@ -204,32 +245,96 @@ function Smalltalk(){
 		}
 	};
 
-	st.initClass = function(klass) {
-		var subclasses = st.subclasses(klass);
-		var methods, prototype = klass.fn.prototype;
-
-		if(klass.superclass && klass.superclass !== nil) {
-			methods = st.methods(klass.superclass);
-
-			//Methods linking
-			for(var keys = Object.keys(methods), i=0; i<keys.length; i++) {
-				var key = keys[i];
-				if(!prototype.methods[key]) {
-					prototype.inheritedMethods[key] = methods[key];
-					Object.defineProperty(prototype, methods[key].jsSelector, {
-						value: methods[key].fn, configurable: true, writable: true
-					});
+    st.initClass = function(klass) {
+        if(klass.wrapped) {
+            copySuperclass(klass);
+        } else {
+            installSuperclass(klass);
+        }
+
+        if(klass === smalltalk.Object || klass.wrapped) {
+            installDNUHandlers(klass);
+        }
+    };
+
+    var installSuperclass = function(klass) {
+        if(klass.superclass && klass.superclass !== nil) {
+            // klass.fn.prototype = new klass.superclass.fn();
+            // klass.fn.prototype.constructor = klass.fn;
+            reinstallMethods(klass);
+        }
+    };
+
+    var copySuperclass = function(klass, superclass) {
+        superclass = superclass || klass.superclass;
+        if(superclass && superclass !== nil) {
+			for(var keys = Object.keys(superclass.methods), i=0; i<keys.length; i++) {
+                var method = superclass.methods[keys[i]];
+				if(!klass.fn.prototype[method.jsSelector]) {
+                    installMethod(method, klass);
 				}
 			}
-		}
+            if(superclass.superclass) {
+                copySuperclass(klass, superclass.superclass);
+            }
+        }
+    };
+
+    var installMethod = function(method, klass) {
+        Object.defineProperty(klass.fn.prototype, method.jsSelector, {
+			value: method.fn, configurable: true, writable: true
+		});
+    };
 
-		for(var i=0; i<subclasses.length; i++) {
-			st.initClass(subclasses[i]);
+    var reinstallMethods = function(klass) {
+        for(var keys = Object.keys(klass.methods), i=0; i<keys.length; i++) {
+            installMethod(klass.methods[keys[i]], klass)
 		}
-	};
+    };
 
 
+	// st.initClass = function(klass) {
+	// 	var subclasses = st.subclasses(klass);
+	// 	var methods, prototype = klass.fn.prototype;
+
+	// 	if(klass.superclass && klass.superclass !== nil) {
+	// 		methods = st.allMethods(klass.superclass);
+
+	// 		// Methods linking
+	// 		for(var keys = Object.keys(methods), i=0; i<keys.length; i++) {
+	// 			var key = keys[i];
+	// 			if(!klass.methods[key]) {
+	// 				klass.inheritedMethods[key] = methods[key];
+	// 				Object.defineProperty(prototype, methods[key].jsSelector, {
+	// 					value: methods[key].fn, configurable: true, writable: true
+	// 				});
+	// 			}
+	// 		}
+	// 	}
+
+	// 	for(var i=0; i<subclasses.length; i++) {
+	// 		st.initClass(subclasses[i]);
+	// 	}
+	// };
+
+    /* Install all DNU methods in klass */
+
+    installDNUHandlers = function(klass) {
+        console.log('installing DNU handlers for ' + klass.className);
+        var prototype = klass.fn.prototype;
+
+        for(var i=0; i<dnuHandlers.length; i++) {
+            var selector = dnuHandlers[i]._asSelector();
+            if(!prototype[selector]) {
+                Object.defineProperty(prototype, selector, {
+                    value: dnu(selector), configurable: true, writable: true
+                });
+            }
+        }
+    };
+
 	/* Answer all registered Packages as Array */
+    // TODO: Remove this hack
 
 	st.packages.all = function() {
 		var packages = [];
@@ -241,6 +346,7 @@ function Smalltalk(){
 	};
 
 	/* Answer all registered Smalltalk classes */
+    //TODO: register classes in an array!
 
 	st.classes = function() {
 		var classes = [], names = Object.keys(st), l = names.length;
@@ -256,18 +362,18 @@ function Smalltalk(){
 
 	/* Answer all methods (included inherited ones) of klass. */
 
-	st.methods = function(klass) {
-		var methods = {};
-		inheritedMethods = klass.fn.prototype.inheritedMethods;
-		for(var i=0, keys=Object.keys(inheritedMethods); i<keys.length; i++) {
-			methods[keys[i]] = inheritedMethods[keys[i]];
-		}
-		var inheritedMethods = klass.fn.prototype.methods;
-		for(var i=0, keys=Object.keys(inheritedMethods); i<keys.length; i++) {
-			methods[keys[i]] = inheritedMethods[keys[i]];
-		}
-		return methods;
-	};
+	// st.allMethods = function(klass) {
+	// 	var methods = {};
+	// 	var inheritedMethods = klass.inheritedMethods;
+	// 	for(var i=0, keys=Object.keys(inheritedMethods); i<keys.length; i++) {
+	// 		methods[keys[i]] = inheritedMethods[keys[i]];
+	// 	}
+	// 	inheritedMethods = klass.methods;
+	// 	for(var i=0, keys=Object.keys(inheritedMethods); i<keys.length; i++) {
+	// 		methods[keys[i]] = inheritedMethods[keys[i]];
+	// 	}
+	// 	return methods;
+	// };
 
 
 	/* Answer the direct subclasses of klass. */
@@ -295,13 +401,17 @@ function Smalltalk(){
 	/* Create a new class wrapping a JavaScript constructor, and add it to the 
 	   global smalltalk object. Package is lazily created if it does not exist with given name. */
 
-	st.wrapClassName = function(className, pkgName, fn, superclass) {
+	st.wrapClassName = function(className, pkgName, fn, superclass, wrapped) {
+        if(wrapped !== false) {
+            wrapped = true;
+        }
 		var pkg = st.addPackage(pkgName);
 		st[className] = klass({
 			className:  className, 
 			superclass: superclass,
 			pkg:        pkg, 
-			fn:         fn
+			fn:         fn,
+            wrapped:    wrapped
 		});
 	};
 
@@ -361,11 +471,15 @@ function Smalltalk(){
 		Object.defineProperty(klass.fn.prototype, jsSelector, {
 			value: method.fn, configurable: true, writable: true
 		});
-		klass.fn.prototype.methods[method.selector] = method;
+		klass.methods[method.selector] = method;
 		method.methodClass = klass;
 		method.jsSelector = jsSelector;
 
         klass.organization.addElement(method.category);
+
+        for(var i=0; i<method.messageSends.length; i++) {
+            addDnuHandler(method.messageSends[i]);
+        };
 	};
 
     st.removeMethod = function(method) {
@@ -374,10 +488,10 @@ function Smalltalk(){
         var klass = method.methodClass;
 
         delete klass.fn.prototype[method.selector._asSelector()];
-	    delete klass.fn.prototype.methods[method.selector];
+	    delete klass.methods[method.selector];
 
-        for(var i=0; i<klass.fn.prototype.methods; i++) {
-            if(klass.fn.prototype.methods[i].category == protocol) {
+        for(var i=0; i<klass.methods; i++) {
+            if(klass.methods[i].category == protocol) {
                 shouldDeleteProtocol = true;
             };
         };
@@ -610,22 +724,77 @@ if(this.jQuery) {
 	this.jQuery.allowJavaScriptCalls = true;
 }
 
-/****************************************************************************************/
 
+/***************************************** BOOTSTRAP ******************************************/
+
+/* Boostrap Object, Behavior, Class and Metaclass */
+// (function() {
+//     var objectClass, behaviorClass, classClass, metaclassClass;
+    
+//     var setupMetaclass = function(metaclass) {
+//         metaclass = new SmalltalkMetaclass();
+//         metaclass.fn = function() {};
+//         metaclass.fn.prototype = new SmalltalkClass();
+//     };
+
+//     objectClass = new SmalltalkMetaclass();
+//     objectClass.fn = function() {};
+//     objectClass.fn.prototype = new SmalltalkClass();
+
+//     behaviorClass = new SmalltalkMetaclass();
+//     behaviorClass.fn = function() {};
+//     behaviorClass.fn.prototype = new SmalltalkClass();
+
+//     classClass = new SmalltalkMetaclass();
+//     classClass.fn = function() {};
+//     classClass.fn.prototype = new SmalltalkClass();
+
+//     metaclassClass = new SmalltalkMetaclass();
+//     metaclassClass.fn = function() {};
+//     metaclassClass.fn.prototype = new SmalltalkClass();
+
+//     smalltalk.Behavior = new behaviorClass.fn();
+//     smalltalk.Behavior.fn = SmalltalkBehavior;
+//     smalltalk.Behavior.klass = behaviorClass;
+//     behaviorClass.superclass = smalltalk.Class;
+
+//     smalltalk.Class = new classClass.fn();
+//     smalltalk.Class.fn = SmalltalkClass;
+//     smalltalk.Class.klass = classClass;
+//     classClass.superclass = smalltalk.Class;
+
+//     smalltalk.Metaclass = new metaclassClass.fn();
+//     smalltalk.Metaclass.fn = SmalltalkMetaclass;
+//     smalltalk.Metaclass.klass = metaclassClass;
+//     metaclassClass.superclass = smalltalk.Class;
+
+//     smalltalk.Object = new objectClass.fn();
+//     smalltalk.Object.fn = SmalltalkObject;
+//     smalltalk.Object.klass = objectClass;
+//     objectClass.superclass = smalltalk.Class;
+
+//     smalltalk.setupClass(objectClass);
+//     smalltalk.setupClass(behaviorClass);
+//     smalltalk.setupClass(classClass);
+//     smalltalk.setupClass(metaclassClass);
+//     smalltalk.setupClass(smalltalk.Object);
+//     smalltalk.setupClass(smalltalk.Behavior);
+//     smalltalk.setupClass(smalltalk.Class);
+//     smalltalk.setupClass(smalltalk.Metaclass);
+// })();
+
+
+smalltalk.wrapClassName("Object", "Kernel-Objects", SmalltalkObject, false);
+smalltalk.wrapClassName("Behavior", "Kernel-Classes", SmalltalkBehavior, smalltalk.Object, false);
+smalltalk.wrapClassName("Metaclass", "Kernel-Classes", SmalltalkMetaclass, smalltalk.Behavior, false);
+smalltalk.wrapClassName("Class", "Kernel-Classes", SmalltalkClass, smalltalk.Behavior, false);
 
-/* Base classes wrapping. If you edit this part, do not forget to set the superclass of the
-   object metaclass to Class after the definition of Object */
+smalltalk.wrapClassName("Smalltalk", "Kernel-Objects", Smalltalk, smalltalk.Object, false);
+smalltalk.wrapClassName("Package", "Kernel-Objects", SmalltalkPackage, smalltalk.Object, false);
+smalltalk.wrapClassName("CompiledMethod", "Kernel-Objects", SmalltalkMethod, smalltalk.Object, false);
+smalltalk.wrapClassName("Organizer", "Kernel-Objects", SmalltalkOrganizer, smalltalk.Object, false);
 
-smalltalk.wrapClassName("Object", "Kernel", SmalltalkObject);
-smalltalk.wrapClassName("Smalltalk", "Kernel", Smalltalk, smalltalk.Object);
-smalltalk.wrapClassName("Package", "Kernel", SmalltalkPackage, smalltalk.Object);
-smalltalk.wrapClassName("Behavior", "Kernel", SmalltalkBehavior, smalltalk.Object);
-smalltalk.wrapClassName("Class", "Kernel", SmalltalkClass, smalltalk.Behavior);
-smalltalk.wrapClassName("Metaclass", "Kernel", SmalltalkMetaclass, smalltalk.Behavior);
-smalltalk.wrapClassName("CompiledMethod", "Kernel", SmalltalkMethod, smalltalk.Object);
-smalltalk.wrapClassName("Organizer", "Kernel-Objects", SmalltalkOrganizer, smalltalk.Object);
 
-smalltalk.Object.klass.superclass = smalltalk.Class;
 
 smalltalk.wrapClassName("Number", "Kernel", Number, smalltalk.Object);
 smalltalk.wrapClassName("BlockClosure", "Kernel", Function, smalltalk.Object);
@@ -633,16 +802,16 @@ smalltalk.wrapClassName("Boolean", "Kernel", Boolean, smalltalk.Object);
 smalltalk.wrapClassName("Date", "Kernel", Date, smalltalk.Object);
 smalltalk.wrapClassName("UndefinedObject", "Kernel", SmalltalkNil, smalltalk.Object);
 
-smalltalk.wrapClassName("Collection", "Kernel", null, smalltalk.Object);
-smalltalk.wrapClassName("SequenceableCollection", "Kernel", null, smalltalk.Collection);
-smalltalk.wrapClassName("CharacterArray", "Kernel", null, smalltalk.SequenceableCollection);
+smalltalk.wrapClassName("Collection", "Kernel", null, smalltalk.Object, false);
+smalltalk.wrapClassName("SequenceableCollection", "Kernel", null, smalltalk.Collection, false);
+smalltalk.wrapClassName("CharacterArray", "Kernel", null, smalltalk.SequenceableCollection, false);
 smalltalk.wrapClassName("String", "Kernel", String, smalltalk.CharacterArray);
-smalltalk.wrapClassName("Symbol", "Kernel", SmalltalkSymbol, smalltalk.CharacterArray);
+smalltalk.wrapClassName("Symbol", "Kernel", SmalltalkSymbol, smalltalk.CharacterArray, false);
 smalltalk.wrapClassName("Array", "Kernel", Array, smalltalk.SequenceableCollection);
 smalltalk.wrapClassName("RegularExpression", "Kernel", RegExp, smalltalk.String);
 
 smalltalk.wrapClassName("Error", "Kernel", Error, smalltalk.Object);
-smalltalk.wrapClassName("MethodContext", "Kernel", SmalltalkMethodContext, smalltalk.Object);
+smalltalk.wrapClassName("MethodContext", "Kernel", SmalltalkMethodContext, smalltalk.Object, false);
 
 /* Alias definitions */