jso: improve JS class import to Java

This commit is contained in:
Alexey Andreev 2024-02-22 21:14:30 +01:00
parent 393cd7f807
commit e4452152b7
61 changed files with 1612 additions and 459 deletions

View File

@ -65,7 +65,7 @@ public class TXHRURLConnection extends THttpURLConnection {
return;
}
xhr = XMLHttpRequest.create();
xhr = new XMLHttpRequest();
xhr.open(method, url.toString());
for (Map.Entry<String, List<String>> entry : getRequestProperties().entrySet()) {
for (String value : entry.getValue()) {
@ -97,7 +97,7 @@ public class TXHRURLConnection extends THttpURLConnection {
responseCode = -1;
}
Int8Array array = Int8Array.create((ArrayBuffer) xhr.getResponse());
var array = new Int8Array((ArrayBuffer) xhr.getResponse());
byte[] bytes = new byte[array.getLength()];
for (int i = 0; i < bytes.length; ++i) {
bytes[i] = array.get(i);
@ -119,7 +119,7 @@ public class TXHRURLConnection extends THttpURLConnection {
if (outputStream != null) {
byte[] bytes = outputStream.toByteArray();
Int8Array array = Int8Array.create(bytes.length);
var array = new Int8Array(bytes.length);
for (int i = 0; i < bytes.length; ++i) {
array.set(i, bytes[i]);
}

View File

@ -34,10 +34,10 @@ public final class TByteOrder {
public static TByteOrder nativeOrder() {
if (nativeOrder == null) {
if (PlatformDetector.isJavaScript()) {
var buffer = ArrayBuffer.create(2);
var shortArray = Int16Array.create(buffer);
var buffer = new ArrayBuffer(2);
var shortArray = new Int16Array(buffer);
shortArray.set(0, (short) 1);
var byteArray = Int8Array.create(buffer);
var byteArray = new Int8Array(buffer);
nativeOrder = byteArray.get(0) == 0 ? BIG_ENDIAN : LITTLE_ENDIAN;
} else {
var array = new short[1];

View File

@ -75,7 +75,7 @@ public class TSecureRandom extends TRandom {
@Override
public void nextBytes(byte[] bytes) {
if (PlatformDetector.isJavaScript() && Crypto.isSupported()) {
Uint8Array buffer = Uint8Array.create(bytes.length);
var buffer = new Uint8Array(bytes.length);
Crypto.current().getRandomValues(buffer);
for (int i = 0; i < bytes.length; ++i) {

View File

@ -64,7 +64,7 @@ public class TDate implements TComparable<TDate> {
public TDate(int year, int month, int date, int hrs, int min, int sec) {
this(PlatformDetector.isLowLevel()
? initDateLowLevel(year, month, date, hrs, min, sec)
: (long) JSDate.create(year, month, date, hrs, min, sec).getTime());
: (long) new JSDate(year, month, date, hrs, min, sec).getTime());
if (!PlatformDetector.isLowLevel()) {
setYear(year);
}
@ -127,7 +127,7 @@ public class TDate implements TComparable<TDate> {
if (PlatformDetector.isLowLevel()) {
return getYearLowLevel(value);
}
return JSDate.create(value).getFullYear() - 1900;
return new JSDate(value).getFullYear() - 1900;
}
@Import(name = "teavm_date_getYear")
@ -143,7 +143,7 @@ public class TDate implements TComparable<TDate> {
value = setYearLowLevel(value, year);
return;
}
JSDate date = JSDate.create(value);
var date = new JSDate(value);
date.setFullYear(year + 1900);
value = (long) date.getTime();
}
@ -160,7 +160,7 @@ public class TDate implements TComparable<TDate> {
if (PlatformDetector.isLowLevel()) {
return getMonthLowLevel(value);
}
return JSDate.create(value).getMonth();
return new JSDate(value).getMonth();
}
@Import(name = "teavm_date_getMonth")
@ -176,7 +176,7 @@ public class TDate implements TComparable<TDate> {
value = setMonthLowLevel(value, month);
return;
}
JSDate date = JSDate.create(value);
var date = new JSDate(value);
date.setMonth(month);
value = (long) date.getTime();
}
@ -193,7 +193,7 @@ public class TDate implements TComparable<TDate> {
if (PlatformDetector.isLowLevel()) {
return getDateLowLevel(value);
}
return JSDate.create(value).getDate();
return new JSDate(value).getDate();
}
@Import(name = "teavm_date_getDate")
@ -209,7 +209,7 @@ public class TDate implements TComparable<TDate> {
value = setDateLowLevel(value, date);
return;
}
JSDate d = JSDate.create(value);
var d = new JSDate(value);
d.setDate(date);
this.value = (long) d.getTime();
}
@ -226,7 +226,7 @@ public class TDate implements TComparable<TDate> {
if (PlatformDetector.isLowLevel()) {
return getDayLowLevel(value);
}
return JSDate.create(value).getDay();
return new JSDate(value).getDay();
}
@Import(name = "teavm_date_getDay")
@ -239,7 +239,7 @@ public class TDate implements TComparable<TDate> {
if (PlatformDetector.isLowLevel()) {
return getHoursLowLevel(value);
}
return JSDate.create(value).getHours();
return new JSDate(value).getHours();
}
@Import(name = "teavm_date_getHours")
@ -389,12 +389,12 @@ public class TDate implements TComparable<TDate> {
@Deprecated
public String toLocaleString() {
return JSDate.create(value).toLocaleFormat("%c");
return new JSDate(value).toLocaleFormat("%c");
}
@Deprecated
public String toGMTString() {
return JSDate.create(value).toUTCString();
return new JSDate(value).toUTCString();
}
@Deprecated

View File

@ -16,6 +16,7 @@
package org.teavm.jso.ajax;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.Event;
@ -23,7 +24,8 @@ import org.teavm.jso.dom.events.EventListener;
import org.teavm.jso.dom.events.EventTarget;
import org.teavm.jso.dom.xml.Document;
public abstract class XMLHttpRequest implements JSObject, EventTarget {
@JSClass
public class XMLHttpRequest implements JSObject, EventTarget {
public static final int UNSET = 0;
public static final int OPENED = 1;
@ -34,52 +36,55 @@ public abstract class XMLHttpRequest implements JSObject, EventTarget {
public static final int DONE = 4;
public abstract void open(String method, String url);
public XMLHttpRequest() {
}
public abstract void open(String method, String url, boolean async);
public native void open(String method, String url);
public abstract void open(String method, String url, boolean async, String user);
public native void open(String method, String url, boolean async);
public abstract void open(String method, String url, boolean async, String user, String password);
public native void open(String method, String url, boolean async, String user);
public abstract void send();
public native void open(String method, String url, boolean async, String user, String password);
public abstract void send(String data);
public native void send();
public abstract void send(JSObject data);
public native void send(String data);
public abstract void setRequestHeader(String name, String value);
public native void send(JSObject data);
public abstract String getAllResponseHeaders();
public native void setRequestHeader(String name, String value);
public abstract String getResponseHeader(String name);
public native String getAllResponseHeaders();
public native String getResponseHeader(String name);
@JSProperty("onreadystatechange")
public abstract void setOnReadyStateChange(ReadyStateChangeHandler handler);
public native void setOnReadyStateChange(ReadyStateChangeHandler handler);
@JSProperty("onreadystatechange")
public abstract void setOnReadyStateChange(EventListener<Event> handler);
public native void setOnReadyStateChange(EventListener<Event> handler);
@JSProperty("onabort")
public abstract void onAbort(EventListener<ProgressEvent> eventListener);
public native void onAbort(EventListener<ProgressEvent> eventListener);
@JSProperty("onerror")
public abstract void onError(EventListener<ProgressEvent> eventListener);
public native void onError(EventListener<ProgressEvent> eventListener);
@JSProperty("onload")
public abstract void onLoad(EventListener<ProgressEvent> eventListener);
public native void onLoad(EventListener<ProgressEvent> eventListener);
@JSProperty("onloadstart")
public abstract void onLoadStart(EventListener<ProgressEvent> eventListener);
public native void onLoadStart(EventListener<ProgressEvent> eventListener);
@JSProperty("onloadend")
public abstract void onLoadEnd(EventListener<ProgressEvent> eventListener);
public native void onLoadEnd(EventListener<ProgressEvent> eventListener);
@JSProperty("onprogress")
public abstract void onProgress(EventListener<ProgressEvent> eventListener);
public native void onProgress(EventListener<ProgressEvent> eventListener);
@JSProperty("ontimeout")
public abstract void onTimeout(EventListener<ProgressEvent> eventListener);
public native void onTimeout(EventListener<ProgressEvent> eventListener);
public final void onComplete(Runnable runnable) {
setOnReadyStateChange(() -> {
@ -89,37 +94,53 @@ public abstract class XMLHttpRequest implements JSObject, EventTarget {
});
}
public abstract void overrideMimeType(String mimeType);
public native void overrideMimeType(String mimeType);
@JSProperty
public abstract int getReadyState();
public native int getReadyState();
@JSProperty
public abstract String getResponseText();
public native String getResponseText();
@JSProperty
public abstract Document getResponseXML();
public native Document getResponseXML();
@JSProperty
public abstract JSObject getResponse();
public native JSObject getResponse();
@JSProperty
public abstract int getStatus();
public native int getStatus();
@JSProperty
public abstract String getStatusText();
public native String getStatusText();
@JSProperty
public abstract void setResponseType(String type);
public native void setResponseType(String type);
@JSProperty
public abstract String getResponseType();
public native String getResponseType();
@JSBody(script = "return new XMLHttpRequest();")
@Deprecated
public static native XMLHttpRequest create();
public abstract void abort();
public native void abort();
@JSProperty
public abstract String getResponseURL();
public native String getResponseURL();
@Override
public native void addEventListener(String type, EventListener<?> listener, boolean useCapture);
@Override
public native void addEventListener(String type, EventListener<?> listener);
@Override
public native void removeEventListener(String type, EventListener<?> listener, boolean useCapture);
@Override
public native void removeEventListener(String type, EventListener<?> listener);
@Override
public native boolean dispatchEvent(Event evt);
}

View File

@ -16,29 +16,33 @@
package org.teavm.jso.browser;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.gamepad.Gamepad;
import org.teavm.jso.geolocation.Geolocation;
public final class Navigator {
@JSClass(name = "navigator")
public final class Navigator implements JSObject {
private Navigator() {
}
@JSBody(script = "return navigator.onLine;")
@JSProperty("onLine")
public static native boolean isOnline();
@JSBody(script = "return navigator.geolocation;")
@JSProperty
public static native Geolocation getGeolocation();
@JSBody(script = "return (\"geolocation\" in navigator);")
public static native boolean isGeolocationAvailable();
@JSBody(script = "return navigator.language;")
@JSProperty
public static native String getLanguage();
@JSBody(script = "return navigator.languages;")
@JSProperty
public static native String[] getLanguages();
@JSBody(script = "return navigator.getGamepads();")
@JSProperty
public static native Gamepad[] getGamepads();
@JSBody(script = "return navigator.hardwareConcurrency")

View File

@ -16,13 +16,14 @@
package org.teavm.jso.browser;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
@JSClass(name = "performance")
public final class Performance implements JSObject {
private Performance() {
}
@JSBody(script = "return performance.now();")
public static native double now();
@JSBody(script = "return typeof(performance) !== 'undefined';")

View File

@ -16,29 +16,40 @@
package org.teavm.jso.canvas;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.typedarrays.Uint8ClampedArray;
public abstract class ImageData implements JSObject {
private ImageData() {
@JSClass
public class ImageData implements JSObject {
public ImageData(Uint8ClampedArray array, int width) {
}
public ImageData(int width, int height) {
}
public ImageData(Uint8ClampedArray array, int width, int height) {
}
@JSProperty
public abstract int getWidth();
public native int getWidth();
@JSProperty
public abstract int getHeight();
public native int getHeight();
@JSProperty
public abstract Uint8ClampedArray getData();
public native Uint8ClampedArray getData();
@JSBody(params = { "array", "width" }, script = "return new ImageData(array, width);")
@Deprecated
public static native ImageData create(Uint8ClampedArray array, int width);
@JSBody(params = { "width", "height" }, script = "return new ImageData(width, height);")
@Deprecated
public static native ImageData create(int width, int height);
@JSBody(params = { "array", "width", "height" }, script = "return new ImageData(array, width, height);")
@Deprecated
public static native ImageData create(Uint8ClampedArray array, int width, int height);
}

View File

@ -17,50 +17,61 @@ package org.teavm.jso.canvas;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
public abstract class Path2D implements JSObject {
private Path2D() {
@JSClass
public class Path2D implements JSObject {
public Path2D() {
}
public Path2D(Path2D path) {
}
public Path2D(String svg) {
}
@JSBody(script = "return new Path2D();")
@NoSideEffects
@Deprecated
public static native Path2D create();
@JSBody(params = "path", script = "return new Path2D(path);")
@NoSideEffects
@Deprecated
public static native Path2D create(Path2D path);
@JSBody(params = "svg", script = "return new Path2D(svg);")
@NoSideEffects
@Deprecated
public static native Path2D create(String svg);
public abstract void addPath(Path2D path);
public native void addPath(Path2D path);
public abstract void closePath();
public native void closePath();
public abstract void moveTo(double x, double y);
public native void moveTo(double x, double y);
public abstract void lineTo(double x, double y);
public native void lineTo(double x, double y);
public abstract void bezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y);
public native void bezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y);
public abstract void quadraticCurveTo(double cpx, double cpy, double x, double y);
public native void quadraticCurveTo(double cpx, double cpy, double x, double y);
public abstract void arc(double x, double y, double radius, double startAngle, double endAngle);
public native void arc(double x, double y, double radius, double startAngle, double endAngle);
public abstract void arc(double x, double y, double radius, double startAngle, double endAngle,
public native void arc(double x, double y, double radius, double startAngle, double endAngle,
boolean counterclockwise);
public abstract void arcTo(double x1, double y1, double x2, double y2, double radius);
public native void arcTo(double x1, double y1, double x2, double y2, double radius);
public abstract void ellipse(double x, double y, double radiusX, double radiusY, double rotation,
public native void ellipse(double x, double y, double radiusX, double radiusY, double rotation,
double startAngle, double endAngle);
public abstract void ellipse(double x, double y, double radiusX, double radiusY, double rotation,
public native void ellipse(double x, double y, double radiusX, double radiusY, double rotation,
double startAngle, double endAngle, boolean counterclockwise);
public abstract void rect(double x, double y, double width, double height);
public native void rect(double x, double y, double width, double height);
public abstract void roundRect(double x, double y, double width, double height, JSObject radii);
public native void roundRect(double x, double y, double width, double height, JSObject radii);
}

View File

@ -17,80 +17,92 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSProperty;
public abstract class JSArray<T> implements JSArrayReader<T> {
private JSArray() {
@JSClass(name = "Array")
public class JSArray<T> implements JSArrayReader<T> {
public JSArray(int size) {
}
public JSArray() {
}
@JSIndexer
public abstract void set(int index, T value);
public native void set(int index, T value);
public abstract int push(T a);
public native int push(T a);
public abstract int push(T a, T b);
public native int push(T a, T b);
public abstract int push(T a, T b, T c);
public native int push(T a, T b, T c);
public abstract int push(T a, T b, T c, T d);
public native int push(T a, T b, T c, T d);
public abstract T shift();
public native T shift();
public abstract String join(String separator);
public native String join(String separator);
public abstract String join();
public native String join();
public abstract JSArray<T> concat(JSArrayReader<T> a);
public native JSArray<T> concat(JSArrayReader<T> a);
public abstract JSArray<T> concat(JSArrayReader<T> a, JSArrayReader<T> b);
public native JSArray<T> concat(JSArrayReader<T> a, JSArrayReader<T> b);
public abstract JSArray<T> concat(JSArrayReader<T> a, JSArrayReader<T> b, JSArrayReader<T> c);
public native JSArray<T> concat(JSArrayReader<T> a, JSArrayReader<T> b, JSArrayReader<T> c);
public abstract JSArray<T> concat(JSArrayReader<T> a, JSArrayReader<T> b, JSArrayReader<T> c, JSArrayReader<T> d);
public native JSArray<T> concat(JSArrayReader<T> a, JSArrayReader<T> b, JSArrayReader<T> c, JSArrayReader<T> d);
public abstract T pop();
public native T pop();
public abstract int unshift(T a);
public native int unshift(T a);
public abstract int unshift(T a, T b);
public native int unshift(T a, T b);
public abstract int unshift(T a, T b, T c);
public native int unshift(T a, T b, T c);
public abstract int unshift(T a, T b, T c, T d);
public native int unshift(T a, T b, T c, T d);
public abstract JSArray<T> slice(int start);
public native JSArray<T> slice(int start);
public abstract JSArray<T> slice(int start, int end);
public native JSArray<T> slice(int start, int end);
public abstract JSArray<T> reverse();
public native JSArray<T> reverse();
public abstract JSArray<T> sort(JSSortFunction<T> function);
public native JSArray<T> sort(JSSortFunction<T> function);
public abstract JSArray<T> sort();
public native JSArray<T> sort();
public abstract JSArray<T> splice(int start, int count);
public native JSArray<T> splice(int start, int count);
public abstract JSArray<T> splice(int start, int count, T a);
public native JSArray<T> splice(int start, int count, T a);
public abstract JSArray<T> splice(int start, int count, T a, T b);
public native JSArray<T> splice(int start, int count, T a, T b);
public abstract JSArray<T> splice(int start, int count, T a, T b, T c);
public native JSArray<T> splice(int start, int count, T a, T b, T c);
public abstract JSArray<T> splice(int start, int count, T a, T b, T c, T d);
public native JSArray<T> splice(int start, int count, T a, T b, T c, T d);
@JSProperty
public abstract void setLength(int len);
public native void setLength(int len);
@Override
public native int getLength();
@Override
public native T get(int index);
@JSBody(script = "return new Array();")
@NoSideEffects
@Deprecated
public static native <T> JSArray<T> create();
@JSBody(params = "size", script = "return new Array(size);")
@NoSideEffects
@Deprecated
public static native <T> JSArray<T> create(int size);
@JSBody(params = "object", script = "return Array.isArray(object);")
@NoSideEffects
public static native boolean isArray(Object object);

View File

@ -17,164 +17,187 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
public abstract class JSDate implements JSObject {
@JSClass(name = "Date")
public class JSDate implements JSObject {
public JSDate() {
}
public JSDate(double millis) {
}
public JSDate(int year, int month) {
}
public JSDate(int year, int month, int day) {
}
public JSDate(int year, int month, int day, int hour) {
}
public JSDate(int year, int month, int day, int hour, int minute) {
}
public JSDate(int year, int month, int day, int hour, int minute, int second) {
}
public JSDate(int year, int month, int day, int hour, int minute, int second, int millisecond) {
}
@JSBody(script = "return new Date();")
@NoSideEffects
@Deprecated
public static native JSDate create();
@JSBody(params = "millis", script = "return new Date(millis);")
@NoSideEffects
@Deprecated
public static native JSDate create(double millis);
@JSBody(params = { "year", "month" }, script = "return new Date(year, month);")
@NoSideEffects
@Deprecated
public static native JSDate create(int year, int month);
@JSBody(params = { "year", "month", "day" }, script = "return new Date(year, month, day);")
@NoSideEffects
@Deprecated
public static native JSDate create(int year, int month, int day);
@JSBody(params = { "year", "month", "day", "hour" }, script = "return new Date(year, month, day, hour);")
@NoSideEffects
@Deprecated
public static native JSDate create(int year, int month, int day, int hour);
@JSBody(params = { "year", "month", "day", "hour", "minute" },
script = "return new Date(year, month, day, hour, minute);")
@NoSideEffects
@Deprecated
public static native JSDate create(int year, int month, int day, int hour, int minute);
@JSBody(params = { "year", "month", "day", "hour", "minute", "second" },
script = "return new Date(year, month, day, hour, minute, second);")
@NoSideEffects
@Deprecated
public static native JSDate create(int year, int month, int day, int hour, int minute, int second);
@JSBody(params = { "year", "month", "day", "hour", "minute", "second", "millisecond" },
script = "return new Date(year, month, day, hour, minute, second, millisecond);")
@NoSideEffects
@Deprecated
public static native JSDate create(int year, int month, int day, int hour, int minute, int second, int millisecond);
@JSBody(params = {}, script = "return Date.now();")
@NoSideEffects
public static native double now();
@JSBody(params = "stringValue", script = "return Date.parse(stringValue);")
@NoSideEffects
public static native double parse(String stringValue);
@JSBody(params = { "year", "month" }, script = "return Date.UTC(year, month);")
@NoSideEffects
public static native double UTC(int year, int month);
@JSBody(params = { "year", "month", "day" }, script = "return Date.UTC(year, month, day);")
@NoSideEffects
public static native double UTC(int year, int month, int day);
@JSBody(params = { "year", "month", "day", "hour" }, script = "return Date.UTC(year, month, day, hour);")
@NoSideEffects
public static native double UTC(int year, int month, int day, int hour);
@JSBody(params = { "year", "month", "day", "hour", "minute" },
script = "return Date.UTC(year, month, day, hour, minute);")
@NoSideEffects
public static native double UTC(int year, int month, int day, int hour, int minute);
@JSBody(params = { "year", "month", "day", "hour", "minute", "second" },
script = "return Date.UTC(year, month, day, hour, minute, second);")
@NoSideEffects
public static native double UTC(int year, int month, int day, int hour, int minute, int second);
@JSBody(params = { "year", "month", "day", "hour", "minute", "second", "millisecond" },
script = "return Date.UTC(year, month, day, hour, minute, second, millisecond);")
@NoSideEffects
public static native double UTC(int year, int month, int day, int hour, int minute, int second, int millisecond);
public abstract int getDate();
public native int getDate();
public abstract int getDay();
public native int getDay();
public abstract int getFullYear();
public native int getFullYear();
public abstract int getHours();
public native int getHours();
public abstract int getMilliseconds();
public native int getMilliseconds();
public abstract int getMinutes();
public native int getMinutes();
public abstract int getMonth();
public native int getMonth();
public abstract int getSeconds();
public native int getSeconds();
public abstract double getTime();
public native double getTime();
public abstract int getTimezoneOffset();
public native int getTimezoneOffset();
public abstract int getUTCDate();
public native int getUTCDate();
public abstract int getUTCDay();
public native int getUTCDay();
public abstract int getUTCFullYear();
public native int getUTCFullYear();
public abstract int getUTCHours();
public native int getUTCHours();
public abstract int getUTCMilliseconds();
public native int getUTCMilliseconds();
public abstract int getUTCMinutes();
public native int getUTCMinutes();
public abstract int getUTCMonth();
public native int getUTCMonth();
public abstract int getUTCSeconds();
public native int getUTCSeconds();
public abstract void setDate(int date);
public native void setDate(int date);
public abstract void setFullYear(int fullYear);
public native void setFullYear(int fullYear);
public abstract void setHours(int hours);
public native void setHours(int hours);
public abstract void setMilliseconds(int milliseconds);
public native void setMilliseconds(int milliseconds);
public abstract void setMinutes(int minutes);
public native void setMinutes(int minutes);
public abstract void setMonth(int month);
public native void setMonth(int month);
public abstract void setSeconds(int seconds);
public native void setSeconds(int seconds);
public abstract void setTime(double time);
public native void setTime(double time);
public abstract void setUTCDate(int date);
public native void setUTCDate(int date);
public abstract void setUTCFullYear(int fullYear);
public native void setUTCFullYear(int fullYear);
public abstract void setUTCHours(int hours);
public native void setUTCHours(int hours);
public abstract void setUTCMilliseconds(int milliseconds);
public native void setUTCMilliseconds(int milliseconds);
public abstract void setUTCMinutes(int minutes);
public native void setUTCMinutes(int minutes);
public abstract void setUTCMonth(int month);
public native void setUTCMonth(int month);
public abstract void setUTCSeconds(int seconds);
public native void setUTCSeconds(int seconds);
public abstract String toDateString();
public native String toDateString();
public abstract String toISOString();
public native String toISOString();
public abstract String toJSON();
public native String toJSON();
public abstract String toLocaleDateString();
public native String toLocaleDateString();
public abstract String toLocaleString();
public native String toLocaleString();
public abstract String toLocaleTimeString();
public native String toLocaleTimeString();
@JSMethod("toString")
public abstract String stringValue();
public native String stringValue();
public abstract String toTimeString();
public native String toTimeString();
public abstract String toUTCString();
public native String toUTCString();
public abstract String toLocaleFormat(String format);
public native String toLocaleFormat(String format);
}

View File

@ -17,15 +17,20 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
public abstract class JSFinalizationRegistry implements JSObject {
public abstract void register(Object obj, Object token);
@JSClass(name = "FinalizationRegistry")
public class JSFinalizationRegistry implements JSObject {
public JSFinalizationRegistry(JSFinalizationRegistryConsumer consumer) {
}
public native void register(Object obj, Object token);
@JSBody(params = "consumer", script = "return new FinalizationRegistry(consumer);")
@Deprecated
public static native JSFinalizationRegistry create(JSFinalizationRegistryConsumer consumer);
@JSBody(script = "return typeof FinalizationRegistry !== 'undefined';")
@NoSideEffects
public static native boolean isSupported();

View File

@ -17,20 +17,26 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
public abstract class JSMap<K extends JSObject, V extends JSObject> implements JSObject {
public abstract V get(K key);
@JSClass(name = "Map")
public class JSMap<K extends JSObject, V extends JSObject> implements JSObject {
public JSMap() {
}
public abstract boolean has(K key);
public native V get(K key);
public abstract JSMap<K, V> set(K key, V value);
public native boolean has(K key);
public abstract boolean delete(K key);
public native JSMap<K, V> set(K key, V value);
public abstract void clear();
public native boolean delete(K key);
public native void clear();
@JSBody(script = "return new Map();")
@NoSideEffects
@Deprecated
public static native <K extends JSObject, V extends JSObject> JSMap<K, V> create();
}

View File

@ -17,6 +17,7 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
@ -32,8 +33,9 @@ import org.teavm.jso.util.function.JSSupplier;
*
* @param <T> The type this promise returns when resolving successfully.
*/
public abstract class JSPromise<T> implements JSObject {
private JSPromise() {
@JSClass(name = "Promise")
public class JSPromise<T> implements JSObject {
public JSPromise(Executor<T> executor) {
}
/** Interface for a function wrapped by a promise. */
@ -49,63 +51,58 @@ public abstract class JSPromise<T> implements JSObject {
@JSBody(params = "executor", script = "return new Promise(executor);")
@NoSideEffects
@Deprecated
public static native <T> JSPromise<T> create(Executor<T> executor);
@JSBody(params = "promises", script = "return Promise.any(promises);")
@NoSideEffects
public static native <V> JSPromise<V> any(JSArrayReader<JSPromise<V>> promises);
// TODO: Allow passing differently typed promises via a JSTuple<T1, ...> interface
@JSBody(params = "promises", script = "return Promise.all(promises);")
@NoSideEffects
public static native <V> JSPromise<JSArrayReader<V>> all(JSArrayReader<JSPromise<V>> promises);
// TODO: Allow passing differently typed promises via a JSTuple<T1, ...> interface
@JSBody(params = "promises", script = "return Promise.allSettled(promises);")
@NoSideEffects
public static native <V> JSPromise<JSArrayReader<FulfillmentValue<V>>>
allSettled(JSArrayReader<JSPromise<V>> promises);
@JSBody(params = "promises", script = "return Promise.race(promises);")
@NoSideEffects
public static native <V> JSPromise<V> race(JSArrayReader<JSPromise<V>> promises);
@JSBody(params = "value", script = "return Promise.resolve(value);")
@NoSideEffects
public static native <V> JSPromise<V> resolve(V value);
@JSBody(params = "reason", script = "return Promise.reject(reason);")
@NoSideEffects
public static native <V> JSPromise<V> reject(Object reason);
/** Call {@code onFulfilled} with the success value, resolving with its return value. */
public abstract <V> JSPromise<V> then(JSFunction<T, V> onFulfilled);
public native <V> JSPromise<V> then(JSFunction<T, V> onFulfilled);
/** Call {@code onFulfilled} with the success value or {@code onRejected} with the reject reason,
* resolving with its return value. */
public abstract <V> JSPromise<V> then(JSFunction<T, V> onFulfilled, JSFunction<Object, V> onRejected);
public native <V> JSPromise<V> then(JSFunction<T, V> onFulfilled, JSFunction<Object, V> onRejected);
/** Call {@code onFulfilled} with the success value, returning a new promise. */
@JSMethod("then")
public abstract <V> JSPromise<V> flatThen(JSFunction<T, ? extends JSPromise<V>> onFulfilled);
public native <V> JSPromise<V> flatThen(JSFunction<T, ? extends JSPromise<V>> onFulfilled);
/** Call {@code onFulfilled} with the success value or {@code onRejected} with the reject reason,
* returning a new promise. */
@JSMethod("then")
public abstract <V> JSPromise<V> flatThen(JSFunction<T, ? extends JSPromise<V>> onFulfilled,
public native <V> JSPromise<V> flatThen(JSFunction<T, ? extends JSPromise<V>> onFulfilled,
JSFunction<Object, ? extends JSPromise<V>> onRejected);
/** Call {@code onRejected} with the reject reason, resolving with its return value. */
@JSMethod("catch")
public abstract <V> JSPromise<V> catchError(JSFunction<Object, V> onRejected);
public native <V> JSPromise<V> catchError(JSFunction<Object, V> onRejected);
/** Call {@code onRejected} with the reject reason, returning a new promise. */
@JSMethod("catch")
public abstract <V> JSPromise<V> flatCatchError(JSFunction<Object, ? extends JSPromise<V>> onRejected);
public native <V> JSPromise<V> flatCatchError(JSFunction<Object, ? extends JSPromise<V>> onRejected);
/** Call {@code onFinally} after settling, ignoring the return value. */
@JSMethod("finally")
public abstract JSPromise<T> onSettled(JSSupplier<Object> onFinally);
public native JSPromise<T> onSettled(JSSupplier<Object> onFinally);
/** Interface for the return values of {@ref #allSettled()}. */
public interface FulfillmentValue<T> extends JSObject {

View File

@ -17,16 +17,26 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
public abstract class JSRegExp implements JSObject {
@JSClass(name = "RegExp")
public class JSRegExp implements JSObject {
public JSRegExp(String pattern) {
}
public JSRegExp(String pattern, String flags) {
}
@JSBody(params = "pattern", script = "return new RegExp(pattern);")
@NoSideEffects
@Deprecated
public static native JSRegExp create(String pattern);
@JSBody(params = { "pattern", "flags" }, script = "return new RegExp(pattern, flags);")
@NoSideEffects
@Deprecated
public static native JSRegExp create(String pattern, String flags);
public static JSRegExp create(String pattern, JSRegExpFlag... flags) {
@ -60,23 +70,23 @@ public abstract class JSRegExp implements JSObject {
}
@JSProperty
public abstract boolean isGlobal();
public native boolean isGlobal();
@JSProperty
public abstract boolean isIgnoreCase();
public native boolean isIgnoreCase();
@JSProperty
public abstract boolean isMultiline();
public native boolean isMultiline();
@JSProperty
public abstract int getLastIndex();
public native int getLastIndex();
@JSProperty
public abstract JSString getSource();
public native JSString getSource();
public abstract JSArray<JSString> exec(JSString text);
public native JSArray<JSString> exec(JSString text);
public abstract boolean test(JSString text);
public native boolean test(JSString text);
public abstract boolean test(String text);
public native boolean test(String text);
}

View File

@ -36,7 +36,6 @@ public abstract class JSString implements JSObject {
@NoSideEffects
public static native JSString valueOf(String str);
@JSBody(params = "code", script = "return String.fromCharCode(code)")
@NoSideEffects
public static native JSString fromCharCode(int code);

View File

@ -19,7 +19,10 @@ import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject;
public abstract class JSSymbol<T> implements JSObject {
public class JSSymbol<T> implements JSObject {
private JSSymbol() {
}
@JSBody(params = "name", script = "return Symbol(name);")
public static native <T> JSSymbol<T> create(String name);

View File

@ -17,19 +17,25 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
public abstract class JSWeakMap<K, V> implements JSObject {
public abstract V get(K key);
@JSClass(name = "WeakMap")
public class JSWeakMap<K, V> implements JSObject {
public JSWeakMap() {
}
public abstract boolean has(K key);
public native V get(K key);
public abstract JSWeakMap<K, V> set(K key, V value);
public native boolean has(K key);
public abstract boolean remove(K key);
public native JSWeakMap<K, V> set(K key, V value);
public native boolean remove(K key);
@JSBody(script = "return new WeakMap();")
@NoSideEffects
@Deprecated
public static native <K, V> JSWeakMap<K, V> create();
@JSBody(script = "return typeof WeakMap !== 'undefined';")

View File

@ -17,13 +17,19 @@ package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
@JSClass(name = "WeakRef")
public abstract class JSWeakRef<T> implements JSObject {
public JSWeakRef(T value) {
}
public abstract T deref();
@JSBody(params = "value", script = "return new WeakRef(value);")
@NoSideEffects
@Deprecated
public static native <T> JSWeakRef<T> create(T value);
@JSBody(script = "return typeof WeakRef !== 'undefined';")

View File

@ -15,16 +15,15 @@
*/
package org.teavm.jso.json;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
public final class JSON {
@JSClass
public final class JSON implements JSObject {
private JSON() {
}
@JSBody(params = "object", script = "return JSON.stringify(object);")
public static native String stringify(JSObject object);
@JSBody(params = "string", script = "return JSON.parse(string);")
public static native JSObject parse(String string);
}

View File

@ -16,15 +16,24 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
public abstract class ArrayBuffer implements JSObject {
@JSProperty
public abstract int getByteLength();
@JSClass
public class ArrayBuffer implements JSObject {
public ArrayBuffer() {
}
public abstract ArrayBuffer slice(int begin, int end);
public ArrayBuffer(int length) {
}
@JSProperty
public native int getByteLength();
public native ArrayBuffer slice(int begin, int end);
@JSBody(params = "length", script = "return new ArrayBuffer(length);")
@Deprecated
public static native ArrayBuffer create(int length);
}

View File

@ -25,42 +25,42 @@ public abstract class ArrayBufferView implements JSObject {
}
@JSProperty
public abstract int getLength();
public native int getLength();
@JSProperty
public abstract int getByteLength();
public native int getByteLength();
@JSProperty
public abstract int getByteOffset();
public native int getByteOffset();
@JSProperty
public abstract ArrayBuffer getBuffer();
public native ArrayBuffer getBuffer();
public abstract void set(ArrayBufferView other, int offset);
public native void set(ArrayBufferView other, int offset);
public abstract void set(ArrayBufferView other);
public native void set(ArrayBufferView other);
public abstract void set(JSArrayReader<?> other, int offset);
public native void set(JSArrayReader<?> other, int offset);
public abstract void set(JSArrayReader<?> other);
public native void set(JSArrayReader<?> other);
public abstract void set(@JSByRef byte[] other, int offset);
public native void set(@JSByRef byte[] other, int offset);
public abstract void set(@JSByRef byte[] other);
public native void set(@JSByRef byte[] other);
public abstract void set(@JSByRef short[] other, int offset);
public native void set(@JSByRef short[] other, int offset);
public abstract void set(@JSByRef short[] other);
public native void set(@JSByRef short[] other);
public abstract void set(@JSByRef int[] other, int offset);
public native void set(@JSByRef int[] other, int offset);
public abstract void set(@JSByRef int[] other);
public native void set(@JSByRef int[] other);
public abstract void set(@JSByRef float[] other, int offset);
public native void set(@JSByRef float[] other, int offset);
public abstract void set(@JSByRef float[] other);
public native void set(@JSByRef float[] other);
public abstract void set(@JSByRef double[] other, int offset);
public native void set(@JSByRef double[] other, int offset);
public abstract void set(@JSByRef double[] other);
public native void set(@JSByRef double[] other);
}

View File

@ -16,65 +16,80 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
public abstract class DataView extends ArrayBufferView {
public abstract byte getInt8(int byteOffset);
@JSClass
public class DataView extends ArrayBufferView {
public DataView(ArrayBuffer buffer) {
}
public abstract short getUint8(int byteOffset);
public DataView(ArrayBufferView buffer) {
}
public abstract short getInt16(int byteOffset);
public DataView(ArrayBuffer buffer, int offset, int length) {
}
public abstract short getInt16(int byteOffset, boolean littleEndian);
public DataView(ArrayBuffer buffer, int offset) {
}
public abstract int getUint16(int byteOffset);
public native byte getInt8(int byteOffset);
public abstract int getUint16(int byteOffset, boolean littleEndian);
public native short getUint8(int byteOffset);
public abstract int getInt32(int byteOffset);
public native short getInt16(int byteOffset);
public abstract int getInt32(int byteOffset, boolean littleEndian);
public native short getInt16(int byteOffset, boolean littleEndian);
public abstract int getUint32(int byteOffset);
public native int getUint16(int byteOffset);
public abstract int getUint32(int byteOffset, boolean littleEndian);
public native int getUint16(int byteOffset, boolean littleEndian);
public abstract float getFloat32(int byteOffset);
public native int getInt32(int byteOffset);
public abstract float getFloat32(int byteOffset, boolean littleEndian);
public native int getInt32(int byteOffset, boolean littleEndian);
public abstract double getFloat64(int byteOffset);
public native int getUint32(int byteOffset);
public abstract double getFloat64(int byteOffset, boolean littleEndian);
public native int getUint32(int byteOffset, boolean littleEndian);
public abstract void setInt8(int byteOffset, int value);
public native float getFloat32(int byteOffset);
public abstract void setUint8(int byteOffset, int value);
public native float getFloat32(int byteOffset, boolean littleEndian);
public abstract void setInt16(int byteOffset, int value);
public native double getFloat64(int byteOffset);
public abstract void setInt16(int byteOffset, int value, boolean littleEndian);
public native double getFloat64(int byteOffset, boolean littleEndian);
public abstract void setUint16(int byteOffset, int value);
public native void setInt8(int byteOffset, int value);
public abstract void setUint16(int byteOffset, int value, boolean littleEndian);
public native void setUint8(int byteOffset, int value);
public abstract void setInt32(int byteOffset, int value);
public native void setInt16(int byteOffset, int value);
public abstract void setInt32(int byteOffset, int value, boolean littleEndian);
public native void setInt16(int byteOffset, int value, boolean littleEndian);
public abstract void setUint32(int byteOffset, int value);
public native void setUint16(int byteOffset, int value);
public abstract void setUint32(int byteOffset, int value, boolean littleEndian);
public native void setUint16(int byteOffset, int value, boolean littleEndian);
public abstract void setFloat32(int byteOffset, float value);
public native void setInt32(int byteOffset, int value);
public abstract void setFloat32(int byteOffset, float value, boolean littleEndian);
public native void setInt32(int byteOffset, int value, boolean littleEndian);
public abstract void setFloat64(int byteOffset, double value);
public native void setUint32(int byteOffset, int value);
public abstract void setFloat64(int byteOffset, double value, boolean littleEndian);
public native void setUint32(int byteOffset, int value, boolean littleEndian);
public native void setFloat32(int byteOffset, float value);
public native void setFloat32(int byteOffset, float value, boolean littleEndian);
public native void setFloat64(int byteOffset, double value);
public native void setFloat64(int byteOffset, double value, boolean littleEndian);
@JSBody(params = "buffer", script = "return new DataView(buffer);")
@Deprecated
public static native DataView create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new DataView(buffer);")

View File

@ -16,27 +16,49 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Float32Array extends ArrayBufferView {
@JSIndexer
public abstract float get(int index);
@JSClass
public class Float32Array extends ArrayBufferView {
public Float32Array(int length) {
}
public Float32Array(ArrayBuffer buffer) {
}
public Float32Array(ArrayBufferView buffer) {
}
public Float32Array(ArrayBuffer buffer, int offset, int length) {
}
public Float32Array(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, float value);
public native float get(int index);
@JSIndexer
public native void set(int index, float value);
@JSBody(params = "length", script = "return new Float32Array(length);")
@Deprecated
public static native Float32Array create(int length);
@JSBody(params = "buffer", script = "return new Float32Array(buffer);")
@Deprecated
public static native Float32Array create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Float32Array(buffer);")
@Deprecated
public static native Float32Array create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new Float32Array(buffer, offset, length);")
@Deprecated
public static native Float32Array create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Float32Array(buffer, offset);")
@Deprecated
public static native Float32Array create(ArrayBuffer buffer, int offset);
}

View File

@ -16,27 +16,49 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Float64Array extends ArrayBufferView {
@JSIndexer
public abstract double get(int index);
@JSClass
public class Float64Array extends ArrayBufferView {
public Float64Array(int length) {
}
public Float64Array(ArrayBuffer buffer) {
}
public Float64Array(ArrayBufferView buffer) {
}
public Float64Array(ArrayBuffer buffer, int offset, int length) {
}
public Float64Array(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, double value);
public native double get(int index);
@JSIndexer
public native void set(int index, double value);
@JSBody(params = "length", script = "return new Float64Array(length);")
@Deprecated
public static native Float64Array create(int length);
@JSBody(params = "buffer", script = "return new Float64Array(buffer);")
@Deprecated
public static native Float64Array create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Float64Array(buffer);")
@Deprecated
public static native Float64Array create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new Float64Array(buffer, offset, length);")
@Deprecated
public static native Float64Array create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Float64Array(buffer, offset);")
@Deprecated
public static native Float64Array create(ArrayBuffer buffer, int offset);
}

View File

@ -16,27 +16,49 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Int16Array extends ArrayBufferView {
@JSIndexer
public abstract short get(int index);
@JSClass
public class Int16Array extends ArrayBufferView {
public Int16Array(int length) {
}
public Int16Array(ArrayBuffer buffer) {
}
public Int16Array(ArrayBufferView buffer) {
}
public Int16Array(ArrayBuffer buffer, int offset, int length) {
}
public Int16Array(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, short value);
public native short get(int index);
@JSIndexer
public native void set(int index, short value);
@JSBody(params = "length", script = "return new Int16Array(length);")
@Deprecated
public static native Int16Array create(int length);
@JSBody(params = "buffer", script = "return new Int16Array(buffer);")
@Deprecated
public static native Int16Array create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Int16Array(buffer);")
@Deprecated
public static native Int16Array create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new Int16Array(buffer, offset, length);")
@Deprecated
public static native Int16Array create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Int16Array(buffer, offset);")
@Deprecated
public static native Int16Array create(ArrayBuffer buffer, int offset);
}

View File

@ -17,31 +17,55 @@ package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSByRef;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Int32Array extends ArrayBufferView {
@JSIndexer
public abstract int get(int index);
@JSClass
public class Int32Array extends ArrayBufferView {
public Int32Array(int length) {
}
public Int32Array(ArrayBuffer buffer) {
}
public Int32Array(ArrayBufferView buffer) {
}
public Int32Array(ArrayBuffer buffer, int offset, int length) {
}
public Int32Array(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, int value);
public native int get(int index);
public abstract void set(@JSByRef int[] data, int offset);
@JSIndexer
public native void set(int index, int value);
public abstract void set(@JSByRef int[] data);
@Override
public native void set(@JSByRef int[] data, int offset);
@Override
public native void set(@JSByRef int[] data);
@JSBody(params = "length", script = "return new Int32Array(length);")
@Deprecated
public static native Int32Array create(int length);
@JSBody(params = "buffer", script = "return new Int32Array(buffer);")
@Deprecated
public static native Int32Array create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Int32Array(buffer);")
@Deprecated
public static native Int32Array create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new Int32Array(buffer, offset, length);")
@Deprecated
public static native Int32Array create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Int32Array(buffer, offset);")
@Deprecated
public static native Int32Array create(ArrayBuffer buffer, int offset);
}

View File

@ -16,27 +16,49 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Int8Array extends ArrayBufferView {
@JSIndexer
public abstract byte get(int index);
@JSClass
public class Int8Array extends ArrayBufferView {
public Int8Array(int length) {
}
public Int8Array(ArrayBuffer buffer) {
}
public Int8Array(ArrayBufferView buffer) {
}
public Int8Array(ArrayBuffer buffer, int offset, int length) {
}
public Int8Array(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, byte value);
public native byte get(int index);
@JSIndexer
public native void set(int index, byte value);
@JSBody(params = "length", script = "return new Int8Array(length);")
@Deprecated
public static native Int8Array create(int length);
@JSBody(params = "buffer", script = "return new Int8Array(buffer);")
@Deprecated
public static native Int8Array create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Int8Array(buffer);")
@Deprecated
public static native Int8Array create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new Int8Array(buffer, offset, length);")
@Deprecated
public static native Int8Array create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Int8Array(buffer, offset);")
@Deprecated
public static native Int8Array create(ArrayBuffer buffer, int offset);
}

View File

@ -16,27 +16,49 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Uint16Array extends ArrayBufferView {
@JSIndexer
public abstract int get(int index);
@JSClass
public class Uint16Array extends ArrayBufferView {
public Uint16Array(int length) {
}
public Uint16Array(ArrayBuffer buffer) {
}
public Uint16Array(ArrayBufferView buffer) {
}
public Uint16Array(ArrayBuffer buffer, int offset, int length) {
}
public Uint16Array(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, int value);
public native int get(int index);
@JSIndexer
public native void set(int index, int value);
@JSBody(params = "length", script = "return new Uint16Array(length);")
@Deprecated
public static native Uint16Array create(int length);
@JSBody(params = "buffer", script = "return new Uint16Array(buffer);")
@Deprecated
public static native Uint16Array create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Uint16Array(buffer);")
@Deprecated
public static native Uint16Array create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new Uint16Array(buffer, offset, length);")
@Deprecated
public static native Uint16Array create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Uint16Array(buffer, offset);")
@Deprecated
public static native Uint16Array create(ArrayBuffer buffer, int offset);
}

View File

@ -16,27 +16,49 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Uint8Array extends ArrayBufferView {
@JSIndexer
public abstract short get(int index);
@JSClass
public class Uint8Array extends ArrayBufferView {
public Uint8Array(int length) {
}
public Uint8Array(ArrayBuffer buffer) {
}
public Uint8Array(ArrayBufferView buffer) {
}
public Uint8Array(ArrayBuffer buffer, int offset, int length) {
}
public Uint8Array(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, short value);
public native short get(int index);
@JSIndexer
public native void set(int index, short value);
@JSBody(params = "length", script = "return new Uint8Array(length);")
@Deprecated
public static native Uint8Array create(int length);
@JSBody(params = "buffer", script = "return new Uint8Array(buffer);")
@Deprecated
public static native Uint8Array create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Uint8Array(buffer);")
@Deprecated
public static native Uint8Array create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new Uint8Array(buffer, offset, length);")
@Deprecated
public static native Uint8Array create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Uint8Array(buffer, offset);")
@Deprecated
public static native Uint8Array create(ArrayBuffer buffer, int offset);
}

View File

@ -16,26 +16,47 @@
package org.teavm.jso.typedarrays;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSIndexer;
public abstract class Uint8ClampedArray extends ArrayBufferView {
@JSIndexer
public abstract short get(int index);
@JSClass
public class Uint8ClampedArray extends ArrayBufferView {
public Uint8ClampedArray(int length) {
}
public Uint8ClampedArray(ArrayBuffer buffer) {
}
public Uint8ClampedArray(ArrayBufferView buffer) {
}
public Uint8ClampedArray(ArrayBuffer buffer, int offset, int length) {
}
public Uint8ClampedArray(ArrayBuffer buffer, int offset) {
}
@JSIndexer
public abstract void set(int index, int value);
public native short get(int index);
@JSIndexer
public native void set(int index, int value);
@JSBody(params = "length", script = "return new Uint8ClampedArray(length);")
@Deprecated
public static native Uint8ClampedArray create(int length);
@JSBody(params = "buffer", script = "return new Uint8ClampedArray(buffer);")
@Deprecated
public static native Uint8ClampedArray create(ArrayBuffer buffer);
@JSBody(params = "buffer", script = "return new Uint8ClampedArray(buffer);")
@Deprecated
public static native Uint8ClampedArray create(ArrayBufferView buffer);
@JSBody(params = { "buffer", "offset", "length" }, script = "return new "
+ "Uint8ClampedArray(buffer, offset, length);")
@Deprecated
public static native Uint8ClampedArray create(ArrayBuffer buffer, int offset, int length);
@JSBody(params = { "buffer", "offset" }, script = "return new Uint8ClampedArray(buffer, offset);")

View File

@ -17,6 +17,7 @@ package org.teavm.jso.webaudio;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSByRef;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
@ -24,108 +25,110 @@ import org.teavm.jso.dom.html.HTMLMediaElement;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.Float32Array;
public abstract class AudioContext implements JSObject {
@JSClass
public class AudioContext implements JSObject {
public static final String STATE_SUSPENDED = "suspended";
public static final String STATE_RUNNING = "running";
public static final String STATE_CLOSE = "close";
@JSProperty
public abstract AudioDestinationNode getDestination();
public native AudioDestinationNode getDestination();
@JSProperty
public abstract float getSampleRate();
public native float getSampleRate();
@JSProperty
public abstract double getCurrentTime();
public native double getCurrentTime();
@JSProperty
public abstract AudioListener getListener();
public native AudioListener getListener();
@JSProperty
public abstract String getState();
public native String getState();
@JSProperty("onstatechange")
public abstract void setOnStateChange(EventListener<MediaEvent> listener);
public native void setOnStateChange(EventListener<MediaEvent> listener);
@JSProperty("onstatechange")
public abstract EventListener<MediaEvent> getOnStateChange();
public native EventListener<MediaEvent> getOnStateChange();
public abstract void suspend();
public native void suspend();
public abstract void resume();
public native void resume();
public abstract void close();
public native void close();
public abstract AudioBuffer createBuffer(int numberOfChannels, int length, float sampleRate);
public native AudioBuffer createBuffer(int numberOfChannels, int length, float sampleRate);
public abstract AudioBuffer decodeAudioData(ArrayBuffer audioData, DecodeSuccessCallback successCallback,
public native AudioBuffer decodeAudioData(ArrayBuffer audioData, DecodeSuccessCallback successCallback,
DecodeErrorCallback errorCallback);
public abstract AudioBuffer decodeAudioData(ArrayBuffer audioData, DecodeSuccessCallback successCallback);
public native AudioBuffer decodeAudioData(ArrayBuffer audioData, DecodeSuccessCallback successCallback);
public abstract AudioBuffer decodeAudioData(ArrayBuffer audioData);
public native AudioBuffer decodeAudioData(ArrayBuffer audioData);
public abstract AudioBufferSourceNode createBufferSource();
public native AudioBufferSourceNode createBufferSource();
public abstract MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
public native MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
public abstract MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
public native MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
public abstract MediaStreamAudioDestinationNode createMediaStreamDestination();
public native MediaStreamAudioDestinationNode createMediaStreamDestination();
public abstract AudioWorker createAudioWorker();
public native AudioWorker createAudioWorker();
public abstract ScriptProcessorNode createScriptProcessor(int bufferSize, int numberOfInputChannels,
public native ScriptProcessorNode createScriptProcessor(int bufferSize, int numberOfInputChannels,
int numberOfOutputChannels);
public abstract ScriptProcessorNode createScriptProcessor(int bufferSize, int numberOfInputChannels);
public native ScriptProcessorNode createScriptProcessor(int bufferSize, int numberOfInputChannels);
public abstract ScriptProcessorNode createScriptProcessor(int bufferSize);
public native ScriptProcessorNode createScriptProcessor(int bufferSize);
public abstract ScriptProcessorNode createScriptProcessor();
public native ScriptProcessorNode createScriptProcessor();
public abstract AnalyserNode createAnalyser();
public native AnalyserNode createAnalyser();
public abstract GainNode createGain();
public native GainNode createGain();
public abstract DelayNode createDelay(double maxDelayTime);
public native DelayNode createDelay(double maxDelayTime);
public abstract DelayNode createDelay();
public native DelayNode createDelay();
public abstract BiquadFilterNode createBiquadFilter();
public native BiquadFilterNode createBiquadFilter();
public abstract IIRFilterNode createIIRFilter(Float32Array feedforward, Float32Array feedback);
public native IIRFilterNode createIIRFilter(Float32Array feedforward, Float32Array feedback);
public abstract WaveShaperNode createWaveShaper();
public native WaveShaperNode createWaveShaper();
public abstract PannerNode createPanner();
public native PannerNode createPanner();
public abstract StereoPannerNode createStereoPanner();
public native StereoPannerNode createStereoPanner();
public abstract ConvolverNode createConvolver();
public native ConvolverNode createConvolver();
public abstract ChannelSplitterNode createChannelSplitter(int numberOfOutputs);
public native ChannelSplitterNode createChannelSplitter(int numberOfOutputs);
public abstract ChannelSplitterNode createChannelSplitter();
public native ChannelSplitterNode createChannelSplitter();
public abstract ChannelMergerNode createChannelMerger(int numberOfInputs);
public native ChannelMergerNode createChannelMerger(int numberOfInputs);
public abstract ChannelMergerNode createChannelMerger();
public native ChannelMergerNode createChannelMerger();
public abstract DynamicsCompressorNode createDynamicsCompressor();
public native DynamicsCompressorNode createDynamicsCompressor();
public abstract OscillatorNode createOscillator();
public native OscillatorNode createOscillator();
public abstract PeriodicWave createPeriodicWave(Float32Array real, Float32Array image,
public native PeriodicWave createPeriodicWave(Float32Array real, Float32Array image,
PeriodicWaveConstraints constraints);
public abstract PeriodicWave createPeriodicWave(@JSByRef float[] real, @JSByRef float[] image,
public native PeriodicWave createPeriodicWave(@JSByRef float[] real, @JSByRef float[] image,
PeriodicWaveConstraints constraints);
public abstract PeriodicWave createPeriodicWave(Float32Array real, Float32Array image);
public native PeriodicWave createPeriodicWave(Float32Array real, Float32Array image);
public abstract PeriodicWave createPeriodicWave(@JSByRef float[] real, @JSByRef float[] image);
public native PeriodicWave createPeriodicWave(@JSByRef float[] real, @JSByRef float[] image);
@JSBody(script = "var Context = window.AudioContext || window.webkitAudioContext; return new Context();")
@JSBody(script = "return new Context();")
@Deprecated
public static native AudioContext create();
}

View File

@ -15,20 +15,22 @@
*/
package org.teavm.jso.webaudio;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.EventListener;
public abstract class OfflineAudioContext extends AudioContext {
@JSClass
public class OfflineAudioContext extends AudioContext {
@JSProperty("oncomplete")
public abstract void setOnComplete(EventListener<OfflineAudioCompletionEvent> event);
public native void setOnComplete(EventListener<OfflineAudioCompletionEvent> event);
@JSProperty("oncomplete")
public abstract EventListener<OfflineAudioCompletionEvent> getOnComplete();
public native EventListener<OfflineAudioCompletionEvent> getOnComplete();
public abstract AudioBuffer startRendering();
public native AudioBuffer startRendering();
@Override
public abstract void resume();
public native void resume();
public abstract void suspend(double suspendTime);
public native void suspend(double suspendTime);
}

View File

@ -16,6 +16,7 @@
package org.teavm.jso.websocket;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.Event;
@ -24,60 +25,73 @@ import org.teavm.jso.dom.events.MessageEvent;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.ArrayBufferView;
public abstract class WebSocket implements JSObject {
@JSClass
public class WebSocket implements JSObject {
public WebSocket(String url) {
}
public WebSocket(String url, String protocols) {
}
public WebSocket(String url, String[] protocols) {
}
@JSProperty("onclose")
public abstract void onClose(EventListener<CloseEvent> eventListener);
public native void onClose(EventListener<CloseEvent> eventListener);
@JSProperty("onerror")
public abstract void onError(EventListener<Event> eventListener);
public native void onError(EventListener<Event> eventListener);
@JSProperty("onmessage")
public abstract void onMessage(EventListener<MessageEvent> eventListener);
public native void onMessage(EventListener<MessageEvent> eventListener);
@JSProperty("onopen")
public abstract void onOpen(EventListener<Event> eventListener);
public native void onOpen(EventListener<Event> eventListener);
@JSBody(params = "url", script = "return new WebSocket(url);")
@Deprecated
public static native WebSocket create(String url);
@JSBody(params = { "url", "protocols" }, script = "return new WebSocket(url, protocols);")
@Deprecated
public static native WebSocket create(String url, String protocols);
@JSBody(params = { "url", "protocols" }, script = "return new WebSocket(url, protocols);")
@Deprecated
public static native WebSocket create(String url, String[] protocols);
public abstract void close();
public native void close();
public abstract void close(int code);
public native void close(int code);
public abstract void close(int code, String reason);
public native void close(int code, String reason);
public abstract void send(String data);
public native void send(String data);
public abstract void send(ArrayBuffer data);
public native void send(ArrayBuffer data);
public abstract void send(ArrayBufferView data);
public native void send(ArrayBufferView data);
@JSProperty
public abstract String getBinaryType();
public native String getBinaryType();
@JSProperty
public abstract void setBinaryType(String binaryType);
public native void setBinaryType(String binaryType);
@JSProperty
public abstract int getBufferedAmount();
public native int getBufferedAmount();
@JSProperty
public abstract String getExtensions();
public native String getExtensions();
@JSProperty
public abstract String getProtocol();
public native String getProtocol();
@JSProperty
public abstract int getReadyState();
public native int getReadyState();
@JSProperty
public abstract String getUrl();
public native String getUrl();
@JSBody(script = "return typeof WebSocket !== 'undefined';")
public static native boolean isSupported();

View File

@ -17,11 +17,36 @@ package org.teavm.jso.workers;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.ErrorEvent;
import org.teavm.jso.dom.events.Event;
import org.teavm.jso.dom.events.EventListener;
public class SharedWorker implements AbstractWorker {
public SharedWorker(String url) {
}
public abstract class SharedWorker implements AbstractWorker {
@JSBody(params = "url", script = "return new SharedWorker(url);")
@Deprecated
public static native Worker create(String url);
@JSProperty
public abstract MessagePort getPort();
public native MessagePort getPort();
@Override
public native void onError(EventListener<ErrorEvent> listener);
@Override
public native void addEventListener(String type, EventListener<?> listener, boolean useCapture);
@Override
public native void addEventListener(String type, EventListener<?> listener);
@Override
public native void removeEventListener(String type, EventListener<?> listener, boolean useCapture);
@Override
public native void removeEventListener(String type, EventListener<?> listener);
@Override
public native boolean dispatchEvent(Event evt);
}

View File

@ -16,18 +16,44 @@
package org.teavm.jso.workers;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSProperty;
import org.teavm.jso.dom.events.ErrorEvent;
import org.teavm.jso.dom.events.Event;
import org.teavm.jso.dom.events.EventListener;
import org.teavm.jso.dom.events.MessageEvent;
public abstract class Worker implements AbstractWorker {
@JSClass
public class Worker implements AbstractWorker {
public Worker(String url) {
}
@JSBody(params = "url", script = "return new Worker(url);")
@Deprecated
public static native Worker create(String url);
@JSProperty("onmessage")
public abstract void onMessage(EventListener<MessageEvent> listener);
public native void onMessage(EventListener<MessageEvent> listener);
public abstract void postMessage(Object message);
public native void postMessage(Object message);
public abstract void terminate();
public native void terminate();
@Override
public native void onError(EventListener<ErrorEvent> listener);
@Override
public native void addEventListener(String type, EventListener<?> listener, boolean useCapture);
@Override
public native void addEventListener(String type, EventListener<?> listener);
@Override
public native void removeEventListener(String type, EventListener<?> listener, boolean useCapture);
@Override
public native void removeEventListener(String type, EventListener<?> listener);
@Override
public native boolean dispatchEvent(Event evt);
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface JSModule {
String value();
}

View File

@ -140,7 +140,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<T> result = JSArray.create(array.length);
var result = new JSArray<T>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, array[i]);
}
@ -155,7 +155,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<T> result = JSArray.create(array.length);
var result = new JSArray<T>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, f.apply(array[i]));
}
@ -178,7 +178,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSBoolean> result = JSArray.create(array.length);
var result = new JSArray<JSBoolean>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSBoolean.valueOf(array[i]));
}
@ -193,7 +193,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSNumber> result = JSArray.create(array.length);
var result = new JSArray<JSNumber>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSNumber.valueOf(array[i]));
}
@ -208,7 +208,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSNumber> result = JSArray.create(array.length);
var result = new JSArray<JSNumber>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSNumber.valueOf(array[i]));
}
@ -223,7 +223,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSNumber> result = JSArray.create(array.length);
var result = new JSArray<JSNumber>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSNumber.valueOf(array[i]));
}
@ -238,7 +238,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSNumber> result = JSArray.create(array.length);
var result = new JSArray<JSNumber>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSNumber.valueOf(array[i]));
}
@ -253,7 +253,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSString> result = JSArray.create(array.length);
var result = new JSArray<JSString>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSString.valueOf(array[i]));
}
@ -268,7 +268,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSNumber> result = JSArray.create(array.length);
var result = new JSArray<JSNumber>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSNumber.valueOf(array[i]));
}
@ -283,7 +283,7 @@ final class JS {
if (array == null) {
return null;
}
JSArray<JSNumber> result = JSArray.create(array.length);
var result = new JSArray<JSNumber>(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, JSNumber.valueOf(array[i]));
}
@ -516,6 +516,71 @@ final class JS {
JSObject d, JSObject e, JSObject f, JSObject g, JSObject h, JSObject i, JSObject j, JSObject k,
JSObject l, JSObject m);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f, JSObject g);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f, JSObject g, JSObject h);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f, JSObject g, JSObject h, JSObject i);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f, JSObject g, JSObject h, JSObject i, JSObject j);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f, JSObject g, JSObject h, JSObject i, JSObject j, JSObject k);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f, JSObject g, JSObject h, JSObject i, JSObject j, JSObject k, JSObject l);
@InjectedBy(JSNativeInjector.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject construct(JSObject cls, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e,
JSObject f, JSObject g, JSObject h, JSObject i, JSObject j, JSObject k, JSObject l, JSObject m);
@InjectedBy(JSNativeInjector.class)
@JSBody(params = { "instance", "index" }, script = "return instance[index];")
public static native JSObject get(JSObject instance, JSObject index);
@ -541,4 +606,12 @@ final class JS {
@GeneratedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeInjector.class)
public static native JSObject functionAsObject(JSObject instance, JSObject property);
@InjectedBy(JSNativeInjector.class)
@NoSideEffects
public static native JSObject global(String name);
@InjectedBy(JSNativeInjector.class)
@NoSideEffects
public static native JSObject importModule(String name);
}

View File

@ -239,7 +239,7 @@ class JSAliasRenderer implements RendererListener, VirtualMethodContributor {
return true;
}
for (var method : cls.getMethods()) {
if (!method.hasModifier(ElementModifier.STATIC) && getPublicAlias(method) != null) {
if (getPublicAlias(method) != null) {
return true;
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.impl;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.AccessLevel;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
abstract class JSAnnotationCache<T> {
private ClassReaderSource classes;
protected Diagnostics diagnostics;
private Map<MethodReference, Value<T>> data = new HashMap<>();
JSAnnotationCache(ClassReaderSource classes, Diagnostics diagnostics) {
this.classes = classes;
this.diagnostics = diagnostics;
}
T get(MethodReference methodReference, CallLocation location) {
var result = getValue(methodReference, location);
return result != null ? result.annotation : null;
}
private Value<T> getValue(MethodReference methodReference, CallLocation location) {
var result = data.get(methodReference);
if (result == null) {
result = extract(methodReference, location);
data.put(methodReference, result);
}
return result;
}
private Value<T> extract(MethodReference methodReference, CallLocation location) {
var cls = classes.get(methodReference.getClassName());
if (cls == null) {
return new Value<>(null, methodReference);
}
var method = cls.getMethod(methodReference.getDescriptor());
if (method == null || method.hasModifier(ElementModifier.STATIC)
|| method.getLevel() == AccessLevel.PRIVATE) {
for (var candidateMethod : cls.getMethods()) {
if (candidateMethod.getName().equals(methodReference.getName())
&& !candidateMethod.hasModifier(ElementModifier.STATIC)
&& !candidateMethod.hasModifier(ElementModifier.FINAL)
&& candidateMethod.getLevel() != AccessLevel.PRIVATE
&& Arrays.equals(candidateMethod.getParameterTypes(), methodReference.getParameterTypes())) {
method = candidateMethod;
break;
}
}
}
if (method != null) {
methodReference = method.getReference();
var annotation = take(method, location);
if (annotation != null) {
return new Value<>(annotation, methodReference);
}
}
var candidates = new HashMap<MethodReference, T>();
if (cls.getParent() != null) {
var value = getValue(new MethodReference(cls.getParent(), methodReference.getDescriptor()), location);
if (value.annotation != null) {
candidates.put(value.source, value.annotation);
}
}
for (var itf : cls.getInterfaces()) {
var value = getValue(new MethodReference(itf, methodReference.getDescriptor()), location);
if (value != null) {
candidates.put(value.source, value.annotation);
}
}
if (candidates.isEmpty()) {
return new Value<>(null, methodReference);
}
if (candidates.size() == 1) {
var entry = candidates.entrySet().iterator().next();
return new Value<>(entry.getValue(), entry.getKey());
}
T annot = null;
MethodReference lastMethod = null;
for (var entry : candidates.entrySet()) {
if (annot != null && !annot.equals(entry.getValue())) {
diagnostics.error(location, "Method '{{m0}}' has inconsistent JS annotations from overridden "
+ "methods '{{m1}}' and '{{m2}}', so it should be annotated explicitly",
methodReference, lastMethod, entry.getKey());
return new Value<>(null, methodReference);
}
annot = entry.getValue();
lastMethod = entry.getKey();
}
return new Value<>(annot, methodReference);
}
protected abstract T take(MethodReader method, CallLocation location);
private static class Value<T> {
final T annotation;
final MethodReference source;
Value(T annotation, MethodReference source) {
this.annotation = annotation;
this.source = source;
}
}
}

View File

@ -18,6 +18,7 @@ package org.teavm.jso.impl;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -35,10 +36,7 @@ import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSByRef;
import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
import org.teavm.model.AnnotationContainerReader;
import org.teavm.model.AnnotationHolder;
import org.teavm.model.AnnotationReader;
@ -63,6 +61,7 @@ import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.GetElementInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction;
@ -91,6 +90,8 @@ class JSClassProcessor {
private final JSBodyRepository repository;
private final JavaInvocationProcessor javaInvocationProcessor;
private Program program;
private int[] variableAliases;
private boolean[] nativeConstructedObjects;
private JSTypeInference types;
private final List<Instruction> replacement = new ArrayList<>();
private final JSTypeHelper typeHelper;
@ -98,6 +99,7 @@ class JSClassProcessor {
private final Map<MethodReference, MethodReader> overriddenMethodCache = new HashMap<>();
private JSValueMarshaller marshaller;
private IncrementalDependencyRegistration incrementalCache;
private JSImportAnnotationCache annotationCache;
JSClassProcessor(ClassReaderSource classSource, JSTypeHelper typeHelper, JSBodyRepository repository,
Diagnostics diagnostics, IncrementalDependencyRegistration incrementalCache) {
@ -107,6 +109,8 @@ class JSClassProcessor {
this.diagnostics = diagnostics;
this.incrementalCache = incrementalCache;
javaInvocationProcessor = new JavaInvocationProcessor(typeHelper, repository, classSource, diagnostics);
annotationCache = new JSImportAnnotationCache(classSource, diagnostics);
}
public ClassReaderSource getClassSource() {
@ -220,6 +224,48 @@ class JSClassProcessor {
private void setCurrentProgram(Program program) {
this.program = program;
marshaller = new JSValueMarshaller(diagnostics, typeHelper, classSource, program, replacement);
findVariableAliases();
}
private void findVariableAliases() {
if (program == null) {
return;
}
variableAliases = new int[program.variableCount()];
nativeConstructedObjects = new boolean[program.variableCount()];
var resolved = new boolean[program.variableCount()];
Arrays.fill(resolved, true);
for (var i = 0; i < variableAliases.length; ++i) {
variableAliases[i] = i;
}
for (var block : program.getBasicBlocks()) {
for (var instruction : block) {
if (instruction instanceof AssignInstruction) {
var assign = (AssignInstruction) instruction;
var from = assign.getAssignee().getIndex();
var to = assign.getReceiver().getIndex();
variableAliases[to] = from;
resolved[assign.getAssignee().getIndex()] = true;
} else if (instruction instanceof ConstructInstruction) {
var construct = (ConstructInstruction) instruction;
if (typeHelper.isJavaScriptClass(construct.getType())) {
nativeConstructedObjects[construct.getReceiver().getIndex()] = true;
}
}
}
}
for (var i = 0; i < variableAliases.length; ++i) {
getVariableAlias(i, resolved);
}
}
private int getVariableAlias(int index, boolean[] resolved) {
if (resolved[index]) {
return variableAliases[index];
}
resolved[index] = true;
variableAliases[index] = getVariableAlias(variableAliases[index], resolved);
return variableAliases[index];
}
void processProgram(MethodHolder methodToProcess) {
@ -266,9 +312,28 @@ class JSClassProcessor {
methodToProcess.getResultType()));
} else if (insn instanceof ClassConstantInstruction) {
processClassConstant((ClassConstantInstruction) insn);
} else if (insn instanceof ConstructInstruction) {
processConstructObject((ConstructInstruction) insn);
} else if (insn instanceof AssignInstruction) {
var assign = (AssignInstruction) insn;
var index = variableAliases[assign.getReceiver().getIndex()];
if (nativeConstructedObjects[index]) {
assign.delete();
}
}
}
}
var varMapper = new InstructionVariableMapper(v -> {
if (v.getIndex() < nativeConstructedObjects.length
&& nativeConstructedObjects[variableAliases[v.getIndex()]]) {
return program.variableAt(variableAliases[v.getIndex()]);
}
return v;
});
for (var block : program.getBasicBlocks()) {
varMapper.apply(block);
}
}
private void processInvokeArgs(InvokeInstruction invoke, MethodReader methodToInvoke) {
@ -346,6 +411,12 @@ class JSClassProcessor {
insn.setConstant(processType(insn.getConstant()));
}
private void processConstructObject(ConstructInstruction insn) {
if (nativeConstructedObjects[insn.getReceiver().getIndex()]) {
insn.delete();
}
}
private ValueType processType(ValueType type) {
return processType(typeHelper, type);
}
@ -485,11 +556,21 @@ class JSClassProcessor {
return false;
}
if (method.hasModifier(ElementModifier.STATIC)) {
return false;
if (method.getName().equals("<init>")) {
return processConstructor(method, callLocation, invoke);
}
var isStatic = method.hasModifier(ElementModifier.STATIC);
if (isStatic) {
switch (method.getOwnerName()) {
case "org.teavm.platform.PlatformQueue":
return false;
}
}
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
if (isStatic) {
return false;
}
MethodReader overridden = getOverriddenMethod(method);
if (overridden != null) {
diagnostics.error(callLocation, "JS final method {{m0}} overrides {{m1}}. "
@ -511,13 +592,18 @@ class JSClassProcessor {
return false;
}
if (method.getAnnotations().get(JSProperty.class.getName()) != null) {
return processProperty(method, callLocation, invoke);
} else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) {
return processIndexer(method, callLocation, invoke);
} else {
return processMethod(method, callLocation, invoke);
var annot = annotationCache.get(method.getReference(), callLocation);
if (annot != null) {
switch (annot.kind) {
case PROPERTY:
return processProperty(method, annot.name, callLocation, invoke);
case INDEXER:
return processIndexer(method, callLocation, invoke);
case METHOD:
return processMethod(method, annot.name, callLocation, invoke);
}
}
return processMethod(method, null, callLocation, invoke);
}
private boolean processJSBodyInvocation(MethodReader method, CallLocation callLocation, InvokeInstruction invoke,
@ -577,16 +663,17 @@ class JSClassProcessor {
return true;
}
private boolean processProperty(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
private boolean processProperty(MethodReader method, String suggestedName, CallLocation callLocation,
InvokeInstruction invoke) {
boolean pure = method.getAnnotations().get(NO_SIDE_EFFECTS) != null;
if (isProperGetter(method)) {
String propertyName = extractSuggestedPropertyName(method);
if (isProperGetter(method, suggestedName)) {
var propertyName = suggestedName;
if (propertyName == null) {
propertyName = method.getName().charAt(0) == 'i' ? cutPrefix(method.getName(), 2)
: cutPrefix(method.getName(), 3);
}
Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
addPropertyGet(propertyName, invoke.getInstance(), result, invoke.getLocation(), pure);
addPropertyGet(propertyName, getCallTarget(invoke), result, invoke.getLocation(), pure);
if (result != null) {
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false,
canBeOnlyJava(invoke.getReceiver()));
@ -594,15 +681,15 @@ class JSClassProcessor {
}
return true;
}
if (isProperSetter(method)) {
String propertyName = extractSuggestedPropertyName(method);
if (isProperSetter(method, suggestedName)) {
var propertyName = suggestedName;
if (propertyName == null) {
propertyName = cutPrefix(method.getName(), 3);
}
var value = invoke.getArguments().get(0);
value = marshaller.wrapArgument(callLocation, value,
method.parameterType(0), types.typeOf(value), false);
addPropertySet(propertyName, invoke.getInstance(), value, invoke.getLocation(), pure);
addPropertySet(propertyName, getCallTarget(invoke), value, invoke.getLocation(), pure);
return true;
}
diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript property "
@ -610,17 +697,11 @@ class JSClassProcessor {
return false;
}
private String extractSuggestedPropertyName(MethodReader method) {
AnnotationReader annot = method.getAnnotations().get(JSProperty.class.getName());
AnnotationValue value = annot.getValue("value");
return value != null ? value.getString() : null;
}
private boolean processIndexer(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
if (isProperGetIndexer(method.getDescriptor())) {
Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
var index = invoke.getArguments().get(0);
addIndexerGet(invoke.getInstance(), marshaller.wrapArgument(callLocation, index,
addIndexerGet(getCallTarget(invoke), marshaller.wrapArgument(callLocation, index,
method.parameterType(0), types.typeOf(index), false), result, invoke.getLocation());
if (result != null) {
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false,
@ -635,7 +716,7 @@ class JSClassProcessor {
var value = invoke.getArguments().get(1);
value = marshaller.wrapArgument(callLocation, value, method.parameterType(1),
types.typeOf(value), false);
addIndexerSet(invoke.getInstance(), index, value, invoke.getLocation());
addIndexerSet(getCallTarget(invoke), index, value, invoke.getLocation());
return true;
}
diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript indexer "
@ -678,17 +759,11 @@ class JSClassProcessor {
return type != JSType.JS && type != JSType.MIXED;
}
private boolean processMethod(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
String name = method.getName();
AnnotationReader methodAnnot = method.getAnnotations().get(JSMethod.class.getName());
if (methodAnnot != null) {
AnnotationValue redefinedMethodName = methodAnnot.getValue("value");
if (redefinedMethodName != null) {
name = redefinedMethodName.getString();
}
private boolean processMethod(MethodReader method, String name, CallLocation callLocation,
InvokeInstruction invoke) {
if (name == null) {
name = method.getName();
}
boolean[] byRefParams = new boolean[method.parameterCount() + 1];
if (!validateSignature(method, callLocation, byRefParams)) {
return false;
@ -700,7 +775,7 @@ class JSClassProcessor {
newInvoke.setType(InvocationType.SPECIAL);
newInvoke.setReceiver(result);
List<Variable> newArguments = new ArrayList<>();
newArguments.add(invoke.getInstance());
newArguments.add(getCallTarget(invoke));
newArguments.add(marshaller.addStringWrap(marshaller.addString(name, invoke.getLocation()),
invoke.getLocation()));
newInvoke.setLocation(invoke.getLocation());
@ -721,6 +796,38 @@ class JSClassProcessor {
return true;
}
private Variable getCallTarget(InvokeInstruction invoke) {
return invoke.getInstance() != null
? invoke.getInstance()
: marshaller.classRef(invoke.getMethod().getClassName(), invoke.getLocation());
}
private boolean processConstructor(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
var byRefParams = new boolean[method.parameterCount() + 1];
if (!validateSignature(method, callLocation, byRefParams)) {
return false;
}
var result = program.variableAt(variableAliases[invoke.getInstance().getIndex()]);
var newInvoke = new InvokeInstruction();
newInvoke.setMethod(JSMethods.construct(method.parameterCount()));
newInvoke.setType(InvocationType.SPECIAL);
newInvoke.setReceiver(result);
var newArguments = new ArrayList<Variable>();
newArguments.add(marshaller.classRef(invoke.getMethod().getClassName(), invoke.getLocation()));
newInvoke.setLocation(invoke.getLocation());
for (int i = 0; i < invoke.getArguments().size(); ++i) {
var arg = invoke.getArguments().get(i);
arg = marshaller.wrapArgument(callLocation, arg,
method.parameterType(i), types.typeOf(arg), byRefParams[i]);
newArguments.add(arg);
}
newInvoke.setArguments(newArguments.toArray(new Variable[0]));
replacement.add(newInvoke);
return true;
}
private void requireJSBody(Diagnostics diagnostics, MethodReader methodToProcess) {
if (!repository.processedMethods.add(methodToProcess.getReference())) {
return;
@ -997,11 +1104,11 @@ class JSClassProcessor {
return null;
}
private boolean isProperGetter(MethodReader method) {
private boolean isProperGetter(MethodReader method, String suggestedName) {
if (method.parameterCount() > 0 || !typeHelper.isSupportedType(method.getResultType())) {
return false;
}
if (extractSuggestedPropertyName(method) != null) {
if (suggestedName != null) {
return true;
}
@ -1013,13 +1120,13 @@ class JSClassProcessor {
return isProperPrefix(method.getName(), "get");
}
private boolean isProperSetter(MethodReader method) {
private boolean isProperSetter(MethodReader method, String suggestedName) {
if (method.parameterCount() != 1 || !typeHelper.isSupportedType(method.parameterType(0))
|| method.getResultType() != ValueType.VOID) {
return false;
}
return extractSuggestedPropertyName(method) != null || isProperPrefix(method.getName(), "set");
return suggestedName != null || isProperPrefix(method.getName(), "set");
}
private boolean isProperPrefix(String name, String prefix) {

View File

@ -0,0 +1,66 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.impl;
import java.util.Arrays;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSProperty;
import org.teavm.model.AnnotationReader;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReader;
class JSImportAnnotationCache extends JSAnnotationCache<JSImportDescriptor> {
JSImportAnnotationCache(ClassReaderSource classes, Diagnostics diagnostics) {
super(classes, diagnostics);
}
@Override
protected JSImportDescriptor take(MethodReader method, CallLocation location) {
var propertyAnnot = method.getAnnotations().get(JSProperty.class.getName());
var indexerAnnot = method.getAnnotations().get(JSIndexer.class.getName());
var methodAnnot = method.getAnnotations().get(JSMethod.class.getName());
var found = false;
for (var annot : Arrays.asList(propertyAnnot, indexerAnnot, methodAnnot)) {
if (annot != null) {
if (!found) {
found = true;
} else {
diagnostics.error(location, "@JSProperty, @JSIndexer and @JSMethod are mutually exclusive "
+ "and can't appear simultaneously on {{m}}", method.getReference());
return null;
}
}
}
if (propertyAnnot != null) {
return new JSImportDescriptor(JSImportKind.PROPERTY, extractValue(propertyAnnot));
}
if (indexerAnnot != null) {
return new JSImportDescriptor(JSImportKind.INDEXER, null);
}
if (methodAnnot != null) {
return new JSImportDescriptor(JSImportKind.METHOD, extractValue(methodAnnot));
}
return null;
}
private String extractValue(AnnotationReader annotation) {
var value = annotation.getValue("value");
return value != null ? value.getString() : null;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.impl;
import java.util.Objects;
class JSImportDescriptor {
final JSImportKind kind;
final String name;
JSImportDescriptor(JSImportKind kind, String name) {
this.kind = kind;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof JSImportDescriptor)) {
return false;
}
var that = (JSImportDescriptor) o;
return kind == that.kind && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(kind, name);
}
}

View File

@ -0,0 +1,22 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.impl;
enum JSImportKind {
PROPERTY,
INDEXER,
METHOD
}

View File

@ -114,15 +114,24 @@ final class JSMethods {
public static final MethodReference FUNCTION_AS_OBJECT = new MethodReference(JS.class, "functionAsObject",
JSObject.class, JSObject.class, JSObject.class);
public static final MethodReference GLOBAL = new MethodReference(JS.class, "global", String.class, JSObject.class);
public static final MethodReference IMPORT_MODULE = new MethodReference(JS.class, "importModule",
String.class, JSObject.class);
public static final ValueType JS_OBJECT = ValueType.object(JSObject.class.getName());
public static final ValueType JS_ARRAY = ValueType.object(JSArray.class.getName());
private static final MethodReference[] INVOKE_METHODS = new MethodReference[13];
private static final MethodReference[] CONSTRUCT_METHODS = new MethodReference[13];
static {
for (int i = 0; i < INVOKE_METHODS.length; ++i) {
ValueType[] signature = new ValueType[i + 3];
var signature = new ValueType[i + 3];
Arrays.fill(signature, JS_OBJECT);
INVOKE_METHODS[i] = new MethodReference(JS.class.getName(), "invoke", signature);
var constructSignature = new ValueType[i + 2];
Arrays.fill(constructSignature, JS_OBJECT);
CONSTRUCT_METHODS[i] = new MethodReference(JS.class.getName(), "construct", constructSignature);
}
}
@ -132,4 +141,8 @@ final class JSMethods {
public static MethodReference invoke(int parameterCount) {
return INVOKE_METHODS[parameterCount];
}
public static MethodReference construct(int parameterCount) {
return CONSTRUCT_METHODS[parameterCount];
}
}

View File

@ -71,21 +71,20 @@ public class JSNativeInjector implements Injector, DependencyPlugin {
}
writer.append(')');
break;
case "instantiate":
case "construct":
if (context.getPrecedence().ordinal() >= Precedence.FUNCTION_CALL.ordinal()) {
writer.append("(");
}
writer.append("new ");
context.writeExpr(context.getArgument(0), Precedence.GROUPING);
renderProperty(context.getArgument(1), context);
writer.append("(");
for (int i = 2; i < context.argumentCount(); ++i) {
if (i > 2) {
writer.append('(');
for (int i = 1; i < context.argumentCount(); ++i) {
if (i > 1) {
writer.append(',').ws();
}
context.writeExpr(context.getArgument(i), Precedence.min());
}
writer.append(")");
writer.append(')');
if (context.getPrecedence().ordinal() >= Precedence.FUNCTION_CALL.ordinal()) {
writer.append(")");
}
@ -152,6 +151,18 @@ public class JSNativeInjector implements Injector, DependencyPlugin {
case "dataToArray":
dataToArray(context, "$rt_objcls");
break;
case "global": {
var cst = (ConstantExpr) context.getArgument(0);
var name = (String) cst.getValue();
writer.appendGlobal(name);
break;
}
case "importModule": {
var cst = (ConstantExpr) context.getArgument(0);
var name = (String) cst.getValue();
writer.appendFunction(context.importModule(name));
break;
}
default:
if (methodRef.getName().startsWith("unwrap")) {
@ -172,7 +183,7 @@ public class JSNativeInjector implements Injector, DependencyPlugin {
public void methodReached(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
case "invoke":
case "instantiate":
case "construct":
case "function":
if (reachedFunctorMethods.add(method.getReference()) && !method.isMissing()) {
for (int i = 0; i < method.getReference().parameterCount(); ++i) {

View File

@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSExport;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
@ -82,6 +83,11 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
}
processor.createJSMethods(cls);
if (cls.hasModifier(ElementModifier.ABSTRACT)
|| cls.getAnnotations().get(JSClass.class.getName()) != null && isJavaScriptClass(cls)) {
return;
}
MethodReference functorMethod = processor.isFunctor(cls.getName());
if (functorMethod != null) {
if (processor.isFunctor(cls.getParent()) != null) {
@ -277,6 +283,18 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
}
}
private boolean isJavaScriptClass(ClassReader cls) {
if (cls.getParent() != null && typeHelper.isJavaScriptClass(cls.getParent())) {
return true;
}
for (var itf : cls.getInterfaces()) {
if (typeHelper.isJavaScriptClass(itf)) {
return true;
}
}
return false;
}
private boolean addInterfaces(ExposedClass exposedCls, ClassReader cls) {
boolean added = false;
for (String ifaceName : cls.getInterfaces()) {

View File

@ -17,6 +17,7 @@ package org.teavm.jso.impl;
import java.util.HashMap;
import java.util.Map;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
@ -43,15 +44,20 @@ class JSTypeHelper {
}
public boolean isJavaScriptImplementation(String className) {
return knownJavaScriptImplementations
.computeIfAbsent(className, k -> examineIfJavaScriptImplementation(className));
return knownJavaScriptImplementations.computeIfAbsent(className, k ->
examineIfJavaScriptImplementation(className));
}
private boolean examineIfJavaScriptClass(String className) {
ClassReader cls = classSource.get(className);
if (cls == null || !(cls.hasModifier(ElementModifier.INTERFACE) || cls.hasModifier(ElementModifier.ABSTRACT))) {
if (cls == null) {
return false;
}
if (!(cls.hasModifier(ElementModifier.INTERFACE) || cls.hasModifier(ElementModifier.ABSTRACT))) {
if (cls.getAnnotations().get(JSClass.class.getName()) == null) {
return false;
}
}
if (cls.getParent() != null) {
if (isJavaScriptClass(cls.getParent())) {
return true;
@ -65,7 +71,7 @@ class JSTypeHelper {
return false;
}
ClassReader cls = classSource.get(className);
if (cls == null) {
if (cls == null || cls.getAnnotations().get(JSClass.class.getName()) != null) {
return false;
}
if (cls.getParent() != null) {

View File

@ -18,7 +18,9 @@ package org.teavm.jso.impl;
import java.util.ArrayList;
import java.util.List;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSModule;
import org.teavm.jso.JSObject;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
@ -553,4 +555,90 @@ class JSValueMarshaller {
replacement.add(nameInsn);
return var;
}
Variable classRef(String className, TextLocation location) {
String name = null;
String module = null;
var cls = classSource.get(className);
if (cls != null) {
name = cls.getSimpleName();
var jsExport = cls.getAnnotations().get(JSClass.class.getName());
if (jsExport != null) {
var nameValue = jsExport.getValue("name");
if (nameValue != null) {
var nameValueString = nameValue.getString();
if (!nameValueString.isEmpty()) {
name = nameValueString;
}
}
}
var jsModule = cls.getAnnotations().get(JSModule.class.getName());
if (jsModule != null) {
module = jsModule.getValue("value").getString();
}
}
if (name == null) {
name = cls.getName().substring(cls.getName().lastIndexOf('.') + 1);
}
return module != null ? moduleRef(module, name, location) : globalRef(name, location);
}
Variable globalRef(String name, TextLocation location) {
var nameInsn = new StringConstantInstruction();
nameInsn.setReceiver(program.createVariable());
nameInsn.setConstant(name);
nameInsn.setLocation(location);
replacement.add(nameInsn);
var invoke = new InvokeInstruction();
invoke.setType(InvocationType.SPECIAL);
invoke.setMethod(JSMethods.GLOBAL);
invoke.setArguments(nameInsn.getReceiver());
invoke.setReceiver(program.createVariable());
invoke.setLocation(location);
replacement.add(invoke);
return invoke.getReceiver();
}
Variable moduleRef(String module, String name, TextLocation location) {
var moduleNameInsn = new StringConstantInstruction();
moduleNameInsn.setReceiver(program.createVariable());
moduleNameInsn.setConstant(module);
moduleNameInsn.setLocation(location);
replacement.add(moduleNameInsn);
var invoke = new InvokeInstruction();
invoke.setType(InvocationType.SPECIAL);
invoke.setMethod(JSMethods.IMPORT_MODULE);
invoke.setArguments(moduleNameInsn.getReceiver());
invoke.setReceiver(program.createVariable());
invoke.setLocation(location);
replacement.add(invoke);
var nameInsn = new StringConstantInstruction();
nameInsn.setReceiver(program.createVariable());
nameInsn.setConstant(name);
nameInsn.setLocation(location);
replacement.add(nameInsn);
var wrapName = new InvokeInstruction();
wrapName.setType(InvocationType.SPECIAL);
wrapName.setMethod(referenceCache.getCached(new MethodReference(JS.class, "wrap",
String.class, JSObject.class)));
wrapName.setReceiver(program.createVariable());
wrapName.setArguments(nameInsn.getReceiver());
wrapName.setLocation(location);
replacement.add(wrapName);
var get = new InvokeInstruction();
get.setType(InvocationType.SPECIAL);
get.setMethod(JSMethods.GET_PURE);
get.setReceiver(program.createVariable());
get.setArguments(invoke.getReceiver(), wrapName.getReceiver());
get.setLocation(location);
replacement.add(get);
return get.getReceiver();
}
}

View File

@ -28,13 +28,13 @@ import org.teavm.jso.core.JSWeakMap;
import org.teavm.jso.core.JSWeakRef;
public final class JSWrapper {
private static final JSWeakMap<JSObject, JSNumber> hashCodes = JSWeakMap.create();
private static final JSWeakMap<JSObject, JSNumber> hashCodes = new JSWeakMap<>();
private static final JSWeakMap<JSObject, JSWeakRef<JSObject>> wrappers = JSWeakRef.isSupported()
? JSWeakMap.create() : null;
? new JSWeakMap<>() : null;
private static final JSMap<JSString, JSWeakRef<JSObject>> stringWrappers = JSWeakRef.isSupported()
? JSMap.create() : null;
? new JSMap<>() : null;
private static final JSMap<JSNumber, JSWeakRef<JSObject>> numberWrappers = JSWeakRef.isSupported()
? JSMap.create() : null;
? new JSMap<>() : null;
private static JSWeakRef<JSObject> undefinedWrapper;
private static final JSFinalizationRegistry stringFinalizationRegistry;
private static final JSFinalizationRegistry numberFinalizationRegistry;
@ -44,10 +44,10 @@ public final class JSWrapper {
static {
stringFinalizationRegistry = stringWrappers != null
? JSFinalizationRegistry.create(token -> stringWrappers.delete((JSString) token))
? new JSFinalizationRegistry(token -> stringWrappers.delete((JSString) token))
: null;
numberFinalizationRegistry = numberWrappers != null
? JSFinalizationRegistry.create(token -> numberWrappers.delete((JSNumber) token))
? new JSFinalizationRegistry(token -> numberWrappers.delete((JSNumber) token))
: null;
}

View File

@ -37,7 +37,7 @@ public final class Client {
private static void sayHello() {
helloButton.setDisabled(true);
thinkingPanel.getStyle().setProperty("display", "");
var xhr = XMLHttpRequest.create();
var xhr = new XMLHttpRequest();
xhr.onComplete(() -> receiveResponse(xhr.getResponseText()));
xhr.open("GET", "hello");
xhr.send();

View File

@ -103,7 +103,7 @@ public final class PromiseExample {
}
private static void runSimplePromise() {
var promise = JSPromise.create((resolve, reject) -> {
new JSPromise<>((resolve, reject) -> {
report("Simple promise execution");
report("Resolving with 'success'");
@ -112,7 +112,7 @@ public final class PromiseExample {
}
private static void runComplexPromise() {
var promise = JSPromise.create((resolve, reject) -> {
new JSPromise<>((resolve, reject) -> {
report("Complex promise execution");
report("Resolving with 'step1'");
@ -155,7 +155,7 @@ public final class PromiseExample {
.flatThen(value -> {
report("Resolved with '" + value + "'");
report("... and resolve with new promise");
return JSPromise.create((resolve, reject) -> {
return new JSPromise<>((resolve, reject) -> {
report("Inner promise");
report("Reject with 'step from inner'");
reject.accept("step from inner");
@ -176,7 +176,7 @@ public final class PromiseExample {
}
private static void runLongRunningPromise(Object lock) {
var promise = JSPromise.create((resolve, reject) -> {
var promise = new JSPromise<>((resolve, reject) -> {
report("Long promise exection");
report("Wait for a while...");
Window.setTimeout(() -> {
@ -193,7 +193,7 @@ public final class PromiseExample {
}
private static void combinePromises(Object lock) throws InterruptedException {
JSArray<JSPromise<String>> promises = JSArray.create(3);
var promises = new JSArray<JSPromise<String>>(3);
report("Start 3 successful promises");
promises.set(0, JSPromise.resolve("success1"));
@ -245,7 +245,7 @@ public final class PromiseExample {
var settledPromises = JSPromise.allSettled(promises);
settledPromises.then(value -> {
report(Integer.toString(value.getLength()) + " promises settled to:");
report(value.getLength() + " promises settled to:");
for (int i = 0; i < value.getLength(); ++i) {
var item = value.get(i);
var msg = "-- Promise " + i + " " + item.getStatus() + " with: ";
@ -313,9 +313,9 @@ public final class PromiseExample {
}
report("Start 3 delayed promises");
promises.set(0, JSPromise.create((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success1"), 200)));
promises.set(1, JSPromise.create((resolve, reject) -> Window.setTimeout(() -> reject.accept("failure1"), 100)));
promises.set(2, JSPromise.create((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success3"), 50)));
promises.set(0, new JSPromise<>((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success1"), 200)));
promises.set(1, new JSPromise<>((resolve, reject) -> Window.setTimeout(() -> reject.accept("failure1"), 100)));
promises.set(2, new JSPromise<>((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success3"), 50)));
anyPromise = JSPromise.race(promises);
anyPromise.then(value -> {
@ -337,9 +337,9 @@ public final class PromiseExample {
}
report("Start 3 delayed promises");
promises.set(0, JSPromise.create((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success1"), 200)));
promises.set(1, JSPromise.create((resolve, reject) -> Window.setTimeout(() -> reject.accept("failure1"), 50)));
promises.set(2, JSPromise.create((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success3"), 100)));
promises.set(0, new JSPromise<>((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success1"), 200)));
promises.set(1, new JSPromise<>((resolve, reject) -> Window.setTimeout(() -> reject.accept("failure1"), 50)));
promises.set(2, new JSPromise<>((resolve, reject) -> Window.setTimeout(() -> resolve.accept("success3"), 100)));
anyPromise = JSPromise.race(promises);
anyPromise.then(value -> {
@ -397,11 +397,11 @@ public final class PromiseExample {
}
report("Pass promise to native method");
handlePromise(JSPromise.create((resolve, reject) -> {
handlePromise(new JSPromise<>((resolve, reject) -> {
resolve.accept(JSString.valueOf("Resolved from Java"));
}));
handlePromise(JSPromise.create((resolve, reject) -> {
handlePromise(new JSPromise<>((resolve, reject) -> {
reject.accept(JSString.valueOf("Rejected from Java"));
}));
}

View File

@ -55,7 +55,7 @@ class Controller(
WorkerType.KOTLIN_JS -> "kjs/software3d.js"
}
workers = (0 until tasks).map { index ->
Worker.create(scriptName).apply {
Worker(scriptName).apply {
postMessage(JSObjects.createWithoutProto<JSMapLike<JSObject>>().apply {
set("type", JSString.valueOf("init"))
set("width", JSNumber.valueOf(width))
@ -118,8 +118,8 @@ class Controller(
private fun displayBuffers(buffers: Array<out ArrayBuffer?>) {
for (y in 0 until height) {
val buffer = buffers[y % buffers.size]!!
val array = Uint8ClampedArray.create(buffer, width * 4 * (y / buffers.size), width * 4)
val imageData = ImageData.create(array, width, 1)
val array = Uint8ClampedArray(buffer, width * 4 * (y / buffers.size), width * 4)
val imageData = ImageData(array, width, 1)
context.putImageData(imageData, 0.0, y.toDouble())
}
}

View File

@ -41,7 +41,7 @@ public final class Storage {
var key = document.getElementById("key").<HTMLInputElement>cast().getValue();
var value = document.getElementById("value").<HTMLInputElement>cast().getValue();
if (key != null && key.length() > 0 && value != null && value.length() > 0) {
if (key != null && !key.isEmpty() && value != null && !value.isEmpty()) {
storage.setItem(key, value);
draw();
}
@ -49,7 +49,7 @@ public final class Storage {
HTMLButtonElement deleteButton = document.getElementById("delete-button").cast();
deleteButton.listenClick(e -> {
String key = document.getElementById("key").<HTMLInputElement>cast().getValue();
if (key != null && key.length() > 0) {
if (key != null && !key.isEmpty()) {
storage.removeItem(key);
draw();
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.test;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
@JSClass
public class ClassWithConstructor implements JSObject {
public ClassWithConstructor(int foo) {
}
public ClassWithConstructor() {
}
@JSProperty
public native int getFoo();
public native String bar();
public static native String staticMethod();
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.jso.test;
import org.teavm.jso.JSClass;
import org.teavm.jso.JSModule;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
@JSClass(name = "ClassWithConstructor")
@JSModule("./testModule.js")
public class ClassWithConstructorInModule implements JSObject {
public ClassWithConstructorInModule(int foo) {
}
public ClassWithConstructorInModule() {
}
@JSProperty
public native int getFoo();
public native String bar();
}

View File

@ -21,6 +21,7 @@ import org.junit.runner.RunWith;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSObject;
import org.teavm.junit.AttachJavaScript;
import org.teavm.junit.EachTestCompiledSeparately;
import org.teavm.junit.OnlyPlatform;
import org.teavm.junit.SkipJVM;
@ -41,6 +42,23 @@ public class ImportClassTest {
assertEquals(42, o.get("bar"));
}
@Test
@AttachJavaScript("org/teavm/jso/test/classWithConstructor.js")
public void constructor() {
var o = new ClassWithConstructor();
assertEquals(99, o.getFoo());
assertEquals("bar called", o.bar());
o = new ClassWithConstructor(23);
assertEquals(23, o.getFoo());
}
@Test
@AttachJavaScript("org/teavm/jso/test/classWithConstructor.js")
public void staticMethod() {
assertEquals("static method called", ClassWithConstructor.staticMethod());
}
@JSBody(script = "return {};")
private static native O create();

View File

@ -56,6 +56,18 @@ public class ImportModuleTest {
assertEquals(23, runTestFunction());
}
@Test
@JsModuleTest
@ServeJS(from = "org/teavm/jso/test/classWithConstructorInModule.js", as = "testModule.js")
public void classConstructor() {
var o = new ClassWithConstructorInModule();
assertEquals(99, o.getFoo());
assertEquals("bar called", o.bar());
o = new ClassWithConstructorInModule(23);
assertEquals(23, o.getFoo());
}
@JSBody(
script = "return testModule.foo();",
imports = @JSBodyImport(alias = "testModule", fromModule = "./testModule.js")

View File

@ -0,0 +1,33 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ClassWithConstructor {
constructor(foo) {
this._foo = foo || 99;
}
get foo() {
return this._foo;
}
bar() {
return "bar called";
}
static staticMethod() {
return "static method called";
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export class ClassWithConstructor {
constructor(foo) {
this._foo = foo || 99;
}
get foo() {
return this._foo;
}
bar() {
return "bar called";
}
}

View File

@ -34,14 +34,14 @@ import org.teavm.jso.typedarrays.Int8Array;
import org.teavm.model.MethodReference;
public final class Deobfuscator {
private static final JSRegExp FRAME_PATTERN = JSRegExp.create(""
private static final JSRegExp FRAME_PATTERN = new JSRegExp(""
+ "(^ +at ([^(]+) *\\((.+):([0-9]+):([0-9]+)\\) *$)|"
+ "(^([^@]*)@(.+):([0-9]+):([0-9]+)$)");
private DebugInformation debugInformation;
private String classesFileName;
public Deobfuscator(ArrayBuffer buffer, String classesFileName) throws IOException {
Int8Array array = Int8Array.create(buffer);
var array = new Int8Array(buffer);
debugInformation = DebugInformation.read(new Int8ArrayInputStream(array));
this.classesFileName = classesFileName;
}
@ -51,7 +51,7 @@ public final class Deobfuscator {
}
private static void loadDeobfuscator(String fileName, String classesFileName) {
XMLHttpRequest xhr = XMLHttpRequest.create();
var xhr = new XMLHttpRequest();
xhr.setResponseType("arraybuffer");
xhr.onComplete(() -> {
installDeobfuscator(xhr.getResponse().cast(), classesFileName);