|
@@ -50,13 +50,13 @@ if(typeof console === "undefined") {
|
|
Array.prototype.addElement = function(el) {
|
|
Array.prototype.addElement = function(el) {
|
|
if(typeof el === 'undefined') { return; }
|
|
if(typeof el === 'undefined') { return; }
|
|
if(this.indexOf(el) == -1) {
|
|
if(this.indexOf(el) == -1) {
|
|
- this.push(el);
|
|
|
|
- }
|
|
|
|
|
|
+ this.push(el);
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
Array.prototype.removeElement = function(el) {
|
|
Array.prototype.removeElement = function(el) {
|
|
- var i = this.indexOf(el);
|
|
|
|
- if (i !== -1) { this.splice(i, 1); }
|
|
|
|
|
|
+ var i = this.indexOf(el);
|
|
|
|
+ if (i !== -1) { this.splice(i, 1); }
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -76,11 +76,11 @@ function SmalltalkOrganizer() {
|
|
}
|
|
}
|
|
|
|
|
|
function SmalltalkPackageOrganizer() {
|
|
function SmalltalkPackageOrganizer() {
|
|
- this.elements = [];
|
|
|
|
|
|
+ this.elements = [];
|
|
}
|
|
}
|
|
|
|
|
|
function SmalltalkClassOrganizer() {
|
|
function SmalltalkClassOrganizer() {
|
|
- this.elements = [];
|
|
|
|
|
|
+ this.elements = [];
|
|
}
|
|
}
|
|
|
|
|
|
function inherits(child, parent) {
|
|
function inherits(child, parent) {
|
|
@@ -106,13 +106,13 @@ function Smalltalk() {
|
|
var st = this;
|
|
var st = this;
|
|
|
|
|
|
/* This is the current call context object. While it is publicly available,
|
|
/* This is the current call context object. While it is publicly available,
|
|
- Use smalltalk.getThisContext() instead which will answer a safe copy of
|
|
|
|
- the current context */
|
|
|
|
|
|
+ Use smalltalk.getThisContext() instead which will answer a safe copy of
|
|
|
|
+ the current context */
|
|
|
|
|
|
st.thisContext = undefined;
|
|
st.thisContext = undefined;
|
|
|
|
|
|
/* List of all reserved words in JavaScript. They may not be used as variables
|
|
/* List of all reserved words in JavaScript. They may not be used as variables
|
|
- in Smalltalk. */
|
|
|
|
|
|
+ in Smalltalk. */
|
|
|
|
|
|
// list of reserved JavaScript keywords as of
|
|
// list of reserved JavaScript keywords as of
|
|
// http://es5.github.com/#x7.6.1.1
|
|
// http://es5.github.com/#x7.6.1.1
|
|
@@ -128,14 +128,14 @@ function Smalltalk() {
|
|
'implements', 'interface', 'let', 'package', 'private', 'protected',
|
|
'implements', 'interface', 'let', 'package', 'private', 'protected',
|
|
'public', 'static', 'yield'];
|
|
'public', 'static', 'yield'];
|
|
|
|
|
|
- var initialized = false;
|
|
|
|
|
|
+ var initialized = false;
|
|
|
|
|
|
- /* Smalltalk classes */
|
|
|
|
|
|
+ /* Smalltalk classes */
|
|
|
|
|
|
- var classes = [];
|
|
|
|
- var wrappedClasses = [];
|
|
|
|
|
|
+ var classes = [];
|
|
|
|
+ var wrappedClasses = [];
|
|
|
|
|
|
- /* Method not implemented handlers */
|
|
|
|
|
|
+ /* Method not implemented handlers */
|
|
|
|
|
|
var dnu = {
|
|
var dnu = {
|
|
methods: [],
|
|
methods: [],
|
|
@@ -163,11 +163,11 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- /* Answer all method selectors based on dnu handlers */
|
|
|
|
|
|
+ /* Answer all method selectors based on dnu handlers */
|
|
|
|
|
|
- st.allSelectors = function() {
|
|
|
|
- return dnu.selectors;
|
|
|
|
- };
|
|
|
|
|
|
+ st.allSelectors = function() {
|
|
|
|
+ return dnu.selectors;
|
|
|
|
+ };
|
|
|
|
|
|
/* Unique ID number generator */
|
|
/* Unique ID number generator */
|
|
|
|
|
|
@@ -186,15 +186,15 @@ function Smalltalk() {
|
|
function pkg(spec) {
|
|
function pkg(spec) {
|
|
var that = new SmalltalkPackage();
|
|
var that = new SmalltalkPackage();
|
|
that.pkgName = spec.pkgName;
|
|
that.pkgName = spec.pkgName;
|
|
- that.organization = new SmalltalkPackageOrganizer();
|
|
|
|
|
|
+ that.organization = new SmalltalkPackageOrganizer();
|
|
that.properties = spec.properties || {};
|
|
that.properties = spec.properties || {};
|
|
return that;
|
|
return that;
|
|
}
|
|
}
|
|
|
|
|
|
/* Smalltalk class creation. A class is an instance of an automatically
|
|
/* Smalltalk class creation. A class is an instance of an automatically
|
|
- created metaclass object. Newly created classes (not their metaclass)
|
|
|
|
- should be added to the smalltalk object, see smalltalk.addClass().
|
|
|
|
- Superclass linking is *not* handled here, see smalltalk.init() */
|
|
|
|
|
|
+ created metaclass object. Newly created classes (not their metaclass)
|
|
|
|
+ should be added to the smalltalk object, see smalltalk.addClass().
|
|
|
|
+ Superclass linking is *not* handled here, see smalltalk.init() */
|
|
|
|
|
|
function klass(spec) {
|
|
function klass(spec) {
|
|
spec = spec || {};
|
|
spec = spec || {};
|
|
@@ -203,8 +203,8 @@ function Smalltalk() {
|
|
that.fn = spec.fn || function() {};
|
|
that.fn = spec.fn || function() {};
|
|
setupClass(that, spec);
|
|
setupClass(that, spec);
|
|
|
|
|
|
- that.className = spec.className;
|
|
|
|
- that.wrapped = spec.wrapped || false;
|
|
|
|
|
|
+ that.className = spec.className;
|
|
|
|
+ that.wrapped = spec.wrapped || false;
|
|
meta.className = spec.className + ' class';
|
|
meta.className = spec.className + ' class';
|
|
if(spec.superclass) {
|
|
if(spec.superclass) {
|
|
that.superclass = spec.superclass;
|
|
that.superclass = spec.superclass;
|
|
@@ -221,22 +221,22 @@ function Smalltalk() {
|
|
spec.superclass ? spec.superclass.klass.fn : SmalltalkClass
|
|
spec.superclass ? spec.superclass.klass.fn : SmalltalkClass
|
|
);
|
|
);
|
|
that.instanceClass = new that.fn();
|
|
that.instanceClass = new that.fn();
|
|
- setupClass(that);
|
|
|
|
|
|
+ setupClass(that);
|
|
return that;
|
|
return that;
|
|
}
|
|
}
|
|
|
|
|
|
function setupClass(klass, spec) {
|
|
function setupClass(klass, spec) {
|
|
- spec = spec || {};
|
|
|
|
|
|
+ spec = spec || {};
|
|
klass.iVarNames = spec.iVarNames || [];
|
|
klass.iVarNames = spec.iVarNames || [];
|
|
klass.pkg = spec.pkg;
|
|
klass.pkg = spec.pkg;
|
|
|
|
|
|
- Object.defineProperty(klass, "toString", {
|
|
|
|
|
|
+ Object.defineProperty(klass, "toString", {
|
|
value: function() { return 'Smalltalk ' + this.className; },
|
|
value: function() { return 'Smalltalk ' + this.className; },
|
|
- enumerable:false, configurable: true, writable: false
|
|
|
|
|
|
+ enumerable:false, configurable: true, writable: false
|
|
});
|
|
});
|
|
|
|
|
|
klass.organization = new SmalltalkClassOrganizer();
|
|
klass.organization = new SmalltalkClassOrganizer();
|
|
- klass.organization.theClass = klass;
|
|
|
|
|
|
+ klass.organization.theClass = klass;
|
|
|
|
|
|
Object.defineProperty(klass, "methods", {
|
|
Object.defineProperty(klass, "methods", {
|
|
value: {},
|
|
value: {},
|
|
@@ -246,7 +246,7 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
/* Smalltalk method object. To add a method to a class,
|
|
/* Smalltalk method object. To add a method to a class,
|
|
- use smalltalk.addMethod() */
|
|
|
|
|
|
+ use smalltalk.addMethod() */
|
|
|
|
|
|
st.method = function(spec) {
|
|
st.method = function(spec) {
|
|
var that = new SmalltalkMethod();
|
|
var that = new SmalltalkMethod();
|
|
@@ -262,7 +262,7 @@ function Smalltalk() {
|
|
};
|
|
};
|
|
|
|
|
|
/* Initialize a class in its class hierarchy. Handle both classes and
|
|
/* Initialize a class in its class hierarchy. Handle both classes and
|
|
- metaclasses. */
|
|
|
|
|
|
+ metaclasses. */
|
|
|
|
|
|
st.init = function(klass) {
|
|
st.init = function(klass) {
|
|
st.initClass(klass);
|
|
st.initClass(klass);
|
|
@@ -271,18 +271,17 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- st.initClass = function(klass) {
|
|
|
|
- if(klass.wrapped) {
|
|
|
|
- copySuperclass(klass);
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- installSuperclass(klass);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(klass === st.Object || klass.wrapped) {
|
|
|
|
- installDnuHandlers(klass);
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ st.initClass = function(klass) {
|
|
|
|
+ if(klass.wrapped) {
|
|
|
|
+ copySuperclass(klass);
|
|
|
|
+ } else {
|
|
|
|
+ installSuperclass(klass);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(klass === st.Object || klass.wrapped) {
|
|
|
|
+ installDnuHandlers(klass);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
function wireKlass(klass) {
|
|
function wireKlass(klass) {
|
|
Object.defineProperty(klass.fn.prototype, "klass", {
|
|
Object.defineProperty(klass.fn.prototype, "klass", {
|
|
@@ -292,20 +291,20 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
function installSuperclass(klass) {
|
|
function installSuperclass(klass) {
|
|
- // only if the klass has not been initialized yet.
|
|
|
|
|
|
+ // only if the klass has not been initialized yet.
|
|
if(klass.fn.prototype._yourself) { return; }
|
|
if(klass.fn.prototype._yourself) { return; }
|
|
|
|
|
|
if(klass.superclass && klass.superclass !== nil) {
|
|
if(klass.superclass && klass.superclass !== nil) {
|
|
- inherits(klass.fn, klass.superclass.fn);
|
|
|
|
|
|
+ inherits(klass.fn, klass.superclass.fn);
|
|
wireKlass(klass);
|
|
wireKlass(klass);
|
|
reinstallMethods(klass);
|
|
reinstallMethods(klass);
|
|
- }
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
function copySuperclass(klass, superclass) {
|
|
function copySuperclass(klass, superclass) {
|
|
for (superclass = superclass || klass.superclass;
|
|
for (superclass = superclass || klass.superclass;
|
|
- superclass && superclass !== nil;
|
|
|
|
- superclass = superclass.superclass) {
|
|
|
|
|
|
+ superclass && superclass !== nil;
|
|
|
|
+ superclass = superclass.superclass) {
|
|
for (var keys = Object.keys(superclass.methods), i = 0; i < keys.length; i++) {
|
|
for (var keys = Object.keys(superclass.methods), i = 0; i < keys.length; i++) {
|
|
installMethodIfAbsent(superclass.methods[keys[i]], klass);
|
|
installMethodIfAbsent(superclass.methods[keys[i]], klass);
|
|
}
|
|
}
|
|
@@ -313,7 +312,7 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
function installMethod(method, klass) {
|
|
function installMethod(method, klass) {
|
|
- Object.defineProperty(klass.fn.prototype, method.jsSelector, {
|
|
|
|
|
|
+ Object.defineProperty(klass.fn.prototype, method.jsSelector, {
|
|
value: method.fn,
|
|
value: method.fn,
|
|
enumerable: false, configurable: true, writable: true
|
|
enumerable: false, configurable: true, writable: true
|
|
});
|
|
});
|
|
@@ -326,16 +325,16 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
function reinstallMethods(klass) {
|
|
function reinstallMethods(klass) {
|
|
- for(var keys = Object.keys(klass.methods), i=0; i<keys.length; i++) {
|
|
|
|
- installMethod(klass.methods[keys[i]], klass);
|
|
|
|
|
|
+ for(var keys = Object.keys(klass.methods), i=0; i<keys.length; i++) {
|
|
|
|
+ installMethod(klass.methods[keys[i]], klass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function installDnuHandlers(klass) {
|
|
function installDnuHandlers(klass) {
|
|
var m = dnu.methods;
|
|
var m = dnu.methods;
|
|
- for(var i=0; i<m.length; i++) {
|
|
|
|
|
|
+ for(var i=0; i<m.length; i++) {
|
|
installMethodIfAbsent(m[i], klass);
|
|
installMethodIfAbsent(m[i], klass);
|
|
- }
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
function installNewDnuHandler(newHandler) {
|
|
function installNewDnuHandler(newHandler) {
|
|
@@ -346,7 +345,7 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
/* Answer all registered Packages as Array */
|
|
/* Answer all registered Packages as Array */
|
|
- // TODO: Remove this hack
|
|
|
|
|
|
+ // TODO: Remove this hack
|
|
|
|
|
|
st.packages.all = function() {
|
|
st.packages.all = function() {
|
|
var packages = [];
|
|
var packages = [];
|
|
@@ -354,19 +353,19 @@ function Smalltalk() {
|
|
if(!st.packages.hasOwnProperty(i) || typeof(st.packages[i]) === "function") continue;
|
|
if(!st.packages.hasOwnProperty(i) || typeof(st.packages[i]) === "function") continue;
|
|
packages.push(st.packages[i]);
|
|
packages.push(st.packages[i]);
|
|
}
|
|
}
|
|
- return packages
|
|
|
|
|
|
+ return packages;
|
|
};
|
|
};
|
|
|
|
|
|
/* Answer all registered Smalltalk classes */
|
|
/* Answer all registered Smalltalk classes */
|
|
- //TODO: remove the function and make smalltalk.classes an array
|
|
|
|
|
|
+ //TODO: remove the function and make smalltalk.classes an array
|
|
|
|
|
|
st.classes = function() {
|
|
st.classes = function() {
|
|
return classes;
|
|
return classes;
|
|
};
|
|
};
|
|
|
|
|
|
- st.wrappedClasses = function() {
|
|
|
|
- return wrappedClasses;
|
|
|
|
- };
|
|
|
|
|
|
+ st.wrappedClasses = function() {
|
|
|
|
+ return wrappedClasses;
|
|
|
|
+ };
|
|
|
|
|
|
/* Answer the direct subclasses of klass. */
|
|
/* Answer the direct subclasses of klass. */
|
|
|
|
|
|
@@ -390,35 +389,37 @@ function Smalltalk() {
|
|
return subclasses;
|
|
return subclasses;
|
|
};
|
|
};
|
|
|
|
|
|
- st.allSubclasses = function(klass) {
|
|
|
|
- var result, subclasses;
|
|
|
|
- result = subclasses = st.subclasses(klass);
|
|
|
|
- subclasses.forEach(function(subclass) {
|
|
|
|
- result.push.apply(result, st.allSubclasses(subclass));
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return result;
|
|
|
|
- };
|
|
|
|
|
|
+ st.allSubclasses = function(klass) {
|
|
|
|
+ var result, subclasses;
|
|
|
|
+ result = subclasses = st.subclasses(klass);
|
|
|
|
+ subclasses.forEach(function(subclass) {
|
|
|
|
+ result.push.apply(result, st.allSubclasses(subclass));
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ };
|
|
|
|
|
|
|
|
|
|
/* Create a new class wrapping a JavaScript constructor, and add it to the
|
|
/* 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. */
|
|
|
|
|
|
+ global smalltalk object. Package is lazily created if it does not exist with given name. */
|
|
|
|
|
|
st.wrapClassName = function(className, pkgName, fn, superclass, wrapped) {
|
|
st.wrapClassName = function(className, pkgName, fn, superclass, wrapped) {
|
|
- if(wrapped !== false) {
|
|
|
|
- wrapped = true;
|
|
|
|
- }
|
|
|
|
|
|
+ if(wrapped !== false) {
|
|
|
|
+ wrapped = true;
|
|
|
|
+ }
|
|
var pkg = st.addPackage(pkgName);
|
|
var pkg = st.addPackage(pkgName);
|
|
st[className] = klass({
|
|
st[className] = klass({
|
|
className: className,
|
|
className: className,
|
|
superclass: superclass,
|
|
superclass: superclass,
|
|
pkg: pkg,
|
|
pkg: pkg,
|
|
fn: fn,
|
|
fn: fn,
|
|
- wrapped: wrapped
|
|
|
|
|
|
+ wrapped: wrapped
|
|
});
|
|
});
|
|
|
|
|
|
- classes.addElement(st[className]);
|
|
|
|
- if(wrapped) {wrappedClasses.addElement(st[className])}
|
|
|
|
|
|
+ classes.addElement(st[className]);
|
|
|
|
+ if(wrapped) {
|
|
|
|
+ wrappedClasses.addElement(st[className]);
|
|
|
|
+ }
|
|
pkg.organization.elements.addElement(st[className]);
|
|
pkg.organization.elements.addElement(st[className]);
|
|
};
|
|
};
|
|
|
|
|
|
@@ -429,8 +430,8 @@ function Smalltalk() {
|
|
};
|
|
};
|
|
|
|
|
|
/* Add a package to the smalltalk.packages object, creating a new one if needed.
|
|
/* Add a package to the smalltalk.packages object, creating a new one if needed.
|
|
- If pkgName is null or empty we return nil, which is an allowed package for a class.
|
|
|
|
- If package already exists we still update the properties of it. */
|
|
|
|
|
|
+ If pkgName is null or empty we return nil, which is an allowed package for a class.
|
|
|
|
+ If package already exists we still update the properties of it. */
|
|
|
|
|
|
st.addPackage = function(pkgName, properties) {
|
|
st.addPackage = function(pkgName, properties) {
|
|
if(!pkgName) {return nil;}
|
|
if(!pkgName) {return nil;}
|
|
@@ -448,18 +449,18 @@ function Smalltalk() {
|
|
};
|
|
};
|
|
|
|
|
|
/* Add a class to the smalltalk object, creating a new one if needed.
|
|
/* Add a class to the smalltalk object, creating a new one if needed.
|
|
- A Package is lazily created if it does not exist with given name. */
|
|
|
|
|
|
+ A Package is lazily created if it does not exist with given name. */
|
|
|
|
|
|
st.addClass = function(className, superclass, iVarNames, pkgName) {
|
|
st.addClass = function(className, superclass, iVarNames, pkgName) {
|
|
var pkg = st.addPackage(pkgName);
|
|
var pkg = st.addPackage(pkgName);
|
|
- if (superclass == nil) { superclass = null; }
|
|
|
|
|
|
+ if (superclass == nil) { superclass = null; }
|
|
if(st[className] && st[className].superclass == superclass) {
|
|
if(st[className] && st[className].superclass == superclass) {
|
|
st[className].superclass = superclass;
|
|
st[className].superclass = superclass;
|
|
st[className].iVarNames = iVarNames;
|
|
st[className].iVarNames = iVarNames;
|
|
st[className].pkg = pkg || st[className].pkg;
|
|
st[className].pkg = pkg || st[className].pkg;
|
|
} else {
|
|
} else {
|
|
- if(st[className]) {
|
|
|
|
- st.removeClass(st[className]);
|
|
|
|
|
|
+ if(st[className]) {
|
|
|
|
+ st.removeClass(st[className]);
|
|
}
|
|
}
|
|
st[className] = klass({
|
|
st[className] = klass({
|
|
className: className,
|
|
className: className,
|
|
@@ -469,114 +470,113 @@ function Smalltalk() {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- classes.addElement(st[className]);
|
|
|
|
- pkg.organization.elements.addElement(st[className]);
|
|
|
|
|
|
+ classes.addElement(st[className]);
|
|
|
|
+ pkg.organization.elements.addElement(st[className]);
|
|
};
|
|
};
|
|
|
|
|
|
- st.removeClass = function(klass) {
|
|
|
|
- klass.pkg.organization.elements.removeElement(klass);
|
|
|
|
- classes.removeElement(klass);
|
|
|
|
- delete st[klass.className];
|
|
|
|
- };
|
|
|
|
|
|
+ st.removeClass = function(klass) {
|
|
|
|
+ klass.pkg.organization.elements.removeElement(klass);
|
|
|
|
+ classes.removeElement(klass);
|
|
|
|
+ delete st[klass.className];
|
|
|
|
+ };
|
|
|
|
|
|
- /*
|
|
|
|
- * Add/remove a method to/from a class
|
|
|
|
- */
|
|
|
|
|
|
+ /* Add/remove a method to/from a class */
|
|
|
|
|
|
- /* This is a temporary version of addMethod() for backward compatibility */
|
|
|
|
|
|
+ /* This is a temporary version of addMethod() for backward compatibility */
|
|
st.addMethod = function(method_exJsSelector, klass_exMethod, exKlass) {
|
|
st.addMethod = function(method_exJsSelector, klass_exMethod, exKlass) {
|
|
- if (typeof method_exJsSelector === "string") { //legacy
|
|
|
|
- if (method_exJsSelector !== st.selector(klass_exMethod.selector)) {
|
|
|
|
- console.log("DISCREPANCY: arg, in_method");
|
|
|
|
- console.log(method_exJsSelector);
|
|
|
|
- console.log(st.selector(klass_exMethod.selector));
|
|
|
|
- klass_exMethod.jsSelector = method_exJsSelector;
|
|
|
|
- }
|
|
|
|
- return new_addMethod(klass_exMethod, exKlass);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return new_addMethod(method_exJsSelector, klass_exMethod);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // later, st.addMethod can be this:
|
|
|
|
- function new_addMethod(method, klass) {
|
|
|
|
- if (!(method.jsSelector)) {
|
|
|
|
- method.jsSelector = st.selector(method.selector);
|
|
|
|
- }
|
|
|
|
|
|
+ if (typeof method_exJsSelector === "string") { //legacy
|
|
|
|
+ if (method_exJsSelector !== st.selector(klass_exMethod.selector)) {
|
|
|
|
+ console.log("DISCREPANCY: arg, in_method");
|
|
|
|
+ console.log(method_exJsSelector);
|
|
|
|
+ console.log(st.selector(klass_exMethod.selector));
|
|
|
|
+ klass_exMethod.jsSelector = method_exJsSelector;
|
|
|
|
+ }
|
|
|
|
+ return new_addMethod(klass_exMethod, exKlass);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return new_addMethod(method_exJsSelector, klass_exMethod);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // later, st.addMethod can be this:
|
|
|
|
+ function new_addMethod(method, klass) {
|
|
|
|
+ if (!(method.jsSelector)) {
|
|
|
|
+ method.jsSelector = st.selector(method.selector);
|
|
|
|
+ }
|
|
installMethod(method, klass);
|
|
installMethod(method, klass);
|
|
klass.methods[method.selector] = method;
|
|
klass.methods[method.selector] = method;
|
|
method.methodClass = klass;
|
|
method.methodClass = klass;
|
|
|
|
|
|
- // During the bootstrap, #addCompiledMethod is not used.
|
|
|
|
- // Therefore we populate the organizer here too
|
|
|
|
- klass.organization.elements.addElement(method.category);
|
|
|
|
-
|
|
|
|
- // If already initialized (else it will be done later anyway),
|
|
|
|
- // re-initialize all subclasses to ensure the new method
|
|
|
|
- // propagation (for wrapped classes, not using the prototype
|
|
|
|
- // chain.
|
|
|
|
- if(initialized) {
|
|
|
|
- st.allSubclasses(klass).forEach(function(subclass) {
|
|
|
|
- st.initClass(subclass);
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for(var i=0; i<method.messageSends.length; i++) {
|
|
|
|
- var dnuHandler = dnu.get(method.messageSends[i]);
|
|
|
|
- if(initialized) {
|
|
|
|
- installNewDnuHandler(dnuHandler);
|
|
|
|
|
|
+ // During the bootstrap, #addCompiledMethod is not used.
|
|
|
|
+ // Therefore we populate the organizer here too
|
|
|
|
+ klass.organization.elements.addElement(method.category);
|
|
|
|
+
|
|
|
|
+ // If already initialized (else it will be done later anyway),
|
|
|
|
+ // re-initialize all subclasses to ensure the new method
|
|
|
|
+ // propagation (for wrapped classes, not using the prototype
|
|
|
|
+ // chain.
|
|
|
|
+ if(initialized) {
|
|
|
|
+ st.allSubclasses(klass).forEach(function(subclass) {
|
|
|
|
+ st.initClass(subclass);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for(var i=0; i<method.messageSends.length; i++) {
|
|
|
|
+ var dnuHandler = dnu.get(method.messageSends[i]);
|
|
|
|
+ if(initialized) {
|
|
|
|
+ installNewDnuHandler(dnuHandler);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- };
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- st.removeMethod = function(method) {
|
|
|
|
- var protocol = method.category;
|
|
|
|
- var klass = method.methodClass;
|
|
|
|
|
|
+ st.removeMethod = function(method) {
|
|
|
|
+ var protocol = method.category;
|
|
|
|
+ var klass = method.methodClass;
|
|
|
|
|
|
- delete klass.fn.prototype[st.selector(method.selector)];
|
|
|
|
- delete klass.methods[method.selector];
|
|
|
|
|
|
+ delete klass.fn.prototype[st.selector(method.selector)];
|
|
|
|
+ delete klass.methods[method.selector];
|
|
|
|
|
|
var selectors = Object.keys(klass.methods);
|
|
var selectors = Object.keys(klass.methods);
|
|
- // Do *not* delete protocols from here.
|
|
|
|
- // This is handled by #removeCompiledMethod
|
|
|
|
- };
|
|
|
|
|
|
+ // Do *not* delete protocols from here.
|
|
|
|
+ // This is handled by #removeCompiledMethod
|
|
|
|
+ };
|
|
|
|
|
|
/* Handles unhandled errors during message sends */
|
|
/* Handles unhandled errors during message sends */
|
|
- // simply send the message and handle #dnu:
|
|
|
|
|
|
+ // simply send the message and handle #dnu:
|
|
|
|
|
|
st.send = function(receiver, selector, args, klass) {
|
|
st.send = function(receiver, selector, args, klass) {
|
|
var method;
|
|
var method;
|
|
- if(receiver == null) {
|
|
|
|
|
|
+ if(receiver === null) {
|
|
receiver = nil;
|
|
receiver = nil;
|
|
}
|
|
}
|
|
method = klass ? klass.fn.prototype[selector] : receiver.klass && receiver[selector];
|
|
method = klass ? klass.fn.prototype[selector] : receiver.klass && receiver[selector];
|
|
if(method) {
|
|
if(method) {
|
|
- return method.apply(receiver, args);
|
|
|
|
|
|
+ return method.apply(receiver, args);
|
|
} else {
|
|
} else {
|
|
return messageNotUnderstood(receiver, selector, args);
|
|
return messageNotUnderstood(receiver, selector, args);
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ };
|
|
|
|
|
|
st.withContext = function(worker, setup) {
|
|
st.withContext = function(worker, setup) {
|
|
if(st.thisContext) {
|
|
if(st.thisContext) {
|
|
- st.thisContext.pc++;
|
|
|
|
|
|
+ st.thisContext.pc++;
|
|
return inContext(worker, setup);
|
|
return inContext(worker, setup);
|
|
} else {
|
|
} else {
|
|
- try {return inContext(worker, setup)}
|
|
|
|
- catch(error) {
|
|
|
|
|
|
+ try {
|
|
|
|
+ return inContext(worker, setup);
|
|
|
|
+ } catch(error) {
|
|
if(error.smalltalkError) {
|
|
if(error.smalltalkError) {
|
|
handleError(error);
|
|
handleError(error);
|
|
- } else {
|
|
|
|
- var errorWrapper = st.JavaScriptException._on_(error);
|
|
|
|
- try {errorWrapper._signal()} catch(ex) {}
|
|
|
|
- errorWrapper._context_(st.getThisContext());
|
|
|
|
- handleError(errorWrapper);
|
|
|
|
- }
|
|
|
|
|
|
+ } else {
|
|
|
|
+ var errorWrapper = st.JavaScriptException._on_(error);
|
|
|
|
+ try {errorWrapper._signal();} catch(ex) {}
|
|
|
|
+ errorWrapper._context_(st.getThisContext());
|
|
|
|
+ handleError(errorWrapper);
|
|
|
|
+ }
|
|
// Reset the context stack in any case
|
|
// Reset the context stack in any case
|
|
st.thisContext = undefined;
|
|
st.thisContext = undefined;
|
|
- // Throw the exception anyway, as we want to stop
|
|
|
|
- // the execution to avoid infinite loops
|
|
|
|
- // Update: do not throw the exception. It's really annoying.
|
|
|
|
|
|
+ // Throw the exception anyway, as we want to stop
|
|
|
|
+ // the execution to avoid infinite loops
|
|
|
|
+ // Update: do not throw the exception. It's really annoying.
|
|
// throw error;
|
|
// throw error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -590,15 +590,15 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
/* Handles Smalltalk errors. Triggers the registered ErrorHandler
|
|
/* Handles Smalltalk errors. Triggers the registered ErrorHandler
|
|
- (See the Smalltalk class ErrorHandler and its subclasses */
|
|
|
|
|
|
+ (See the Smalltalk class ErrorHandler and its subclasses */
|
|
|
|
|
|
function handleError(error) {
|
|
function handleError(error) {
|
|
- st.ErrorHandler._current()._handleError_(error);
|
|
|
|
|
|
+ st.ErrorHandler._current()._handleError_(error);
|
|
}
|
|
}
|
|
|
|
|
|
/* Handles #dnu: *and* JavaScript method calls.
|
|
/* Handles #dnu: *and* JavaScript method calls.
|
|
- if the receiver has no klass, we consider it a JS object (outside of the
|
|
|
|
- Amber system). Else assume that the receiver understands #doesNotUnderstand: */
|
|
|
|
|
|
+ if the receiver has no klass, we consider it a JS object (outside of the
|
|
|
|
+ Amber system). Else assume that the receiver understands #doesNotUnderstand: */
|
|
|
|
|
|
function messageNotUnderstood(receiver, selector, args) {
|
|
function messageNotUnderstood(receiver, selector, args) {
|
|
/* Handles JS method calls. */
|
|
/* Handles JS method calls. */
|
|
@@ -607,7 +607,7 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
/* Handles not understood messages. Also see the Amber counter-part
|
|
/* Handles not understood messages. Also see the Amber counter-part
|
|
- Object>>doesNotUnderstand: */
|
|
|
|
|
|
+ Object>>doesNotUnderstand: */
|
|
|
|
|
|
return receiver._doesNotUnderstand_(
|
|
return receiver._doesNotUnderstand_(
|
|
st.Message._new()
|
|
st.Message._new()
|
|
@@ -617,17 +617,17 @@ function Smalltalk() {
|
|
}
|
|
}
|
|
|
|
|
|
/* Call a method of a JS object, or answer a property if it exists.
|
|
/* Call a method of a JS object, or answer a property if it exists.
|
|
- Else try wrapping a JSObjectProxy around the receiver.
|
|
|
|
|
|
+ Else try wrapping a JSObjectProxy around the receiver.
|
|
|
|
|
|
- If the object property is a function, then call it, except if it starts with
|
|
|
|
- an uppercase character (we probably want to answer the function itself in this
|
|
|
|
- case and send it #new from Amber).
|
|
|
|
|
|
+ If the object property is a function, then call it, except if it starts with
|
|
|
|
+ an uppercase character (we probably want to answer the function itself in this
|
|
|
|
+ case and send it #new from Amber).
|
|
|
|
|
|
- Converts keyword-based selectors by using the first
|
|
|
|
- keyword only, but keeping all message arguments.
|
|
|
|
-
|
|
|
|
- Example:
|
|
|
|
- "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
|
|
|
|
|
|
+ Converts keyword-based selectors by using the first
|
|
|
|
+ keyword only, but keeping all message arguments.
|
|
|
|
+
|
|
|
|
+ Example:
|
|
|
|
+ "self do: aBlock with: anObject" -> "self.do(aBlock, anObject)" */
|
|
|
|
|
|
function callJavaScriptMethod(receiver, selector, args) {
|
|
function callJavaScriptMethod(receiver, selector, args) {
|
|
var jsSelector = selector._asJavaScriptSelector();
|
|
var jsSelector = selector._asJavaScriptSelector();
|
|
@@ -649,16 +649,17 @@ function Smalltalk() {
|
|
/* Handle thisContext pseudo variable */
|
|
/* Handle thisContext pseudo variable */
|
|
|
|
|
|
st.getThisContext = function() {
|
|
st.getThisContext = function() {
|
|
- if(st.thisContext) {
|
|
|
|
- st.thisContext.init();
|
|
|
|
- return st.thisContext;
|
|
|
|
- } else {
|
|
|
|
- return nil;
|
|
|
|
- }
|
|
|
|
|
|
+ if(st.thisContext) {
|
|
|
|
+ st.thisContext.init();
|
|
|
|
+ return st.thisContext;
|
|
|
|
+ } else {
|
|
|
|
+ return nil;
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
function pushContext(setup) {
|
|
function pushContext(setup) {
|
|
- return st.thisContext = new SmalltalkMethodContext(smalltalk.thisContext, setup);
|
|
|
|
|
|
+ st.thisContext = new SmalltalkMethodContext(smalltalk.thisContext, setup);
|
|
|
|
+ return st.thisContext;
|
|
}
|
|
}
|
|
|
|
|
|
function popContext(context) {
|
|
function popContext(context) {
|
|
@@ -667,28 +668,28 @@ function Smalltalk() {
|
|
|
|
|
|
/* Convert a Smalltalk selector into a JS selector */
|
|
/* Convert a Smalltalk selector into a JS selector */
|
|
|
|
|
|
- st.selector = function(string) {
|
|
|
|
- var selector = '_' + string;
|
|
|
|
- selector = selector.replace(/:/g, '_');
|
|
|
|
- selector = selector.replace(/[\&]/g, '_and');
|
|
|
|
- selector = selector.replace(/[\|]/g, '_or');
|
|
|
|
- selector = selector.replace(/[+]/g, '_plus');
|
|
|
|
- selector = selector.replace(/-/g, '_minus');
|
|
|
|
- selector = selector.replace(/[*]/g ,'_star');
|
|
|
|
- selector = selector.replace(/[\/]/g ,'_slash');
|
|
|
|
- selector = selector.replace(/[\\]/g ,'_backslash');
|
|
|
|
- selector = selector.replace(/[\~]/g ,'_tild');
|
|
|
|
- selector = selector.replace(/>/g ,'_gt');
|
|
|
|
- selector = selector.replace(/</g ,'_lt');
|
|
|
|
- selector = selector.replace(/=/g ,'_eq');
|
|
|
|
- selector = selector.replace(/,/g ,'_comma');
|
|
|
|
- selector = selector.replace(/[@]/g ,'_at');
|
|
|
|
- return selector
|
|
|
|
- };
|
|
|
|
|
|
+ st.selector = function(string) {
|
|
|
|
+ var selector = '_' + string;
|
|
|
|
+ selector = selector.replace(/:/g, '_');
|
|
|
|
+ selector = selector.replace(/[\&]/g, '_and');
|
|
|
|
+ selector = selector.replace(/[\|]/g, '_or');
|
|
|
|
+ selector = selector.replace(/[+]/g, '_plus');
|
|
|
|
+ selector = selector.replace(/-/g, '_minus');
|
|
|
|
+ selector = selector.replace(/[*]/g ,'_star');
|
|
|
|
+ selector = selector.replace(/[\/]/g ,'_slash');
|
|
|
|
+ selector = selector.replace(/[\\]/g ,'_backslash');
|
|
|
|
+ selector = selector.replace(/[\~]/g ,'_tild');
|
|
|
|
+ selector = selector.replace(/>/g ,'_gt');
|
|
|
|
+ selector = selector.replace(/</g ,'_lt');
|
|
|
|
+ selector = selector.replace(/=/g ,'_eq');
|
|
|
|
+ selector = selector.replace(/,/g ,'_comma');
|
|
|
|
+ selector = selector.replace(/[@]/g ,'_at');
|
|
|
|
+ return selector;
|
|
|
|
+ };
|
|
|
|
|
|
/* Convert a string to a valid smalltalk selector.
|
|
/* Convert a string to a valid smalltalk selector.
|
|
- if you modify the following functions, also change String>>asSelector
|
|
|
|
- accordingly */
|
|
|
|
|
|
+ if you modify the following functions, also change String>>asSelector
|
|
|
|
+ accordingly */
|
|
|
|
|
|
st.convertSelector = function(selector) {
|
|
st.convertSelector = function(selector) {
|
|
if(selector.match(/__/)) {
|
|
if(selector.match(/__/)) {
|
|
@@ -717,7 +718,7 @@ function Smalltalk() {
|
|
.replace(/_lt/g, '<')
|
|
.replace(/_lt/g, '<')
|
|
.replace(/_eq/g, '=')
|
|
.replace(/_eq/g, '=')
|
|
.replace(/_comma/g, ',')
|
|
.replace(/_comma/g, ',')
|
|
- .replace(/_at/g, '@')
|
|
|
|
|
|
+ .replace(/_at/g, '@');
|
|
}
|
|
}
|
|
|
|
|
|
/* Converts a JavaScript object to valid Smalltalk Object */
|
|
/* Converts a JavaScript object to valid Smalltalk Object */
|
|
@@ -740,40 +741,40 @@ function Smalltalk() {
|
|
return object;
|
|
return object;
|
|
};
|
|
};
|
|
|
|
|
|
- /* Boolean assertion */
|
|
|
|
- st.assert = function(shouldBeBoolean) {
|
|
|
|
- if ((undefined !== shouldBeBoolean) && (shouldBeBoolean.klass === smalltalk.Boolean)) {
|
|
|
|
- return shouldBeBoolean == true;
|
|
|
|
- } else {
|
|
|
|
- smalltalk.NonBooleanReceiver._new()._object_(shouldBeBoolean)._signal();
|
|
|
|
- }
|
|
|
|
|
|
+ /* Boolean assertion */
|
|
|
|
+ st.assert = function(shouldBeBoolean) {
|
|
|
|
+ if ((undefined !== shouldBeBoolean) && (shouldBeBoolean.klass === smalltalk.Boolean)) {
|
|
|
|
+ return (shouldBeBoolean == true);
|
|
|
|
+ } else {
|
|
|
|
+ smalltalk.NonBooleanReceiver._new()._object_(shouldBeBoolean)._signal();
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
- /* Backward compatibility with Amber 0.9.1 */
|
|
|
|
- st.symbolFor = function(aString) { return aString; }
|
|
|
|
-
|
|
|
|
- /* Smalltalk initialization. Called on page load */
|
|
|
|
-
|
|
|
|
- st.initialize = function() {
|
|
|
|
|
|
+ /* Backward compatibility with Amber 0.9.1 */
|
|
|
|
+ st.symbolFor = function(aString) { return aString; };
|
|
|
|
+
|
|
|
|
+ /* Smalltalk initialization. Called on page load */
|
|
|
|
+
|
|
|
|
+ st.initialize = function() {
|
|
if(initialized) { return; }
|
|
if(initialized) { return; }
|
|
|
|
|
|
classes.forEach(function(klass) {
|
|
classes.forEach(function(klass) {
|
|
- st.init(klass);
|
|
|
|
- });
|
|
|
|
- classes.forEach(function(klass) {
|
|
|
|
- klass._initialize();
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- initialized = true;
|
|
|
|
- };
|
|
|
|
|
|
+ st.init(klass);
|
|
|
|
+ });
|
|
|
|
+ classes.forEach(function(klass) {
|
|
|
|
+ klass._initialize();
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ initialized = true;
|
|
|
|
+ };
|
|
}
|
|
}
|
|
|
|
|
|
inherits(Smalltalk, SmalltalkObject);
|
|
inherits(Smalltalk, SmalltalkObject);
|
|
|
|
|
|
function SmalltalkMethodContext(home, setup) {
|
|
function SmalltalkMethodContext(home, setup) {
|
|
this.homeContext = home;
|
|
this.homeContext = home;
|
|
- this.setup = setup || function() {};
|
|
|
|
- this.pc = 0;
|
|
|
|
|
|
+ this.setup = setup || function() {};
|
|
|
|
+ this.pc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
// Fallbacks
|
|
// Fallbacks
|
|
@@ -785,39 +786,41 @@ SmalltalkMethodContext.prototype.lookupClass = null;
|
|
inherits(SmalltalkMethodContext, SmalltalkObject);
|
|
inherits(SmalltalkMethodContext, SmalltalkObject);
|
|
|
|
|
|
SmalltalkMethodContext.prototype.fill = function(receiver, selector, locals, lookupClass) {
|
|
SmalltalkMethodContext.prototype.fill = function(receiver, selector, locals, lookupClass) {
|
|
- this.receiver = receiver;
|
|
|
|
- this.selector = selector;
|
|
|
|
- this.locals = locals || {};
|
|
|
|
- this.lookupClass = lookupClass;
|
|
|
|
|
|
+ this.receiver = receiver;
|
|
|
|
+ this.selector = selector;
|
|
|
|
+ this.locals = locals || {};
|
|
|
|
+ this.lookupClass = lookupClass;
|
|
};
|
|
};
|
|
|
|
|
|
SmalltalkMethodContext.prototype.fillBlock = function(locals, ctx) {
|
|
SmalltalkMethodContext.prototype.fillBlock = function(locals, ctx) {
|
|
- this.locals = locals || {};
|
|
|
|
- this.outerContext = ctx;
|
|
|
|
|
|
+ this.locals = locals || {};
|
|
|
|
+ this.outerContext = ctx;
|
|
};
|
|
};
|
|
|
|
|
|
SmalltalkMethodContext.prototype.init = function() {
|
|
SmalltalkMethodContext.prototype.init = function() {
|
|
var home = this.homeContext;
|
|
var home = this.homeContext;
|
|
- if(home) {home = home.init()}
|
|
|
|
|
|
+ if(home) {
|
|
|
|
+ home = home.init();
|
|
|
|
+ }
|
|
|
|
|
|
this.setup(this);
|
|
this.setup(this);
|
|
};
|
|
};
|
|
|
|
|
|
SmalltalkMethodContext.prototype.method = function() {
|
|
SmalltalkMethodContext.prototype.method = function() {
|
|
- var method;
|
|
|
|
- var lookup = this.lookupClass || this.receiver.klass;
|
|
|
|
- while(!method && lookup) {
|
|
|
|
- method = lookup.methods[smalltalk.convertSelector(this.selector)];
|
|
|
|
- lookup = lookup.superclass
|
|
|
|
- }
|
|
|
|
- return method;
|
|
|
|
|
|
+ var method;
|
|
|
|
+ var lookup = this.lookupClass || this.receiver.klass;
|
|
|
|
+ while(!method && lookup) {
|
|
|
|
+ method = lookup.methods[smalltalk.convertSelector(this.selector)];
|
|
|
|
+ lookup = lookup.superclass;
|
|
|
|
+ }
|
|
|
|
+ return method;
|
|
};
|
|
};
|
|
|
|
|
|
// TODO: this is just wrong :)
|
|
// TODO: this is just wrong :)
|
|
SmalltalkMethodContext.prototype.resume = function() {
|
|
SmalltalkMethodContext.prototype.resume = function() {
|
|
- //Brutally set the receiver as thisContext, then re-enter the function
|
|
|
|
- smalltalk.thisContext = this;
|
|
|
|
- return this.method.apply(receiver, temps);
|
|
|
|
|
|
+ //Brutally set the receiver as thisContext, then re-enter the function
|
|
|
|
+ smalltalk.thisContext = this;
|
|
|
|
+ return this.method.apply(receiver, temps);
|
|
};
|
|
};
|
|
|
|
|
|
/* Global Smalltalk objects. */
|
|
/* Global Smalltalk objects. */
|
|
@@ -835,8 +838,8 @@ if(this.jQuery) {
|
|
*/
|
|
*/
|
|
|
|
|
|
var _st = function(o) {
|
|
var _st = function(o) {
|
|
- if(o == null) {return nil}
|
|
|
|
- if(o.klass) {return o}
|
|
|
|
|
|
+ if(o == null) {return nil;}
|
|
|
|
+ if(o.klass) {return o;}
|
|
return smalltalk.JSObjectProxy._on_(o);
|
|
return smalltalk.JSObjectProxy._on_(o);
|
|
};
|
|
};
|
|
|
|
|