org.jsweet.transpiler.extension.RemoveJavaDependenciesAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsweet-transpiler Show documentation
Show all versions of jsweet-transpiler Show documentation
A Java to TypeScript/JavaScript Open Transpiler
The newest version!
/*
* JSweet transpiler - http://www.jsweet.org
* Copyright (C) 2015 CINCHEO SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jsweet.transpiler.extension;
import static org.jsweet.JSweetConfig.isJDKPath;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.Collator;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import org.jsweet.transpiler.JSweetContext;
import org.jsweet.transpiler.Java2TypeScriptTranslator;
import org.jsweet.transpiler.ModuleKind;
import org.jsweet.transpiler.model.BinaryOperatorElement;
import org.jsweet.transpiler.model.ExtendedElement;
import org.jsweet.transpiler.model.ExtendedElementFactory;
import org.jsweet.transpiler.model.ForeachLoopElement;
import org.jsweet.transpiler.model.ImportElement;
import org.jsweet.transpiler.model.LiteralElement;
import org.jsweet.transpiler.model.MethodInvocationElement;
import org.jsweet.transpiler.model.NewArrayElement;
import org.jsweet.transpiler.model.NewClassElement;
import org.jsweet.transpiler.model.VariableAccessElement;
import org.jsweet.transpiler.util.Util;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.EnhancedForLoopTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.ParameterizedTypeTree;
/**
* An adapter that removes many uses of Java APIs and replace them with
* JavaScript equivalent when possible.
*
* @author Renaud Pawlak
*/
public class RemoveJavaDependenciesAdapter extends Java2TypeScriptAdapter {
protected Map extTypesMapping = new HashMap<>();
private final String ERASED_CLASS_HIERARCHY_FIELD = "__classes";
private Set excludedJavaSuperTypes = new HashSet<>();
public RemoveJavaDependenciesAdapter(JSweetContext context) {
super(context);
init();
}
public RemoveJavaDependenciesAdapter(PrinterAdapter parentAdapter) {
super(parentAdapter);
init();
}
protected void init() {
initTypesMapping();
addTypeMappings(extTypesMapping);
}
protected void initTypesMapping() {
addTypeMapping(Class.class.getName(), "any");
context.getLangTypeMappings().put(RuntimeException.class.getName(), "Error");
context.getBaseThrowables().add(RuntimeException.class.getName());
extTypesMapping.put(URL.class.getName(), "URL");
extTypesMapping.put(List.class.getName(), "Array");
extTypesMapping.put(AbstractList.class.getName(), "Array");
extTypesMapping.put(ArrayList.class.getName(), "Array");
extTypesMapping.put(CopyOnWriteArrayList.class.getName(), "Array");
extTypesMapping.put(Iterable.class.getName(), "Array");
extTypesMapping.put(LinkedList.class.getName(), "Array");
extTypesMapping.put(Collection.class.getName(), "Array");
extTypesMapping.put(Set.class.getName(), "Array");
extTypesMapping.put(EnumSet.class.getName(), "Array");
extTypesMapping.put(Deque.class.getName(), "Array");
extTypesMapping.put(ArrayDeque.class.getName(), "Array");
extTypesMapping.put(Queue.class.getName(), "Array");
extTypesMapping.put(Stack.class.getName(), "Array");
extTypesMapping.put(HashSet.class.getName(), "Array");
extTypesMapping.put(SortedSet.class.getName(), "Array");
extTypesMapping.put(TreeSet.class.getName(), "Array");
extTypesMapping.put(LinkedHashSet.class.getName(), "Array");
extTypesMapping.put(Vector.class.getName(), "Array");
extTypesMapping.put(Enumeration.class.getName(), "any");
extTypesMapping.put(Iterator.class.getName(), "any");
extTypesMapping.put(ListIterator.class.getName(), "any");
extTypesMapping.put(Map.class.getName(), "any");
extTypesMapping.put(Properties.class.getName(), "any");
extTypesMapping.put(AbstractMap.class.getName(), "any");
extTypesMapping.put(HashMap.class.getName(), "any");
extTypesMapping.put(NavigableMap.class.getName(), "any");
extTypesMapping.put(TreeMap.class.getName(), "any");
extTypesMapping.put(WeakHashMap.class.getName(), "any");
extTypesMapping.put(LinkedHashMap.class.getName(), "any");
extTypesMapping.put(EnumMap.class.getName(), "any");
extTypesMapping.put(Hashtable.class.getName(), "any");
extTypesMapping.put(Comparator.class.getName(), "any");
extTypesMapping.put(Exception.class.getName(), "Error");
extTypesMapping.put(RuntimeException.class.getName(), "Error");
extTypesMapping.put(Throwable.class.getName(), "Error");
extTypesMapping.put(Error.class.getName(), "Error");
extTypesMapping.put(StringBuffer.class.getName(), "{ str: string, toString: Function }");
extTypesMapping.put(StringBuilder.class.getName(), "{ str: string, toString: Function }");
extTypesMapping.put(Collator.class.getName(), "any");
extTypesMapping.put(Calendar.class.getName(), "Date");
extTypesMapping.put(GregorianCalendar.class.getName(), "Date");
extTypesMapping.put(TimeZone.class.getName(), "string");
extTypesMapping.put(Locale.class.getName(), "string");
extTypesMapping.put(Charset.class.getName(), "string");
extTypesMapping.put(Reader.class.getName(), "{ str: string, cursor: number }");
extTypesMapping.put(StringReader.class.getName(), "{ str: string, cursor: number }");
extTypesMapping.put(InputStream.class.getName(), "{ str: string, cursor: number }");
extTypesMapping.put(InputStreamReader.class.getName(), "{ str: string, cursor: number }");
extTypesMapping.put(BufferedReader.class.getName(), "{ str: string, cursor: number }");
extTypesMapping.put(Method.class.getName(), "{ owner: any, name: string, fn : Function }");
// replace java.*
addTypeMapping((TypeMirror type) -> {
String qualifiedName = util().getQualifiedName(type);
if (!qualifiedName.startsWith("java.") || type == null) {
return null;
}
// Throwable
if (types().isSubtype(type, util().getType(Throwable.class))) {
return "Error";
}
// Optional
if (types().isSubtype(types().erasure(type), types().erasure(util().getType(Optional.class)))
&& type instanceof DeclaredType) {
List typeArgs = ((DeclaredType) type).getTypeArguments();
if (typeArgs.size() > 0) {
TypeMirror backingType = typeArgs.get(0);
Element backingTypeElement = context.types.asElement(backingType);
if (backingType.getKind() == TypeKind.TYPEVAR) {
return backingType.toString();
} else if (backingType.getKind() == TypeKind.WILDCARD) {
return "any";
} else if (backingTypeElement == null) {
return getMappedType(backingType);
} else {
return getPrinter().getQualifiedTypeName(backingTypeElement, false, true);
}
}
}
return null;
});
addTypeMapping((ExtendedElement typeTree, String name) -> mapWeakReferenceType(typeTree, name));
excludedJavaSuperTypes.add(EventObject.class.getName());
}
private Object mapWeakReferenceType(ExtendedElement element, String name) {
if (!(ExtendedElementFactory.toTree(element) instanceof ParameterizedTypeTree)) {
return null;
}
String typeFullName = util().getQualifiedName(element.getTypeAsElement());
if (WeakReference.class.getName().equals(typeFullName)) {
return ((ParameterizedTypeTree) ExtendedElementFactory.toTree(element)).getTypeArguments().get(0);
}
return null;
}
@Override
public String needsImport(ImportElement importElement, String qualifiedName) {
if (isJDKPath(qualifiedName)) {
return null;
}
return super.needsImport(importElement, qualifiedName);
}
protected RemoveJavaDependenciesAdapter print(ExtendedElement expression, boolean delegate) {
if (delegate) {
print("(").print(expression).print(").__delegate");
} else {
print(expression);
}
delegate = false;
return this;
}
protected RemoveJavaDependenciesAdapter printTargetForParameter(ExtendedElement expression, boolean delegate) {
if (expression != null && expression.toString().equals("super")) {
getPrinter().print("this");
return this;
}
return print(expression, delegate);
}
@Override
public boolean substituteMethodInvocation(MethodInvocationElement invocation) {
String targetMethodName = invocation.getMethodName();
String targetClassName = invocation.getMethod().getEnclosingElement().toString();
ExtendedElement targetExpression = invocation.getTargetExpression();
if (targetExpression != null && targetExpression.getTypeAsElement() != null) {
targetClassName = targetExpression.getTypeAsElement().toString();
}
TypeMirror jdkSuperclass = context.getJdkSuperclass(targetClassName, excludedJavaSuperTypes);
boolean delegate = jdkSuperclass != null;
if (delegate) {
targetClassName = jdkSuperclass.toString();
}
TypeMirror targetType = invocation.getTargetType();
if (targetClassName != null
&& (targetExpression != null || invocation.getMethod().getModifiers().contains(Modifier.STATIC))) {
switch (targetClassName) {
case "java.lang.Float":
case "java.lang.Double":
case "java.lang.Integer":
case "java.lang.Byte":
case "java.lang.Long":
case "java.lang.Short":
if (substituteMethodInvocationOnNumber(invocation, targetMethodName)) {
return true;
}
break;
case "java.lang.Character":
if (substituteMethodInvocationOnCharacter(invocation, targetMethodName)) {
return true;
}
break;
case "java.util.Collection":
case "java.util.List":
case "java.util.AbstractList":
case "java.util.AbstractSet":
case "java.util.AbstractCollection":
case "java.util.Queue":
case "java.util.Deque":
case "java.util.ArrayDeque":
case "java.util.LinkedList":
case "java.util.ArrayList":
case "java.util.concurrent.CopyOnWriteArrayList":
case "java.util.Stack":
case "java.util.Vector":
case "java.util.Set":
case "java.util.EnumSet":
case "java.util.HashSet":
case "java.util.SortedSet":
case "java.util.TreeSet":
case "java.util.LinkedHashSet":
if (substituteMethodInvocationOnArray(invocation, targetMethodName, targetClassName, delegate)) {
return true;
}
break;
case "java.util.Properties":
case "java.util.Dictionary":
case "java.util.Map":
case "java.util.AbstractMap":
case "java.util.HashMap":
case "java.util.NavigableMap":
case "java.util.TreeMap":
case "java.util.Hashtable":
case "java.util.WeakHashMap":
case "java.util.LinkedHashMap":
if (substituteMethodInvocationOnMap(invocation, targetMethodName, targetExpression, delegate)) {
return true;
}
break;
case "java.util.Collections":
if (substituteMethodInvocationOnCollections(invocation, targetMethodName, targetExpression, delegate)) {
return true;
}
break;
case "java.util.Arrays":
if (substituteMethodInvocationOnArrays(invocation, targetMethodName, targetExpression, delegate)) {
return true;
}
break;
case "java.lang.System":
switch (targetMethodName) {
case "arraycopy":
printMacroName(targetMethodName);
print("((srcPts, srcOff, dstPts, dstOff, size) => { if(srcPts !== dstPts || dstOff >= srcOff + size) { while (--size >= 0) dstPts[dstOff++] = srcPts[srcOff++];"
+ "} else { let tmp = srcPts.slice(srcOff, srcOff + size); for (let i = 0; i < size; i++) dstPts[dstOff++] = tmp[i]; }})(")
.printArgList(invocation.getArguments()).print(")");
return true;
case "currentTimeMillis":
printMacroName(targetMethodName);
print("Date.now()");
return true;
case "nanoTime":
printMacroName(targetMethodName);
print("(Date.now() * 1000000)");
return true;
}
break;
case "java.util.Objects":
if (substituteMethodInvocationOnObjects(invocation, targetMethodName, delegate)) {
return true;
}
break;
case "java.util.Optional":
if (substituteMethodInvocationOnOptional(invocation, targetMethodName, delegate)) {
return true;
}
break;
case "java.lang.StringBuffer":
case "java.lang.StringBuilder":
if (substituteMethodInvocationOnStringBuilder(invocation, targetMethodName, delegate)) {
return true;
}
break;
case "java.lang.ref.WeakReference":
switch (targetMethodName) {
case "get":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate);
return true;
}
break;
case "java.text.Collator":
switch (targetMethodName) {
case "getInstance":
printMacroName(targetMethodName);
print("{ compare: (o1, o2) => o1.toString().localeCompare(o2.toString()), equals: (o1, o2) => o1.toString().localeCompare(o2.toString()) === 0 }");
return true;
}
break;
case "java.nio.charset.Charset":
switch (targetMethodName) {
case "forName":
print(invocation.getArgument(0));
return true;
}
break;
case "java.util.Locale":
switch (targetMethodName) {
case "getDefault":
printMacroName(targetMethodName);
getPrinter().print("(window.navigator['userLanguage'] || window.navigator.language)");
return true;
}
break;
case "java.util.TimeZone":
switch (targetMethodName) {
case "getTimeZone":
if (invocation.getArgumentCount() == 1) {
printMacroName(targetMethodName);
print(invocation.getArgument(0));
return true;
}
break;
case "getDefault":
printMacroName(targetMethodName);
getPrinter().print("\"UTC\"");
return true;
case "getID":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate);
return true;
}
break;
case "java.util.Calendar":
case "java.util.GregorianCalendar":
if (substituteMethodInvocationOnCalendar(invocation, targetMethodName, delegate)) {
return true;
}
break;
case "java.io.Reader":
case "java.io.StringReader":
case "java.io.InputStream":
case "java.io.InputStreamReader":
case "java.io.BufferedReader":
switch (targetMethodName) {
case "read":
printMacroName(targetMethodName);
print("(r => r.str.charCodeAt(r.cursor++))(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
case "skip":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".cursor+=")
.print(invocation.getArgument(0));
return true;
case "reset":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".cursor=0");
return true;
case "close":
printMacroName(targetMethodName);
// ignore but we could flag it and throw an error...
return true;
}
break;
case "java.lang.ThreadLocal":
switch (targetMethodName) {
case "get":
printMacroName(targetMethodName);
print("((tlObj: any) => {" //
+ " if (tlObj.___value) { return tlObj.___value } " //
+ " else { return tlObj.___value = tlObj.initialValue() } " //
+ " })(");
print(invocation.getTargetExpression());
print(")");
return true;
}
break;
case "java.lang.Class":
if (substituteMethodInvocationOnClass(invocation, targetType, targetMethodName, delegate)) {
return true;
}
break;
case "java.lang.reflect.Method":
if (substituteMethodInvocationOnMethod(invocation, targetMethodName, delegate)) {
return true;
}
break;
case "java.lang.reflect.Field":
if (substituteMethodInvocationOnField(invocation, targetMethodName, delegate)) {
return true;
}
break;
case "java.lang.reflect.Array":
switch (targetMethodName) {
case "newInstance":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 2) {
print("new Array(").print(invocation.getArgument(1)).print(")");
return true;
}
case "getLength":
printMacroName(targetMethodName);
print(invocation.getArgument(0)).print(".length");
return true;
case "get":
printMacroName(targetMethodName);
print(invocation.getArgument(0)).print("[").print(invocation.getArgument(1)).print("]");
return true;
case "set":
printMacroName(targetMethodName);
print("(").print(invocation.getArgument(0)).print("[").print(invocation.getArgument(1)).print("]=")
.print(invocation.getArgument(1)).print(")");
return true;
}
break;
case "java.lang.Math":
case "java.lang.StrictMath":
switch (targetMethodName) {
case "ulp":
printMacroName(targetMethodName);
print("((x) => { let buffer = new ArrayBuffer(8); let dataView = new DataView(buffer); dataView.setFloat64(0, x); let first = dataView.getUint32(0); let second = dataView.getUint32(4); let rawExponent = first & 0x7ff00000; if (rawExponent == 0x7ff00000) { dataView.setUint32(0,first & 0x7fffffff); } else if (rawExponent == 0) { dataView.setUint32(4,1); dataView.setUint32(0,0); } else if (rawExponent >= (52 << 20) + 0x00100000) { dataView.setUint32(0,rawExponent - (52 << 20)); dataView.setUint32(4,0); } else if (rawExponent >= (33 << 20)) { dataView.setUint32(0,1 << ((rawExponent - (33 << 20)) >>> 20 )); dataView.setUint32(4,0); } else { dataView.setUint32(4,1 << ((rawExponent - 0x00100000) >>> 20)); dataView.setUint32(0,0); } return dataView.getFloat64(0); })(")
.printArgList(invocation.getArguments()).print(")");
return true;
case "IEEEremainder":
printMacroName(targetMethodName);
// credits: Ray Cromwell
print("((f1, f2) => { let r = Math.abs(f1 % f2); if (isNaN(r) || r == f2 || r <= Math.abs(f2) / 2.0) { return r; } else { return (f1 > 0 ? 1 : -1) * (r - f2); } })(")
.printArgList(invocation.getArguments()).print(")");
return true;
}
}
switch (targetMethodName) {
case "clone":
printMacroName(targetMethodName);
if (targetExpression != null && invocation.getTargetExpression().getType() instanceof ArrayType) {
print(invocation.getTargetExpression(), delegate).print(".slice(0)");
return true;
}
break;
}
}
return super.substituteMethodInvocation(invocation);
}
private boolean substituteMethodInvocationOnOptional(MethodInvocationElement invocation, String targetMethodName,
boolean delegate) {
switch (targetMethodName) {
case "of":
print("(v => { if (v == null) throw new Error('value is null'); return v; })(")
.print(invocation.getArgument(0)).print(")");
return true;
case "empty":
print("null");
return true;
case "ofNullable":
print(invocation.getArgument(0));
return true;
case "equals":
printDefaultEquals(invocation.getTargetExpression(), invocation.getArgument(0));
return true;
case "filter":
printMacroName(targetMethodName);
print("((o, condition) => condition(o) ? o : null)(").print(invocation.getTargetExpression()).print(",")
.print(invocation.getArgument(0)).print(")");
return true;
case "orElse":
printMacroName(targetMethodName);
print("((v, v2) => v == null ? v2 : v)(").print(invocation.getTargetExpression()).print(",")
.print(invocation.getArgument(0)).print(")");
return true;
case "orElseGet":
case "or":
printMacroName(targetMethodName);
print("((v, get) => v == null ? get() : v)(").print(invocation.getTargetExpression()).print(",")
.print(invocation.getArgument(0)).print(")");
return true;
case "ifPresent":
printMacroName(targetMethodName);
print("((v, action) => v != null ? action(v) : null)(").print(invocation.getTargetExpression()).print(",")
.print(invocation.getArgument(0)).print(")");
return true;
case "ifPresentOrElse":
printMacroName(targetMethodName);
print("((v, action, fallbackAction) => v != null ? action(v) : fallbackAction())(")
.print(invocation.getTargetExpression()).print(",").print(invocation.getArgument(0)).print(",")
.print(invocation.getArgument(1)).print(")");
return true;
case "map":
case "flatMap":
printMacroName(targetMethodName);
print("(").print(invocation.getArgument(0)).print(")(").print(invocation.getTargetExpression()).print(")");
return true;
case "isEmpty":
printMacroName(targetMethodName);
print("(").print(invocation.getTargetExpression()).print(" == null)");
return true;
case "isPresent":
printMacroName(targetMethodName);
print("(").print(invocation.getTargetExpression()).print(" != null)");
return true;
case "get":
case "orElseThrow":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() > 0) {
print("((v, getError) => { if (v == null) throw getError(); return v; })(")
.print(invocation.getTargetExpression()).print(",").print(invocation.getArgument(0)).print(")");
} else {
print("(v => { if (v == null) throw new Error('value is null'); return v; })(")
.print(invocation.getTargetExpression()).print(")");
}
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnObjects(MethodInvocationElement invocation, String targetMethodName,
boolean delegate) {
switch (targetMethodName) {
case "hash":
printMacroName(targetMethodName);
print("0");
return true;
case "requireNonNull":
printMacroName(targetMethodName);
print("if(").print(invocation.getArgument(0)).print("==null){throw new Error('cannot be null')}");
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnField(MethodInvocationElement invocation, String targetMethodName,
boolean delegate) {
switch (targetMethodName) {
case "getName":
printMacroName(targetMethodName);
print(invocation.getTargetExpression()).print(".name");
return true;
case "get":
printMacroName(targetMethodName);
print(invocation.getArgument(0)).print("[").print(invocation.getTargetExpression()).print(".name")
.print("]");
return true;
case "set":
printMacroName(targetMethodName);
print("(").print(invocation.getArgument(0)).print("[").print(invocation.getTargetExpression())
.print(".name").print("]=").print(invocation.getArgument(1)).print(")");
return true;
case "getDeclaringClass":
printMacroName(targetMethodName);
print(invocation.getTargetExpression()).print(".owner");
return true;
case "setAccessible":
// ignore
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnMethod(MethodInvocationElement invocation, String targetMethodName,
boolean delegate) {
switch (targetMethodName) {
case "getName":
printMacroName(targetMethodName);
print(invocation.getTargetExpression()).print(".name");
return true;
case "invoke":
printMacroName(targetMethodName);
print(invocation.getTargetExpression()).print(".fn.apply(").print(invocation.getArgument(0));
if (invocation.getArgumentCount() > 1) {
print(", [").printArgList(invocation.getArgumentTail()).print("]");
}
print(")");
return true;
case "getDeclaringClass":
printMacroName(targetMethodName);
print(invocation.getTargetExpression()).print(".owner");
return true;
case "setAccessible":
// ignore
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnClass(MethodInvocationElement invocationElement, TypeMirror targetType, String targetMethodName,
boolean delegate) {
switch (targetMethodName) {
case "forName":
printMacroName(targetMethodName);
if (getContext().options.getModuleKind() != ModuleKind.none) {
print("eval(").print(invocationElement.getArgument(0)).print(".split('.').slice(-1)[0])");
} else {
print("eval(").print(invocationElement.getArgument(0)).print(")");
}
return true;
case "newInstance":
printMacroName(targetMethodName);
print("new (");
print(invocationElement.getTargetExpression(), delegate).print(")(").printArgList(invocationElement.getArguments())
.print(")");
return true;
case "isInstance":
printMacroName(targetMethodName);
print("((c:any,o:any) => { if(typeof c === 'string') return (o.constructor && o.constructor")
.print("[\"" + Java2TypeScriptTranslator.INTERFACES_FIELD_NAME + "\"] && o.constructor")
.print("[\"" + Java2TypeScriptTranslator.INTERFACES_FIELD_NAME + "\"].indexOf(c) >= 0) || (o")
.print("[\"" + Java2TypeScriptTranslator.INTERFACES_FIELD_NAME + "\"] && o")
.print("[\"" + Java2TypeScriptTranslator.INTERFACES_FIELD_NAME
+ "\"].indexOf(c) >= 0); else if(typeof c === 'function') return (o instanceof c) || (o.constructor && o.constructor === c); })(");
print(invocationElement.getTargetExpression(), delegate).print(", ").printArgList(invocationElement.getArguments())
.print(")");
return true;
case "isPrimitive":
// primitive class types are never used in JSweet, so it
// will always return false
printMacroName(targetMethodName);
print("(").print(invocationElement.getTargetExpression()).print(" === '__erasedPrimitiveType__'").print(")");
return true;
case "getMethods":
case "getDeclaredMethods":
printMacroName(targetMethodName);
print("(c => Object.getOwnPropertyNames(c.prototype).filter(n => typeof c.prototype[n] == 'function').map(n => ({owner:c,name:n,fn:c.prototype[n]}) ) )(")
.print(invocationElement.getTargetExpression()).print(")");
return true;
case "getMethod":
case "getDeclaredMethod":
printMacroName(targetMethodName);
print("((c,p) => { if(c.prototype.hasOwnProperty(p) && typeof c.prototype[p] == 'function') return {owner:c,name:p,fn:c.prototype[p]}; else return null; })(")
.print(invocationElement.getTargetExpression()).print(",").print(invocationElement.getArgument(0)).print(")");
return true;
case "getField":
case "getDeclaredField":
printMacroName(targetMethodName);
print("((c,p) => { return {owner:c,name:p}; })(").print(invocationElement.getTargetExpression()).print(",")
.print(invocationElement.getArgument(0)).print(")");
return true;
case "isAssignableFrom":
printMacroName(targetMethodName);
print("((candidateBase, clazz) => candidateBase != null && clazz != null && " + //
"(candidateBase == clazz || clazz.prototype instanceof candidateBase)" + //
")(");
printTarget(invocationElement.getTargetExpression());
print(",");
print(invocationElement.getArgument(0));
print(")");
return true;
case "getFields":
case "getDeclaredFields":
printMacroName(targetMethodName);
if (targetType instanceof DeclaredType) {
List typeArgs = ((DeclaredType) targetType).getTypeArguments();
if (typeArgs != null && typeArgs.size() > 0 && !util().isType(typeArgs.get(0), Object.class)) {
TypeMirror targetClassType = typeArgs.get(0);
Class targetClass = util().getTypeClass(targetClassType);
if (targetClass != null) {
Field[] fields;
if (targetMethodName.equals("getDeclaredFields")) {
fields = targetClass.getDeclaredFields();
} else {
fields = targetClass.getFields();
}
print("[");
for (Field field : fields) {
print("{");
print(" name: '" + field.getName() + "',");
print(" getName: () => this.name,");
print(" getType: () => ");
if (!getPrinter().printClass(util().getType(field.getType()))) {
print("Object");
}
print(",");
print("},");
}
print("]");
return true;
}
}
}
break;
}
return false;
}
protected boolean substituteMethodInvocationOnArrays(MethodInvocationElement invocation, String targetMethodName,
ExtendedElement targetExpression, boolean delegate) {
switch (targetMethodName) {
case "asList":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 1 && invocation.getArgument(0).getType() instanceof ArrayType) {
printArgList(invocation.getArguments()).print(".slice(0)");
} else {
print("[").printArgList(invocation.getArguments()).print("]");
}
return true;
case "copyOf":
printMacroName(targetMethodName);
print(invocation.getArgument(0)).print(".slice(0,").print(invocation.getArgument(1)).print(")");
return true;
case "fill":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 4) {
print("((a, start, end, v) => { for(let i=start;i { for(let i=0;i { if(a1==null && a2==null) return true; if(a1==null || a2==null) return false; if(a1.length != a2.length) return false; for(let i = 0; i < a1.length; i++) { if(a1[i] != a2[i]) return false; } return true; })(")
.printArgList(invocation.getArguments()).print(")");
return true;
case "deepEquals":
printMacroName(targetMethodName);
print("(JSON.stringify(").print(invocation.getArgument(0)).print(") === JSON.stringify(")
.print(invocation.getArgument(1)).print("))");
return true;
case "sort":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() > 2) {
print("((arr, start, end, f?) => ((arr1, arr2) => arr1.splice.apply(arr1, ([start, arr2.length]).concat(arr2)))(")
.print(invocation.getArgument(0)).print(", ").print(invocation.getArgument(0))
.print(".slice(start, end).sort(f)))(").printArgList(invocation.getArguments()).print(")");
} else if (invocation.getArgumentCount() == 2) {
print("((l,c) => { if((c).compare) l.sort((e1,e2)=>(c).compare(e1,e2)); else l.sort(c); })(")
.print(invocation.getArgument(0)).print(",").print(invocation.getArgument(1)).print(")");
} else {
print("((l) => {l.sort(); })(").print(invocation.getArgument(0)).print(")");
}
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnCollections(MethodInvocationElement invocation,
String targetMethodName, ExtendedElement targetExpression, boolean delegate) {
switch (targetMethodName) {
case "emptyList":
printMacroName(targetMethodName);
print("[]");
return true;
case "emptySet":
printMacroName(targetMethodName);
print("[]");
return true;
case "emptyMap":
printMacroName(targetMethodName);
print("{}");
return true;
case "unmodifiableList":
case "unmodifiableCollection":
case "unmodifiableSet":
case "unmodifiableSortedSet":
printMacroName(targetMethodName);
printArgList(invocation.getArguments()).print(".slice(0)");
return true;
case "singleton":
printMacroName(targetMethodName);
print("[").print(invocation.getArgument(0)).print("]");
return true;
case "singletonList":
printMacroName(targetMethodName);
print("[").print(invocation.getArgument(0)).print("]");
return true;
case "nCopies":
printMacroName(targetMethodName);
print("((n,v)=>{let c=[];for(let i=0;i { let o = {}; o[k] = ").print(invocation.getArgument(1)).print("; return o; })(")
.print(invocation.getArgument(0)).print(")");
}
} else {
print("(k => { let o = {entries: [{getKey: function() { return this.key }, getValue: function() { return this.value },key:k, value:")
.print(invocation.getArgument(1)).print("}]}; return o; })(").print(invocation.getArgument(0))
.print(")");
}
return true;
case "binarySearch":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 3) {
print("((l, key, c) => { let comp : any = c; if(typeof c != 'function') { comp = (a,b)=>c.compare(a,b); } let low = 0; let high = l.length-1; while (low <= high) { let mid = (low + high) >>> 1; let midVal = l[mid]; "
+ "let cmp = comp(midVal, key); if (cmp < 0) low = mid + 1; else if (cmp > 0) high = mid - 1; else return mid; } "
+ "return -(low + 1); })(").printArgList(invocation.getArguments()).print(")");
return true;
}
if (invocation.getArgumentCount() == 2) {
if (util().isNumber(invocation.getArgument(1).getType())) {
print("((l, key) => { let comp = (a,b)=>a-b; let low = 0; let high = l.length-1; while (low <= high) { let mid = (low + high) >>> 1; let midVal = l[mid]; "
+ "let cmp = comp(midVal, key); if (cmp < 0) low = mid + 1; else if (cmp > 0) high = mid - 1; else return mid; } "
+ "return -(low + 1); })(").printArgList(invocation.getArguments()).print(")");
return true;
} else {
print("((l, key) => { let comp = (a,b)=> {if(a.compareTo) return (a.compareTo(b)); else return a.localeCompare(b);}; let low = 0; let high = l.length-1; while (low <= high) { let mid = (low + high) >>> 1; let midVal = l[mid]; "
+ "let cmp = comp(midVal, key); if (cmp < 0) low = mid + 1; else if (cmp > 0) high = mid - 1; else return mid; } "
+ "return -(low + 1); })(").printArgList(invocation.getArguments()).print(")");
return true;
}
}
case "sort":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 2) {
print("((l,c) => { if((c).compare) l.sort((e1,e2)=>(c).compare(e1,e2)); else l.sort(c); })(")
.print(invocation.getArgument(0)).print(",").print(invocation.getArgument(1)).print(")");
} else {
print(invocation.getArgument(0)).print(".sort(").printArgList(invocation.getArgumentTail()).print(")");
}
return true;
case "reverse":
printMacroName(targetMethodName);
print(invocation.getArgument(0)).print(".reverse()");
return true;
case "disjoint":
printMacroName(targetMethodName);
print("((c1, c2) => { for(let i=0;ic1[i])>=0) return false; } return true; } )(")
.printArgList(invocation.getArguments()).print(")");
return true;
}
return false;
}
private boolean substituteMethodInvocationOnStringBuilder(MethodInvocationElement invocation,
String targetMethodName, boolean delegate) {
switch (targetMethodName) {
case "append":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 1) {
print("(sb => { sb.str += ").printArgList(invocation.getArguments())
.print("; return sb; })(");
print(invocation.getTargetExpression(), delegate).print(")");
} else {
print("(sb => { sb.str += (").print(invocation.getArgument(0)).print(").substr(")
.printArgList(invocation.getArgumentTail()).print("); return sb; })(");
print(invocation.getTargetExpression(), delegate).print(")");
}
return true;
case "insert":
printMacroName(targetMethodName);
print("((sb, index, c) => { sb.str = sb.str.substr(0, index) + c + sb.str.substr(index); return sb; })(");
print(invocation.getTargetExpression(), delegate).print(", ").printArgList(invocation.getArguments())
.print(")");
return true;
case "setCharAt":
printMacroName(targetMethodName);
print("((sb, index, c) => sb.str = sb.str.substr(0, index) + c + sb.str.substr(index + 1))(");
print(invocation.getTargetExpression(), delegate).print(", ").printArgList(invocation.getArguments())
.print(")");
return true;
case "deleteCharAt":
printMacroName(targetMethodName);
print("((sb, index) => { sb.str = sb.str.substr(0, index) + sb.str.substr(index + 1); return sb; })(");
print(invocation.getTargetExpression(), delegate).print(", ").printArgList(invocation.getArguments())
.print(")");
return true;
case "delete":
printMacroName(targetMethodName);
print("((sb, i1, i2) => { sb.str = sb.str.substr(0, i1) + sb.str.substr(i2); return sb; })(");
print(invocation.getTargetExpression(), delegate).print(", ").printArgList(invocation.getArguments())
.print(")");
return true;
case "length":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".str.length");
return true;
case "charAt":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".str.charAt(").print(invocation.getArgument(0))
.print(")");
return true;
case "setLength":
printMacroName(targetMethodName);
print("((sb, length) => sb.str = sb.str.substring(0, length))(");
print(invocation.getTargetExpression(), delegate).print(", ").printArgList(invocation.getArguments())
.print(")");
return true;
case "toString":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".str");
return true;
case "lastIndexOf":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".str.lastIndexOf(")
.print(invocation.getArgument(0)).print(")");
return true;
case "substring":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".str.substring(")
.printArgList(invocation.getArguments()).print(")");
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnCalendar(MethodInvocationElement invocation, String targetMethodName,
boolean delegate) {
switch (targetMethodName) {
case "set":
if (invocation.getArgumentCount() == 2) {
String first = invocation.getArgument(0).toString();
if (first.endsWith("YEAR")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCFullYear(p):d.setFullYear(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
} else if (first.endsWith("DAY_OF_MONTH")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCDate(p):d.setDate(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
} else if (first.endsWith("DAY_OF_WEEK")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCDay(p):d.setDay(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
} else if (first.endsWith("MONTH")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCMonth(p):d.setMonth(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
} else if (first.endsWith("HOUR_OF_DAY")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCHours(p):d.setHours(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
} else if (first.endsWith("MINUTE")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCMinutes(p):d.setMinutes(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
} else if (first.endsWith("MILLISECOND")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCMilliseconds(p):d.setMilliseconds(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
} else if (first.endsWith("SECOND")) {
printMacroName(targetMethodName);
print("((d, p) => d[\"UTC\"]?d.setUTCSeconds(p):d.setSeconds(p))(");
print(invocation.getTargetExpression(), delegate).print(", ").print(invocation.getArgument(1))
.print(")");
return true;
}
}
break;
case "get":
if (invocation.getArgumentCount() == 1) {
String first = invocation.getArgument(0).toString();
if (first.endsWith("YEAR")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCFullYear():d.getFullYear())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
} else if (first.endsWith("DAY_OF_MONTH")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCDate():d.getDate())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
} else if (first.endsWith("DAY_OF_WEEK")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCDay():d.getDay())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
} else if (first.endsWith("MONTH")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCMonth():d.getMonth())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
} else if (first.endsWith("HOUR_OF_DAY")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCHours():d.getHours())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
} else if (first.endsWith("MINUTE")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCMinutes():d.getMinutes())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
} else if (first.endsWith("MILLISECOND")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCMilliseconds():d.getMilliseconds())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
} else if (first.endsWith("SECOND")) {
printMacroName(targetMethodName);
print("(d => d[\"UTC\"]?d.getUTCSeconds():d.getSeconds())(");
print(invocation.getTargetExpression(), delegate).print(")");
return true;
}
}
break;
case "setTimeInMillis":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".setTime(").print(invocation.getArgument(0))
.print(")");
return true;
case "getTimeInMillis":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".getTime()");
return true;
case "setTime":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".setTime(").print(invocation.getArgument(0))
.print(".getTime())");
return true;
case "getTime":
printMacroName(targetMethodName);
print("(new Date(");
print(invocation.getTargetExpression(), delegate).print(".getTime()))");
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnMap(MethodInvocationElement invocation, String targetMethodName,
ExtendedElement targetExpression, boolean delegate) {
if (targetExpression == null) {
return false;
}
if (((DeclaredType) targetExpression.getType()).getTypeArguments().size() == 2 && types().isSameType(
((DeclaredType) targetExpression.getType()).getTypeArguments().get(0), util().getType(String.class))) {
switch (targetMethodName) {
case "put":
printMacroName(targetMethodName);
print("(");
print(invocation.getTargetExpression(), delegate).print("[").print(invocation.getArgument(0))
.print("] = ").print(invocation.getArgument(1)).print(")");
return true;
case "get":
printMacroName(targetMethodName);
print("((m,k) => m[k]===undefined?null:m[k])(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(", ")
.print(invocation.getArgument(0)).print(")");
return true;
case "containsKey":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".hasOwnProperty(")
.print(invocation.getArgument(0)).print(")");
return true;
case "keySet":
printMacroName(targetMethodName);
print("Object.keys(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "values":
printMacroName(targetMethodName);
print("(obj => Object.keys(obj).map(key => obj[key]))(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "size":
printMacroName(targetMethodName);
print("Object.keys(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(").length");
return true;
case "isEmpty":
printMacroName(targetMethodName);
print("(Object.keys(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(").length == 0)");
return true;
case "remove":
printMacroName(targetMethodName);
print("(map => { let deleted = ");
print(invocation.getTargetExpression(), delegate).print("[").print(invocation.getArgument(0))
.print("];");
print("delete ");
print(invocation.getTargetExpression(), delegate).print("[").print(invocation.getArgument(0))
.print("];");
print("return deleted;})").print("(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "clear":
printMacroName(targetMethodName);
print("(obj => { for (let member in obj) delete obj[member]; })(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "entrySet":
printMacroName(targetMethodName);
print("(o => { let s = []; for (let e in o) s.push({ k: e, v: o[e], getKey: function() { return this.k }, getValue: function() { return this.v } }); return s; })(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "clone":
printMacroName(targetMethodName);
print("(o => { let c = {}; for (let k in Object.keys(o)){ c[k] = o[k] } return c; })(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
}
} else {
String newEntry = "{key:k,value:v,getKey: function() { return this.key }, getValue: function() { return this.value }}";
switch (targetMethodName) {
case "put":
case "setProperty":
printMacroName(targetMethodName);
print("((m,k,v) => { if(m.entries==null) m.entries=[]; for(let i=0;i");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(", ")
.printArgList(invocation.getArguments()).print(")");
return true;
case "get":
case "getProperty":
printMacroName(targetMethodName);
print("((m,k) => { if(m.entries==null) m.entries=[]; for(let i=0;i");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(", ")
.printArgList(invocation.getArguments()).print(")");
return true;
case "containsKey":
printMacroName(targetMethodName);
print("((m,k) => { if(m.entries==null) m.entries=[]; for(let i=0;i");
print(invocation.getTargetExpression(), delegate).print(", ").printArgList(invocation.getArguments())
.print(")");
return true;
case "keySet":
case "stringPropertyNames":
printMacroName(targetMethodName);
print("((m) => { let r=[]; if(m.entries==null) m.entries=[]; for(let i=0;i");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "values":
printMacroName(targetMethodName);
print("((m) => { let r=[]; if(m.entries==null) m.entries=[]; for(let i=0;i");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "size":
printMacroName(targetMethodName);
print("((m) => { if(m.entries==null) m.entries=[]; return m.entries.length; })(").print("");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "isEmpty":
printMacroName(targetMethodName);
print("((m) => { if(m.entries==null) m.entries=[]; return m.entries.length == 0; })(").print("");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "remove":
printMacroName(targetMethodName);
print("((m,k) => { if(m.entries==null) m.entries=[]; for(let i=0;i");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(", ")
.printArgList(invocation.getArguments()).print(")");
return true;
case "clear":
printMacroName(targetMethodName);
print("(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(").entries=[]");
return true;
case "entrySet":
printMacroName(targetMethodName);
print("((m) => { if(m.entries==null) m.entries=[]; return m.entries; })(").print("");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "clone":
printMacroName(targetMethodName);
print("(m => { if(m.entries==null) m.entries=[]; let c = {entries: []}; for(let i=0;i { if(s.indexOf(e)==-1) { s.push(e); return true; } else { return false; } })(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(", ")
.print(invocation.getArgument(0)).print(")");
break;
default:
if (invocation.getArgumentCount() == 2) {
print(invocation.getTargetExpression(), delegate).print(".splice(").print(invocation.getArgument(0))
.print(", 0, ").print(invocation.getArgument(1)).print(")");
} else {
print("(");
print(invocation.getTargetExpression(), delegate).print(".push(")
.printArgList(invocation.getArguments()).print(")>0)");
}
}
return true;
case "addAll":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 2) {
print("((l1, ndx, l2) => { for(let i=l2.length-1;i>=0;i--) l1.splice(ndx,0,l2[i]); })(");
print(invocation.getTargetExpression(), delegate).print(", ").printArgList(invocation.getArguments())
.print(")");
} else {
print("((l1, l2) => l1.push.apply(l1, l2))(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(", ")
.printArgList(invocation.getArguments()).print(")");
}
return true;
case "pop":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".pop(").printArgList(invocation.getArguments())
.print(")");
return true;
case "peek":
case "lastElement":
case "peekLast":
printMacroName(targetMethodName);
print("(a => a.length==0 ? null : a[a.length-1])(");
printTargetForParameter(invocation.getTargetExpression(), delegate);
print(")");
return true;
case "peekFirst":
printMacroName(targetMethodName);
print("(a => a.length==0 ? null : a[0])(");
printTargetForParameter(invocation.getTargetExpression(), delegate);
print(")");
return true;
case "remove":
case "removeFirst": // in Deque
case "removeElement": // in Vector: functionally equivalent to List.remove(int idx)
printMacroName(targetMethodName);
/*
* in Queue: interface contains a no-arg method remove() which is functionally
* identical to Deque.removeFirst()
*/
if (invocation.getArgumentCount() == 0) {
print(invocation.getTargetExpression(), delegate).print(".splice(0, 1)[0]");
} else if (util().isNumber(invocation.getArgument(0).getType())
&& types().isSubtype(types().erasure(invocation.getTargetExpression().getType()),
types().erasure(util().getType(List.class)))) {
print(invocation.getTargetExpression(), delegate).print(".splice(")
.printArgList(invocation.getArguments()).print(", 1)[0]");
} else {
print("(a => { let index = a.indexOf(").print(invocation.getArgument(0))
.print("); if(index>=0) { a.splice(index").print(invocation.getArgumentCount() == 1 ? "" : ", ")
.printArgList(invocation.getArgumentTail())
.print(", 1); return true; } else { return false; }})(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
}
return true;
case "removeAll":
printMacroName(targetMethodName);
print("((a, r) => { let b=false; for(let i=0;i=0) { a.splice(ndx, 1); b=true; } } return b; })(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(",")
.print(invocation.getArgument(0)).print(")");
return true;
case "containsAll":
printMacroName(targetMethodName);
print("((a, r) => { for(let i=0;ir[i])<0) return false; } return true; } )(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(",")
.print(invocation.getArgument(0)).print(")");
return true;
case "retainAll":
printMacroName(targetMethodName);
print("((a, r) => { let b=false; for(let i=0;i a.length==0?null:a.shift())(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "pollLast":
printMacroName(targetMethodName);
print("(a => a.length==0?null:a.pop())(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
case "removeElementAt":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".splice(").printArgList(invocation.getArguments())
.print(", 1)");
return true;
case "subList":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print(".slice(").printArgList(invocation.getArguments())
.print(")");
return true;
case "size":
printMacroName(targetMethodName);
print("(");
print(invocation.getTargetExpression(), delegate).print(".length)");
return true;
case "get":
case "elementAt":
printMacroName(targetMethodName);
print(invocation.getTargetExpression(), delegate).print("[").printArgList(invocation.getArguments())
.print("]");
return true;
case "set":
printMacroName(targetMethodName);
print("(");
print(invocation.getTargetExpression(), delegate).print("[").print(invocation.getArgument(0)).print("] = ")
.print(invocation.getArgument(1)).print(")");
return true;
case "clear":
printMacroName(targetMethodName);
print("(");
print(invocation.getTargetExpression(), delegate).print(".length = 0)");
return true;
case "isEmpty":
printMacroName(targetMethodName);
print("(");
print(invocation.getTargetExpression(), delegate).print(".length == 0)");
return true;
case "contains":
printMacroName(targetMethodName);
print("(");
print(invocation.getTargetExpression(), delegate).print(".indexOf((").print(invocation.getArgument(0))
.print(")) >= 0)");
return true;
case "toArray":
printMacroName(targetMethodName);
if (invocation.getArgumentCount() == 1) {
ExtendedElement e = invocation.getArgument(0);
if (invocation.getTargetExpression() instanceof VariableAccessElement && e instanceof NewArrayElement) {
NewArrayElement newArray = (NewArrayElement) e;
boolean simplified = false;
if (newArray.getDimensionCount() == 1) {
ExtendedElement d = newArray.getDimension(0);
if (d.isConstant() && d.toString().equals("0")) {
simplified = true;
} else if (d instanceof MethodInvocationElement) {
if (((MethodInvocationElement) d).getMethodName().equals("size")
&& ((MethodInvocationElement) d).getTargetExpression().toString()
.equals(invocation.getTargetExpression().toString())) {
simplified = true;
}
}
}
if (simplified) {
print(invocation.getTargetExpression(), delegate).print(".slice(0)");
return true;
}
}
print("((a1, a2) => { if(a1.length >= a2.length) { a1.length=0; a1.push.apply(a1, a2); return a1; } else { return a2.slice(0); } })(")
.print(invocation.getArgument(0)).print(", ");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(")");
return true;
} else {
print(invocation.getTargetExpression(), delegate).print(".slice(0)");
return true;
}
case "elements":
printMacroName(targetMethodName);
print("((a) => { var i = 0; return { nextElement: function() { return i { var i = 0; return { next: function() { return i { var i = 0; return { next: function() { return ival)) { result.push(parseInt(val,10)); } } return result; }()");
return true;
case "equals":
printMacroName(targetMethodName);
print("((a1, a2) => { if(a1==null && a2==null) return true; if(a1==null || a2==null) return false; if(a1.length != a2.length) return false; for(let i = 0; i < a1.length; i++) { if(a1[i] != a2[i]) return false; } return true; })(");
printTargetForParameter(invocation.getTargetExpression(), delegate).print(", ")
.printArgList(invocation.getArguments()).print(")");
return true;
}
return false;
}
protected boolean substituteMethodInvocationOnNumber(MethodInvocationElement invocation, String targetMethodName) {
switch (targetMethodName) {
case "parseInt":
case "parseLong":
case "parseShort":
case "parseByte":
printMacroName(targetMethodName);
print("parseInt").print("(").printArgList(invocation.getArguments()).print(")");
return true;
case "parseFloat":
case "parseDouble":
printMacroName(targetMethodName);
print("parseFloat").print("(").printArgList(invocation.getArguments()).print(")");
return true;
case "floatToIntBits":
case "floatToRawIntBits":
printMacroName(targetMethodName);
print("((f) => { let buf = new ArrayBuffer(4); (new Float32Array(buf))[0]=f; return (new Uint32Array(buf))[0]; })(")
.printArgList(invocation.getArguments()).print(")");
return true;
case "intBitsToFloat":
print("((v) => { let buf = new ArrayBuffer(4); (new Uint32Array(buf))[0]=v; return (new Float32Array(buf))[0]; })(")
.printArgList(invocation.getArguments()).print(")");
return true;
case "doubleToLongBits":
case "doubleToRawLongBits":
printMacroName(targetMethodName);
print("((f) => { let buf = new ArrayBuffer(4); (new Float32Array(buf))[0]=f; return (new Uint32Array(buf))[0]; })((Math).fround(")
.printArgList(invocation.getArguments()).print("))");
return true;
case "longBitsToDouble":
print("((v) => { let buf = new ArrayBuffer(4); (new Uint32Array(buf))[0]=v; return (new Float32Array(buf))[0]; })(")
.printArgList(invocation.getArguments()).print(")");
return true;
case "valueOf":
if (util().isNumber(invocation.getArgument(0).getType())) {
print(invocation.getArgument(0));
return true;
} else {
print("parseFloat").print("(").printArgList(invocation.getArguments()).print(")");
return true;
}
}
return false;
}
protected boolean substituteMethodInvocationOnCharacter(MethodInvocationElement invocation,
String targetMethodName) {
switch (targetMethodName) {
case "isDigit":
printMacroName(targetMethodName);
print("/\\d/.test(").printArgList(invocation.getArguments()).print("[0])");
return true;
case "isLetter":
printMacroName(targetMethodName);
print("/[a-zA-Z]/.test(").printArgList(invocation.getArguments()).print("[0])");
return true;
case "isAlphabetic":
printMacroName(targetMethodName);
print("/[a-zA-Z]/.test(").printArgList(invocation.getArguments()).print("[0])");
return true;
case "isLetterOrDigit":
printMacroName(targetMethodName);
print("/[a-zA-Z\\d]/.test(").printArgList(invocation.getArguments()).print("[0])");
return true;
case "toLowerCase":
printMacroName(targetMethodName);
print(invocation.getArgument(0)).print(".toLowerCase()");
return true;
case "toUpperCase":
printMacroName(targetMethodName);
print(invocation.getArgument(0)).print(".toUpperCase()");
return true;
case "isLowerCase":
printMacroName(targetMethodName);
print("(s => s.toLowerCase() === s)(").print(invocation.getArgument(0)).print(")");
return true;
case "isUpperCase":
printMacroName(targetMethodName);
print("(s => s.toUpperCase() === s)(").print(invocation.getArgument(0)).print(")");
return true;
case "charValue":
printMacroName(targetMethodName);
print(invocation.getTargetExpression());
return true;
case "valueOf":
print(invocation.getArgument(0));
return true;
case "toString":
if (invocation.getMethod().getModifiers().contains(Modifier.STATIC)) {
print(invocation.getArgument(0));
return true;
}
}
return false;
}
@Override
public boolean substituteVariableAccess(VariableAccessElement variableAccess) {
String targetClassName = variableAccess.getTargetElement().toString();
String variableName = variableAccess.getVariableName();
if (variableAccess.getVariable().getModifiers().contains(Modifier.STATIC) && isMappedType(targetClassName)
&& targetClassName.startsWith("java.lang.") && !"class".equals(variableName)) {
switch (targetClassName) {
case "java.lang.Float":
case "java.lang.Double":
case "java.lang.Integer":
case "java.lang.Byte":
case "java.lang.Long":
case "java.lang.Short":
switch (variableName) {
case "MIN_VALUE":
case "MAX_VALUE":
case "POSITIVE_INFINITY":
case "NEGATIVE_INFINITY":
try {
Field constantField = Class.forName(targetClassName).getDeclaredField(variableName);
print("" + constantField.get(null));
} catch (Exception e) {
logger.warn("unable to read Java constant value " + targetClassName + "." + variableName, e);
print("Number." + variableName);
}
return true;
case "NaN":
print("NaN");
return true;
}
break;
case "java.lang.Boolean":
switch (variableName) {
case "TRUE":
print("true");
return true;
case "FALSE":
print("false");
return true;
}
}
}
return super.substituteVariableAccess(variableAccess);
}
@Override
public boolean substituteNewClass(NewClassElement newClass) {
String className = newClass.getTypeAsElement().toString();
TypeMirror jdkSuperclass = context.getJdkSuperclass(className, excludedJavaSuperTypes);
boolean extendsJava = jdkSuperclass != null;
if (extendsJava) {
className = jdkSuperclass.toString();
print("(() => { let __o : any = new ").print(newClass.getConstructorAccess()).print("(")
.printArgList(newClass.getArguments()).print("); __o.__delegate = ");
}
boolean substitute = false;
switch (className) {
case "java.lang.Integer":
case "java.lang.Long":
case "java.lang.Double":
case "java.lang.Float":
case "java.long.Short":
case "java.util.Byte":
String argType = newClass.getArgument(0).getType().toString();
boolean isCharArgument = Character.class.getName().equals(argType) || "char".equals(argType);
if (isCharArgument) {
print("new Number(").print(newClass.getArgument(0)).print(".charCodeAt(0)" + ").valueOf()");
} else {
print("new Number(").print(newClass.getArgument(0)).print(").valueOf()");
}
substitute = true;
break;
case "java.util.ArrayList":
case "java.util.LinkedList":
case "java.util.Vector":
case "java.util.Stack":
case "java.util.TreeSet":
case "java.util.HashSet":
case "java.util.AbstractSet":
case "java.util.AbstractCollection":
case "java.util.AbstractList":
case "java.util.AbstractQueue":
if (newClass.getArgumentCount() == 0) {
print("[]");
} else {
if (util().isNumber(newClass.getArgument(0).getType())
|| (newClass.getArgument(0) instanceof LiteralElement)) {
print("[]");
} else {
print(newClass.getArgument(0)).print(".slice(0)");
}
}
substitute = true;
break;
case "java.util.HashMap":
case "java.util.NavigableMap":
case "java.util.TreeMap":
case "java.util.Hashtable":
case "java.util.WeakHashMap":
case "java.util.LinkedHashMap":
case "java.util.EnumMap":
if (newClass.getArgumentCount() == 0 || !(newClass.getArgument(0).getType() instanceof DeclaredType)
|| !util().isDeclarationOrSubClassDeclaration((DeclaredType) newClass.getArgument(0).getType(),
Map.class.getName())) {
print("{}");
} else {
if (((DeclaredType) newClass.getType()).getTypeArguments().size() == 2 && types().isSameType(
((DeclaredType) newClass.getType()).getTypeArguments().get(0), util().getType(String.class))) {
print("((o) => { let r = {}; for(let p in o) r[p]=o[p]; return r; })(")
.print(newClass.getArgument(0)).print(")");
} else {
print("((o) => { let r = {}; r['entries'] = o.entries!=null?o.entries.slice():null; return r; })(")
.print(newClass.getArgument(0)).print(")");
}
}
substitute = true;
break;
case "java.lang.String":
if (newClass.getArgumentCount() == 0) {
print("\"\"");
return true;
} else {
ExtendedElement firstArgument = newClass.getArgument(0);
if (firstArgument.getType() instanceof ArrayType) {
if (util().isIntegral(((ArrayType) firstArgument.getType()).getComponentType())) {
print("String.fromCharCode.apply(null, ").print(firstArgument).print(")");
if (newClass.getArgumentCount() >= 3 && util().isIntegral(newClass.getArgument(1).getType())
&& util().isIntegral(newClass.getArgument(2).getType())) {
print(".substr(").print(newClass.getArgument(1)).print(", ").print(newClass.getArgument(2))
.print(")");
}
return true;
} else {
print(firstArgument).print(".join('')");
if (newClass.getArgumentCount() >= 3 && util().isIntegral(newClass.getArgument(1).getType())
&& util().isIntegral(newClass.getArgument(2).getType())) {
print(".substr(").print(newClass.getArgument(1)).print(", ").print(newClass.getArgument(2))
.print(")");
}
return true;
}
} else if (StringBuffer.class.getName().equals(firstArgument.getTypeAsElement().toString())
|| StringBuilder.class.getName().equals(firstArgument.getTypeAsElement().toString())) {
print(firstArgument).print(".str");
return true;
}
}
break;
case "java.lang.StringBuffer":
case "java.lang.StringBuilder":
if (newClass.getArgumentCount() == 0 || util().isNumber(newClass.getArgument(0).getType())) {
print("{ str: \"\", toString: function() { return this.str; } }");
} else {
print("{ str: ").print(newClass.getArgument(0)).print(", toString: function() { return this.str; } }");
}
substitute = true;
break;
case "java.lang.ref.WeakReference":
print(newClass.getArgument(0));
substitute = true;
break;
case "java.io.StringReader":
print("{ str: ").print(newClass.getArgument(0)).print(", cursor: 0 }");
substitute = true;
break;
case "java.io.InputStreamReader":
case "java.io.BufferedReader":
print(newClass.getArgument(0));
substitute = true;
break;
case "java.util.GregorianCalendar":
if (newClass.getArgumentCount() == 0) {
getPrinter().print("new Date()");
substitute = true;
break;
} else if (newClass.getArgumentCount() == 1
&& TimeZone.class.getName().equals(newClass.getArgument(0).getType().toString())) {
if (newClass.getArgument(0) instanceof MethodInvocationElement) {
MethodInvocationElement inv = (MethodInvocationElement) newClass.getArgument(0);
if (inv.getMethodName().equals("getTimeZone") && inv.getArgument(0) instanceof LiteralElement
&& ((LiteralElement) inv.getArgument(0)).getValue().equals("UTC")) {
getPrinter().print("(d => { d[\"UTC\"]=true; return d; })(new Date())");
substitute = true;
break;
}
}
}
break;
}
if (!extendsJava && className.startsWith("java.")) {
TypeMirror throwableType = util().getType(Throwable.class);
if (types().isSubtype(newClass.getType(), throwableType)) {
print("Object.defineProperty(");
print("new Error(");
if (newClass.getArgumentCount() > 0) {
if (String.class.getName().equals(newClass.getArgument(0).getType().toString())) {
print(newClass.getArgument(0));
} else if (types().isSubtype(newClass.getArgument(0).getType(), throwableType)) {
print(newClass.getArgument(0)).print(".message");
}
}
print(")");
Set classes = new HashSet<>();
context.grabSuperClassNames(classes, newClass.getTypeAsElement());
print(", '" + ERASED_CLASS_HIERARCHY_FIELD + "', { configurable: true, value: [");
for (String c : classes) {
print("'" + c + "',");
}
if (!classes.isEmpty()) {
removeLastChar();
}
print("] })");
return true;
}
}
if (!substitute) {
substitute = super.substituteNewClass(newClass);
}
if (extendsJava) {
print("; return __o; })()");
}
return substitute;
}
@Override
public boolean substituteForEachLoop(ForeachLoopElement foreachLoop, boolean targetHasLength, String indexVarName) {
EnhancedForLoopTree loop = ExtendedElementFactory.toTree(foreachLoop);
TypeMirror expressionType = Util.getType(loop.getExpression());
if (!targetHasLength && !isJDKPath(expressionType.toString())
&& types().isSubtype(expressionType, types().erasure(util().getType(Iterable.class)))) {
printForEachLoop(loop, indexVarName);
return true;
}
return false;
}
@Override
public boolean eraseSuperClass(TypeElement classdecl, TypeElement superClass) {
return superClass.getQualifiedName().toString().startsWith("java.")
&& !(util().isType(superClass.asType(), Throwable.class)
|| util().isType(superClass.asType(), Exception.class)
|| util().isType(superClass.asType(), RuntimeException.class)
|| util().isType(superClass.asType(), Error.class))
&& !util().isSourceElement(superClass);
}
@Override
public boolean eraseSuperInterface(TypeElement classdecl, TypeElement superInterface) {
return superInterface.getQualifiedName().toString().startsWith("java.")
&& !util().isSourceElement(superInterface);
}
@Override
public boolean isSubstituteSuperTypes() {
return true;
}
@Override
public boolean substituteInstanceof(String exprStr, ExtendedElement expr, TypeMirror type) {
String typeName = util().getQualifiedName(type);
if (typeName.startsWith("java.") && context.types.isSubtype(type, util().getType(Throwable.class))) {
print(exprStr, expr);
print(" != null && ");
print("(");
print(exprStr, expr);
print("[\"" + ERASED_CLASS_HIERARCHY_FIELD + "\"] && ");
print(exprStr, expr);
print("[\"" + ERASED_CLASS_HIERARCHY_FIELD + "\"].indexOf(\"" + typeName + "\") >= 0");
print(")");
if (context.getBaseThrowables().contains(typeName)) {
print(" || ");
return false;
}
return true;
}
String mappedType = extTypesMapping.get(typeName);
if ("string".equals(mappedType)) {
mappedType = "String";
}
if ("boolean".equals(mappedType)) {
mappedType = "Boolean";
}
if ("any".equals(mappedType) || (mappedType != null && mappedType.startsWith("{"))) {
mappedType = "Object";
}
if (mappedType != null) {
if ("String".equals(mappedType)) {
print("typeof ");
print(exprStr, expr);
print(" === ").print("'string'");
return true;
} else {
print(exprStr, expr);
print(" != null && ");
print("(");
print(exprStr, expr);
print(" instanceof " + mappedType);
print(")");
return true;
}
}
return super.substituteInstanceof(exprStr, expr, type);
}
@Override
public boolean substituteBinaryOperator(BinaryOperatorElement binaryOperator) {
if ("+".equals(binaryOperator.getOperator())) {
BinaryTree loop = ExtendedElementFactory.toTree(binaryOperator);
TypeMirror binaryOperationType = util().getOperatorType(loop);
if (types().isSameType(util().getType(String.class), binaryOperationType)) {
if ("Array".equals(
extTypesMapping.get(types().erasure(binaryOperator.getLeftHandSide().getType()).toString()))) {
print("/* implicit toString */ (a => a?'['+a.join(', ')+']':'null')(")
.print(binaryOperator.getLeftHandSide()).print(") + ")
.print(binaryOperator.getRightHandSide());
return true;
} else if ("Array".equals(
extTypesMapping.get(types().erasure(binaryOperator.getRightHandSide().getType()).toString()))) {
print(binaryOperator.getLeftHandSide())
.print(" + /* implicit toString */ (a => a?'['+a.join(', ')+']':'null')(")
.print(binaryOperator.getRightHandSide()).print(")");
return true;
}
}
}
return super.substituteBinaryOperator(binaryOperator);
}
}