Worked on kotlinJsLib and supported trait extending other trait.
This commit is contained in:
@@ -31,34 +31,20 @@ public final class ClassTranslator extends AbstractTranslator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsStatement translateClass(@NotNull JetClass classDeclaration) {
|
||||
if (!classDeclaration.isTrait()) {
|
||||
return translateAsClassWithState(classDeclaration);
|
||||
} else {
|
||||
return translateAsStatelessTrait(classDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement translateAsStatelessTrait(@NotNull JetClass classDeclaration) {
|
||||
JsObjectLiteral traitLiteral = translateClassDeclarations(classDeclaration);
|
||||
return AstUtil.convertToStatement
|
||||
(AstUtil.newAssignment(namespaceQualifiedClassNameReference(classDeclaration), traitLiteral));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement translateAsClassWithState(@NotNull JetClass jetClassDeclaration) {
|
||||
JsInvocation jsClassDeclaration = createMethodInvocation();
|
||||
public JsStatement translateClass(@NotNull JetClass jetClassDeclaration) {
|
||||
JsInvocation jsClassDeclaration = classCreateMethodInvocation(jetClassDeclaration);
|
||||
addSuperclassReferences(jetClassDeclaration, jsClassDeclaration);
|
||||
addClassOwnDeclarations(jetClassDeclaration, jsClassDeclaration);
|
||||
return classDeclarationStatement(jetClassDeclaration, jsClassDeclaration);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsInvocation createMethodInvocation() {
|
||||
JsInvocation jsClassDeclaration = new JsInvocation();
|
||||
jsClassDeclaration.setQualifier(Namer.creationMethodReference());
|
||||
return jsClassDeclaration;
|
||||
private JsInvocation classCreateMethodInvocation(@NotNull JetClass jetClassDeclaration) {
|
||||
if (jetClassDeclaration.isTrait()) {
|
||||
return AstUtil.newInvocation(Namer.traitCreationMethodReference());
|
||||
} else {
|
||||
return AstUtil.newInvocation(Namer.classCreationMethodReference());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -58,14 +58,18 @@ public final class Namer {
|
||||
return name;
|
||||
}
|
||||
|
||||
//TODO: dummy
|
||||
public static JsNameRef classObjectReference() {
|
||||
//TODO dummy
|
||||
return AstUtil.newQualifiedNameRef("Class");
|
||||
}
|
||||
|
||||
public static JsNameRef creationMethodReference() {
|
||||
public static JsNameRef classCreationMethodReference() {
|
||||
return AstUtil.newQualifiedNameRef("Class.create");
|
||||
}
|
||||
|
||||
public static JsNameRef traitCreationMethodReference() {
|
||||
return AstUtil.newQualifiedNameRef("Trait.create");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -42,12 +42,26 @@ public class KotlinLibTest extends TranslationTest {
|
||||
|
||||
@Test
|
||||
public void classObjectHasCreateMethod() throws Exception {
|
||||
String objectName = "Class";
|
||||
final Map<String, Class<? extends Scriptable>> propertyToType
|
||||
= new HashMap<String, Class<? extends Scriptable>>();
|
||||
propertyToType.put("create", Function.class);
|
||||
runPropertyTypeCheck(objectName, propertyToType);
|
||||
runPropertyTypeCheck("Class", propertyToType);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void traitObjectHasCreateMethod() throws Exception {
|
||||
final Map<String, Class<? extends Scriptable>> propertyToType
|
||||
= new HashMap<String, Class<? extends Scriptable>>();
|
||||
propertyToType.put("create", Function.class);
|
||||
runPropertyTypeCheck("Trait", propertyToType);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createdTraitIsJSObject() throws Exception {
|
||||
final Map<String, Class<? extends Scriptable>> propertyToType
|
||||
= new HashMap<String, Class<? extends Scriptable>>();
|
||||
runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("trait.js")),
|
||||
new RhinoPropertyTypesChecker("foo", propertyToType));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ public abstract class TranslationTest {
|
||||
|
||||
abstract protected List<String> generateFilenameList(String inputfile);
|
||||
|
||||
//TODO: refactor filename generation logic
|
||||
private String getOutputFilePath(String filename) {
|
||||
return getOutputDirectory() + convertToDotJsFile(filename);
|
||||
}
|
||||
@@ -68,6 +69,10 @@ public abstract class TranslationTest {
|
||||
return getInputDirectory() + filename;
|
||||
}
|
||||
|
||||
protected String cases(String filename) {
|
||||
return getInputFilePath(filename);
|
||||
}
|
||||
|
||||
protected void runFileWithRhino(String inputFile, Context context, Scriptable scope) throws Exception {
|
||||
FileReader reader = new FileReader(inputFile);
|
||||
context.evaluateReader(scope, reader, inputFile, 1, null);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
foo = {};
|
||||
(function(foo){
|
||||
foo.Test = Trait.create({addFoo:function(s){
|
||||
return s + 'FOO';
|
||||
}
|
||||
});
|
||||
foo.ExtendedTest = Trait.create(foo.Test, {hooray:function(){
|
||||
return 'hooray';
|
||||
}
|
||||
});
|
||||
}
|
||||
(foo));
|
||||
@@ -66,8 +66,6 @@ var Class = (function() {
|
||||
return function() { return ancestor[m].apply(this, arguments); };
|
||||
})(property).wrap(method);
|
||||
|
||||
// value.valueOf = method.valueOf.bind(method);
|
||||
// value.toString = method.toString.bind(method);
|
||||
}
|
||||
this.prototype[property] = value;
|
||||
}
|
||||
@@ -85,8 +83,25 @@ var Class = (function() {
|
||||
|
||||
var Trait = (function() {
|
||||
|
||||
|
||||
function add(object, source) {
|
||||
properties = Object.keys(source);
|
||||
for (var i = 0, length = properties.length; i < length; i++) {
|
||||
var property = properties[i];
|
||||
var value = source[property];
|
||||
object[property] = value;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
function create() {
|
||||
return new Class.create(arguments);
|
||||
|
||||
result = {}
|
||||
for (var i = 0, length = arguments.length; i < length; i++)
|
||||
{
|
||||
add(result, arguments[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Vendored
+388
@@ -0,0 +1,388 @@
|
||||
function $A(iterable) {
|
||||
if (!iterable) return [];
|
||||
if ('toArray' in Object(iterable)) return iterable.toArray();
|
||||
var length = iterable.length || 0, results = new Array(length);
|
||||
while (length--) results[length] = iterable[length];
|
||||
return results;
|
||||
}
|
||||
|
||||
var emptyFunction = function() {}
|
||||
|
||||
var Class = (function() {
|
||||
|
||||
var IS_DONTENUM_BUGGY = (function(){
|
||||
for (var p in { toString: 1 }) {
|
||||
if (p === 'toString') return false;
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
|
||||
function subclass() {};
|
||||
function create() {
|
||||
var parent = null, properties = $A(arguments);
|
||||
if (Object.isFunction(properties[0]))
|
||||
parent = properties.shift();
|
||||
|
||||
function klass() {
|
||||
this.initialize.apply(this, arguments);
|
||||
}
|
||||
|
||||
Object.extend(klass, Class.Methods);
|
||||
klass.superclass = parent;
|
||||
klass.subclasses = [];
|
||||
|
||||
if (parent) {
|
||||
subclass.prototype = parent.prototype;
|
||||
klass.prototype = new subclass;
|
||||
parent.subclasses.push(klass);
|
||||
}
|
||||
|
||||
for (var i = 0, length = properties.length; i < length; i++)
|
||||
klass.addMethods(properties[i]);
|
||||
|
||||
if (!klass.prototype.initialize)
|
||||
klass.prototype.initialize = emptyFunction;
|
||||
|
||||
klass.prototype.constructor = klass;
|
||||
return klass;
|
||||
}
|
||||
|
||||
function addMethods(source) {
|
||||
var ancestor = this.superclass && this.superclass.prototype,
|
||||
properties = Object.keys(source);
|
||||
|
||||
if (IS_DONTENUM_BUGGY) {
|
||||
if (source.toString != Object.prototype.toString)
|
||||
properties.push("toString");
|
||||
if (source.valueOf != Object.prototype.valueOf)
|
||||
properties.push("valueOf");
|
||||
}
|
||||
|
||||
for (var i = 0, length = properties.length; i < length; i++) {
|
||||
var property = properties[i], value = source[property];
|
||||
if (ancestor && Object.isFunction(value) &&
|
||||
value.argumentNames()[0] == "$super") {
|
||||
var method = value;
|
||||
value = (function(m) {
|
||||
return function() { return ancestor[m].apply(this, arguments); };
|
||||
})(property).wrap(method);
|
||||
|
||||
value.valueOf = method.valueOf.bind(method);
|
||||
value.toString = method.toString.bind(method);
|
||||
}
|
||||
this.prototype[property] = value;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
return {
|
||||
create: create,
|
||||
Methods: {
|
||||
addMethods: addMethods
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
var Trait = (function() {
|
||||
|
||||
function create() {
|
||||
var traitClass = Class.create.apply(Class, arguments)
|
||||
return new traitClass;
|
||||
}
|
||||
|
||||
return {
|
||||
create: create
|
||||
};
|
||||
})();
|
||||
|
||||
(function() {
|
||||
|
||||
var _toString = Object.prototype.toString,
|
||||
NULL_TYPE = 'Null',
|
||||
UNDEFINED_TYPE = 'Undefined',
|
||||
BOOLEAN_TYPE = 'Boolean',
|
||||
NUMBER_TYPE = 'Number',
|
||||
STRING_TYPE = 'String',
|
||||
OBJECT_TYPE = 'Object',
|
||||
FUNCTION_CLASS = '[object Function]',
|
||||
BOOLEAN_CLASS = '[object Boolean]',
|
||||
NUMBER_CLASS = '[object Number]',
|
||||
STRING_CLASS = '[object String]',
|
||||
ARRAY_CLASS = '[object Array]',
|
||||
DATE_CLASS = '[object Date]';
|
||||
|
||||
function Type(o) {
|
||||
switch(o) {
|
||||
case null: return NULL_TYPE;
|
||||
case (void 0): return UNDEFINED_TYPE;
|
||||
}
|
||||
var type = typeof o;
|
||||
switch(type) {
|
||||
case 'boolean': return BOOLEAN_TYPE;
|
||||
case 'number': return NUMBER_TYPE;
|
||||
case 'string': return STRING_TYPE;
|
||||
}
|
||||
return OBJECT_TYPE;
|
||||
}
|
||||
|
||||
function extend(destination, source) {
|
||||
for (var property in source)
|
||||
destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
function inspect(object) {
|
||||
try {
|
||||
if (isUndefined(object)) return 'undefined';
|
||||
if (object === null) return 'null';
|
||||
return object.inspect ? object.inspect() : String(object);
|
||||
} catch (e) {
|
||||
if (e instanceof RangeError) return '...';
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function toJSON(value) {
|
||||
return Str('', { '': value }, []);
|
||||
}
|
||||
|
||||
function Str(key, holder, stack) {
|
||||
var value = holder[key],
|
||||
type = typeof value;
|
||||
|
||||
if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
|
||||
value = value.toJSON(key);
|
||||
}
|
||||
|
||||
var _class = _toString.call(value);
|
||||
|
||||
switch (_class) {
|
||||
case NUMBER_CLASS:
|
||||
case BOOLEAN_CLASS:
|
||||
case STRING_CLASS:
|
||||
value = value.valueOf();
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case null: return 'null';
|
||||
case true: return 'true';
|
||||
case false: return 'false';
|
||||
}
|
||||
|
||||
type = typeof value;
|
||||
switch (type) {
|
||||
case 'string':
|
||||
return value.inspect(true);
|
||||
case 'number':
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
case 'object':
|
||||
|
||||
for (var i = 0, length = stack.length; i < length; i++) {
|
||||
if (stack[i] === value) { throw new TypeError(); }
|
||||
}
|
||||
stack.push(value);
|
||||
|
||||
var partial = [];
|
||||
if (_class === ARRAY_CLASS) {
|
||||
for (var i = 0, length = value.length; i < length; i++) {
|
||||
var str = Str(i, value, stack);
|
||||
partial.push(typeof str === 'undefined' ? 'null' : str);
|
||||
}
|
||||
partial = '[' + partial.join(',') + ']';
|
||||
} else {
|
||||
var keys = Object.keys(value);
|
||||
for (var i = 0, length = keys.length; i < length; i++) {
|
||||
var key = keys[i], str = Str(key, value, stack);
|
||||
if (typeof str !== "undefined") {
|
||||
partial.push(key.inspect(true)+ ':' + str);
|
||||
}
|
||||
}
|
||||
partial = '{' + partial.join(',') + '}';
|
||||
}
|
||||
stack.pop();
|
||||
return partial;
|
||||
}
|
||||
}
|
||||
|
||||
function stringify(object) {
|
||||
return JSON.stringify(object);
|
||||
}
|
||||
|
||||
function toQueryString(object) {
|
||||
return $H(object).toQueryString();
|
||||
}
|
||||
|
||||
function toHTML(object) {
|
||||
return object && object.toHTML ? object.toHTML() : String.interpret(object);
|
||||
}
|
||||
|
||||
function keys(object) {
|
||||
if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
|
||||
var results = [];
|
||||
for (var property in object) {
|
||||
if (object.hasOwnProperty(property)) {
|
||||
results.push(property);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function values(object) {
|
||||
var results = [];
|
||||
for (var property in object)
|
||||
results.push(object[property]);
|
||||
return results;
|
||||
}
|
||||
|
||||
function clone(object) {
|
||||
return extend({ }, object);
|
||||
}
|
||||
|
||||
function isElement(object) {
|
||||
return !!(object && object.nodeType == 1);
|
||||
}
|
||||
|
||||
function isArray(object) {
|
||||
return _toString.call(object) === ARRAY_CLASS;
|
||||
}
|
||||
|
||||
var hasNativeIsArray = (typeof Array.isArray == 'function')
|
||||
&& Array.isArray([]) && !Array.isArray({});
|
||||
|
||||
if (hasNativeIsArray) {
|
||||
isArray = Array.isArray;
|
||||
}
|
||||
|
||||
function isHash(object) {
|
||||
return object instanceof Hash;
|
||||
}
|
||||
|
||||
function isFunction(object) {
|
||||
return _toString.call(object) === FUNCTION_CLASS;
|
||||
}
|
||||
|
||||
function isString(object) {
|
||||
return _toString.call(object) === STRING_CLASS;
|
||||
}
|
||||
|
||||
function isNumber(object) {
|
||||
return _toString.call(object) === NUMBER_CLASS;
|
||||
}
|
||||
|
||||
function isDate(object) {
|
||||
return _toString.call(object) === DATE_CLASS;
|
||||
}
|
||||
|
||||
function isUndefined(object) {
|
||||
return typeof object === "undefined";
|
||||
}
|
||||
|
||||
extend(Object, {
|
||||
extend: extend,
|
||||
inspect: inspect,
|
||||
toQueryString: toQueryString,
|
||||
toHTML: toHTML,
|
||||
keys: Object.keys || keys,
|
||||
values: values,
|
||||
clone: clone,
|
||||
isElement: isElement,
|
||||
isArray: isArray,
|
||||
isHash: isHash,
|
||||
isFunction: isFunction,
|
||||
isString: isString,
|
||||
isNumber: isNumber,
|
||||
isDate: isDate,
|
||||
isUndefined: isUndefined
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
Object.extend(Function.prototype, (function() {
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
function update(array, args) {
|
||||
var arrayLength = array.length, length = args.length;
|
||||
while (length--) array[arrayLength + length] = args[length];
|
||||
return array;
|
||||
}
|
||||
|
||||
function merge(array, args) {
|
||||
array = slice.call(array, 0);
|
||||
return update(array, args);
|
||||
}
|
||||
|
||||
function argumentNames() {
|
||||
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
|
||||
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
|
||||
.replace(/\s+/g, '').split(',');
|
||||
return names.length == 1 && !names[0] ? [] : names;
|
||||
}
|
||||
|
||||
function bind(context) {
|
||||
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
|
||||
var __method = this, args = slice.call(arguments, 1);
|
||||
return function() {
|
||||
var a = merge(args, arguments);
|
||||
return __method.apply(context, a);
|
||||
}
|
||||
}
|
||||
|
||||
function bindAsEventListener(context) {
|
||||
var __method = this, args = slice.call(arguments, 1);
|
||||
return function(event) {
|
||||
var a = update([event || window.event], args);
|
||||
return __method.apply(context, a);
|
||||
}
|
||||
}
|
||||
|
||||
function curry() {
|
||||
if (!arguments.length) return this;
|
||||
var __method = this, args = slice.call(arguments, 0);
|
||||
return function() {
|
||||
var a = merge(args, arguments);
|
||||
return __method.apply(this, a);
|
||||
}
|
||||
}
|
||||
|
||||
function delay(timeout) {
|
||||
var __method = this, args = slice.call(arguments, 1);
|
||||
timeout = timeout * 1000;
|
||||
return window.setTimeout(function() {
|
||||
return __method.apply(__method, args);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
function defer() {
|
||||
var args = update([0.01], arguments);
|
||||
return this.delay.apply(this, args);
|
||||
}
|
||||
|
||||
function wrap(wrapper) {
|
||||
var __method = this;
|
||||
return function() {
|
||||
var a = update([__method.bind(this)], arguments);
|
||||
return wrapper.apply(this, a);
|
||||
}
|
||||
}
|
||||
|
||||
function methodize() {
|
||||
if (this._methodized) return this._methodized;
|
||||
var __method = this;
|
||||
return this._methodized = function() {
|
||||
var a = update([this], arguments);
|
||||
return __method.apply(null, a);
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
argumentNames: argumentNames,
|
||||
bind: bind,
|
||||
bindAsEventListener: bindAsEventListener,
|
||||
curry: curry,
|
||||
delay: delay,
|
||||
defer: defer,
|
||||
wrap: wrap,
|
||||
methodize: methodize
|
||||
}
|
||||
})());
|
||||
Reference in New Issue
Block a user