Adds support of native JavaScript interaction

This commit is contained in:
konsoletyper 2014-02-06 17:51:51 +04:00
parent b621b0524b
commit ae2e669ec3
14 changed files with 634 additions and 164 deletions

View File

@ -422,7 +422,7 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
}
public static TString valueOf(TObject obj) {
return obj != null ? obj.toString0() : TString.wrap("null");
return obj != null ? TString.wrap(obj.toString()) : TString.wrap("null");
}
public static TString valueOf(char[] data) {
@ -450,19 +450,19 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
}
public static TString valueOf(int i) {
return new TStringBuilder().append(i).toString0();
return TString.wrap(new TStringBuilder().append(i).toString());
}
public static TString valueOf(long l) {
return new TStringBuilder().append(l).toString0();
return TString.wrap(new TStringBuilder().append(l).toString());
}
public static TString valueOf(float f) {
return new TStringBuilder().append(f).toString0();
return TString.wrap(new TStringBuilder().append(f).toString());
}
public static TString valueOf(double d) {
return new TStringBuilder().append(d).toString0();
return TString.wrap(new TStringBuilder().append(d).toString());
}
@Override

View File

@ -17,11 +17,9 @@ package org.teavm.dependency;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.*;
import org.teavm.common.ConcurrentCachedMapper;
import org.teavm.common.FiniteExecutor;
import org.teavm.common.Mapper;
import org.teavm.common.SimpleFiniteExecutor;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.teavm.common.*;
import org.teavm.common.ConcurrentCachedMapper.KeyListener;
import org.teavm.model.*;

View File

@ -44,9 +44,9 @@ public class JavascriptBuilder {
private Map<String, String> exportedClasses = new HashMap<>();
JavascriptBuilder(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
this.classSource = classSource;
this.classSource = new JavascriptProcessedClassSource(classSource);
this.classLoader = classLoader;
dependencyChecker = new DependencyChecker(classSource, classLoader, executor);
dependencyChecker = new DependencyChecker(this.classSource, classLoader, executor);
this.executor = executor;
}

View File

@ -15,12 +15,10 @@
*/
package org.teavm.javascript;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.javascript.ni.JSObject;
import java.util.*;
import org.teavm.javascript.ni.*;
import org.teavm.model.*;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.*;
/**
*
@ -29,6 +27,8 @@ import org.teavm.model.instructions.InvokeInstruction;
class JavascriptNativeProcessor {
private ClassHolderSource classSource;
private Map<String, Boolean> knownJavaScriptClasses = new HashMap<>();
private Program program;
private List<Instruction> replacement = new ArrayList<>();
public JavascriptNativeProcessor(ClassHolderSource classSource) {
this.classSource = classSource;
@ -36,6 +36,7 @@ class JavascriptNativeProcessor {
}
public void processProgram(Program program) {
this.program = program;
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
List<Instruction> instructions = block.getInstructions();
@ -44,10 +45,219 @@ class JavascriptNativeProcessor {
if (!(insn instanceof InvokeInstruction)) {
continue;
}
InvokeInstruction invoke = (InvokeInstruction)insn;
if (!isJavaScriptClass(invoke.getMethod().getClassName())) {
continue;
}
replacement.clear();
MethodHolder method = getMethod(invoke.getMethod());
if (method.getAnnotations().get(JSProperty.class.getName()) != null) {
if (isProperGetter(method.getDescriptor())) {
String 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);
if (result != null) {
result = unwrap(result, method.getResultType());
copyVar(result, invoke.getReceiver());
}
} else if (isProperSetter(method.getDescriptor())) {
Variable wrapped = wrap(invoke.getArguments().get(3), method.parameterType(2));
addPropertySet(cutPrefix(method.getName(), 3), invoke.getArguments().get(0), wrapped);
} else {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript property declaration");
}
} else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) {
if (isProperGetIndexer(method.getDescriptor())) {
Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
addIndexerGet(invoke.getInstance(), wrap(invoke.getArguments().get(0),
method.parameterType(0)), result);
if (result != null) {
result = unwrap(result, method.getResultType());
copyVar(result, invoke.getReceiver());
}
} else if (isProperSetIndexer(method.getDescriptor())) {
Variable index = wrap(invoke.getArguments().get(0), method.parameterType(0));
Variable value = wrap(invoke.getArguments().get(1), method.parameterType(1));
addIndexerSet(invoke.getInstance(), index, value);
} else {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript indexer declaration");
}
} else {
if (!isSupportedType(method.getResultType())) {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript method declaration");
}
for (ValueType arg : method.getParameterTypes()) {
if (!isSupportedType(arg)) {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript method declaration");
}
}
Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
InvokeInstruction newInvoke = new InvokeInstruction();
ValueType[] signature = new ValueType[method.parameterCount() + 3];
Arrays.fill(signature, ValueType.object(JSObject.class.getName()));
newInvoke.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor("invoke",
signature)));
newInvoke.setType(InvocationType.SPECIAL);
newInvoke.setReceiver(result);
newInvoke.getArguments().add(invoke.getInstance());
newInvoke.getArguments().add(addStringWrap(addString(method.getName())));
for (int k = 0; k < invoke.getArguments().size(); ++k) {
Variable arg = wrap(invoke.getArguments().get(k), method.parameterType(k));
newInvoke.getArguments().add(arg);
}
replacement.add(newInvoke);
if (result != null) {
result = unwrap(result, method.getResultType());
copyVar(result, invoke.getReceiver());
}
}
block.getInstructions().set(j, replacement.get(0));
block.getInstructions().addAll(j + 1, replacement.subList(1, replacement.size()));
j += replacement.size() - 1;
}
}
}
private void addPropertyGet(String propertyName, Variable instance, Variable receiver) {
Variable nameVar = addStringWrap(addString(propertyName));
InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor("get",
ValueType.object(JSObject.class.getName()), ValueType.object(JSObject.class.getName()),
ValueType.object(JSObject.class.getName()))));
insn.setReceiver(receiver);
insn.getArguments().add(instance);
insn.getArguments().add(nameVar);
replacement.add(insn);
}
private void addPropertySet(String propertyName, Variable instance, Variable value) {
Variable nameVar = addStringWrap(addString(propertyName));
InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor("set",
ValueType.object(JSObject.class.getName()), ValueType.object(JSObject.class.getName()),
ValueType.VOID)));
insn.getArguments().add(instance);
insn.getArguments().add(nameVar);
insn.getArguments().add(value);
replacement.add(insn);
}
private void addIndexerGet(Variable array, Variable index, Variable receiver) {
InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor("get",
ValueType.object(JSObject.class.getName()), ValueType.object(JSObject.class.getName()),
ValueType.object(JSObject.class.getName()))));
insn.setReceiver(receiver);
insn.getArguments().add(array);
insn.getArguments().add(index);
replacement.add(insn);
}
private void addIndexerSet(Variable array, Variable index, Variable value) {
InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor("set",
ValueType.object(JSObject.class.getName()), ValueType.object(JSObject.class.getName()),
ValueType.object(JSObject.class.getName()), ValueType.VOID)));
insn.getArguments().add(array);
insn.getArguments().add(index);
insn.getArguments().add(value);
replacement.add(insn);
}
private void copyVar(Variable a, Variable b) {
AssignInstruction insn = new AssignInstruction();
insn.setAssignee(a);
insn.setReceiver(b);
replacement.add(insn);
}
private Variable addStringWrap(Variable var) {
return wrap(var, ValueType.object("java.lang.String"));
}
private Variable addString(String str) {
Variable var = program.createVariable();
StringConstantInstruction nameInsn = new StringConstantInstruction();
nameInsn.setReceiver(var);
nameInsn.setConstant(str);
replacement.add(nameInsn);
return var;
}
private Variable unwrap(Variable var, ValueType type) {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive)type).getKind()) {
case BOOLEAN:
return unwrap(var, "unwrapBoolean", ValueType.BOOLEAN);
case BYTE:
return unwrap(var, "unwrapByte", ValueType.BYTE);
case SHORT:
return unwrap(var, "unwrapShort", ValueType.SHORT);
case INTEGER:
return unwrap(var, "unwrapShort", ValueType.INTEGER);
case CHARACTER:
return unwrap(var, "unwrapCharacter", ValueType.CHARACTER);
case DOUBLE:
return unwrap(var, "unwrapDouble", ValueType.DOUBLE);
case FLOAT:
return unwrap(var, "unwrapFloat", ValueType.FLOAT);
case LONG:
break;
}
} else if (type instanceof ValueType.Object) {
String className = ((ValueType.Object)type).getClassName();
if (className.equals(JSObject.class.getName())) {
return var;
} else if (className.equals("java.lang.String")) {
return unwrap(var, "unwrapString", ValueType.object("java.lang.String"));
} else {
Variable result = program.createVariable();
CastInstruction castInsn = new CastInstruction();
castInsn.setReceiver(result);
castInsn.setValue(var);
castInsn.setTargetType(type);
replacement.add(castInsn);
return result;
}
}
throw new IllegalArgumentException("Unsupported type: " + type);
}
private Variable unwrap(Variable var, String methodName, ValueType resultType) {
Variable result = program.createVariable();
InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor(methodName,
resultType)));
insn.getArguments().add(var);
insn.setReceiver(result);
insn.setType(InvocationType.SPECIAL);
replacement.add(insn);
return result;
}
private Variable wrap(Variable var, ValueType type) {
if (type instanceof ValueType.Object) {
String className = ((ValueType.Object)type).getClassName();
if (!className.equals("java.lang.String")) {
return var;
}
}
Variable result = program.createVariable();
InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor("wrap", type,
ValueType.object(JSObject.class.getName()))));
insn.getArguments().add(var);
insn.setReceiver(result);
insn.setType(InvocationType.SPECIAL);
replacement.add(insn);
return result;
}
private boolean isJavaScriptClass(String className) {
Boolean known = knownJavaScriptClasses.get(className);
if (known == null) {
@ -69,4 +279,89 @@ class JavascriptNativeProcessor {
}
return false;
}
private MethodHolder getMethod(MethodReference ref) {
ClassHolder cls = classSource.getClassHolder(ref.getClassName());
MethodHolder method = cls.getMethod(ref.getDescriptor());
if (method != null) {
return method;
}
for (String iface : cls.getInterfaces()) {
method = getMethod(new MethodReference(iface, ref.getDescriptor()));
if (method != null) {
return method;
}
}
return null;
}
private boolean isProperGetter(MethodDescriptor desc) {
if (desc.parameterCount() > 0 || !isSupportedType(desc.getResultType())) {
return false;
}
if (desc.getResultType().equals(ValueType.BOOLEAN)) {
if (isProperPrefix(desc.getName(), "is")) {
return true;
}
}
return isProperPrefix(desc.getName(), "get");
}
private boolean isProperSetter(MethodDescriptor desc) {
if (desc.parameterCount() != 1 || !isSupportedType(desc.parameterType(0)) ||
desc.getResultType() != ValueType.VOID) {
return false;
}
return isProperPrefix(desc.getName(), "set");
}
private boolean isProperPrefix(String name, String prefix) {
if (!name.startsWith(prefix) || name.length() == prefix.length()) {
return false;
}
char c = name.charAt(prefix.length());
return Character.isUpperCase(c);
}
private boolean isProperGetIndexer(MethodDescriptor desc) {
return desc.parameterCount() == 1 && isSupportedType(desc.parameterType(0)) &&
isSupportedType(desc.getResultType());
}
private boolean isProperSetIndexer(MethodDescriptor desc) {
return desc.parameterCount() == 2 && isSupportedType(desc.parameterType(0)) &&
isSupportedType(desc.parameterType(0)) && desc.getResultType() == ValueType.VOID;
}
private String cutPrefix(String name, int prefixLength) {
if (name.length() == prefixLength + 1) {
return name.substring(prefixLength).toLowerCase();
}
char c = name.charAt(prefixLength + 1);
if (Character.isUpperCase(c)) {
return name.substring(prefixLength);
}
return Character.toLowerCase(name.charAt(prefixLength)) + name.substring(prefixLength + 1);
}
private boolean isSupportedType(ValueType type) {
if (type == ValueType.VOID) {
return false;
}
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive)type).getKind()) {
case LONG:
return false;
default:
return true;
}
} else if (type instanceof ValueType.Array) {
return isSupportedType(((ValueType.Array)type).getItemType());
} else if (type instanceof ValueType.Object) {
String typeName = ((ValueType.Object)type).getClassName();
return typeName.equals("java.lang.String") || isJavaScriptClass(typeName);
} else {
return false;
}
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2014 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.javascript;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource;
import org.teavm.model.MethodHolder;
/**
*
* @author Alexey Andreev
*/
public class JavascriptProcessedClassSource implements ClassHolderSource {
private ClassHolderSource innerSource;
public JavascriptProcessedClassSource(ClassHolderSource innerSource) {
this.innerSource = innerSource;
}
@Override
public ClassHolder getClassHolder(String name) {
ClassHolder cls = innerSource.getClassHolder(name);
if (cls != null) {
transformClass(cls);
}
return cls;
}
private void transformClass(ClassHolder cls) {
JavascriptNativeProcessor processor = new JavascriptNativeProcessor(innerSource);
for (MethodHolder method : cls.getMethods()) {
if (method.getProgram() != null) {
processor.processProgram(method.getProgram());
}
}
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 2014 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.javascript.ni;
import java.util.Iterator;
/**
*
* @author Alexey Andreev
*/
public final class JS {
private JS() {
}
public static JSType getType(JSObject obj) {
switch (unwrapString(getTypeName(obj))) {
case "boolean":
return JSType.OBJECT;
case "number":
return JSType.NUMBER;
case "string":
return JSType.STRING;
case "function":
return JSType.FUNCTION;
case "object":
return JSType.OBJECT;
case "undefined":
return JSType.UNDEFINED;
}
throw new AssertionError("Unexpected type");
}
public static native <T extends JSObject> JSArray<T> createArray(int size);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject getTypeName(JSObject obj);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject getGlobal();
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject wrap(String str);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject wrap(char c);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject wrap(int num);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject wrap(float num);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject wrap(double num);
public static <T extends JSObject> JSArray<T> wrap(T[] array) {
JSArray<T> result = createArray(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, array[i]);
}
return result;
}
public static <T extends JSObject> JSArray<JSArray<T>> wrap(T[][] array) {
JSArray<JSArray<T>> result = createArray(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, wrap(array[i]));
}
return result;
}
public static <T extends JSObject> JSArray<JSArray<JSArray<T>>> wrap(T[][][] array) {
JSArray<JSArray<JSArray<T>>> result = createArray(array.length);
for (int i = 0; i < array.length; ++i) {
result.set(i, wrap(array[i]));
}
return result;
}
@GeneratedBy(JSNativeGenerator.class)
public static native boolean unwrapBoolean(JSObject obj);
public static byte unwrapByte(JSObject obj) {
return (byte)unwrapInt(obj);
}
public static short unwrapShort(JSObject obj) {
return (short)unwrapInt(obj);
}
@GeneratedBy(JSNativeGenerator.class)
public static native int unwrapInt(JSObject obj);
@GeneratedBy(JSNativeGenerator.class)
public static native float unwrapFloat(JSObject obj);
@GeneratedBy(JSNativeGenerator.class)
public static native double unwrapDouble(JSObject obj);
@GeneratedBy(JSNativeGenerator.class)
public static native String unwrapString(JSObject obj);
@GeneratedBy(JSNativeGenerator.class)
public static native char unwrapCharacter(JSObject obj);
@GeneratedBy(JSNativeGenerator.class)
public static native boolean isUndefined(JSObject obj);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
JSObject d);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
JSObject d, JSObject e);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
JSObject d, JSObject e, JSObject f);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
JSObject d, JSObject e, JSObject f, JSObject g);
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
JSObject d, JSObject e, JSObject f, JSObject g, JSObject h);
public static <T extends JSObject> Iterable<T> iterate(final JSArray<T> array) {
return new Iterable<T>() {
@Override public Iterator<T> iterator() {
return new Iterator<T>() {
int index = 0;
@Override public boolean hasNext() {
return index < array.getLength();
}
@Override public T next() {
return array.get(index++);
}
@Override public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
@GeneratedBy(JSNativeGenerator.class)
public static native JSObject get(JSObject instance, JSObject index);
@GeneratedBy(JSNativeGenerator.class)
public static native void set(JSObject instance, JSObject index, JSObject obj);
}

View File

@ -19,12 +19,13 @@ package org.teavm.javascript.ni;
*
* @author Alexey Andreev
*/
public interface JSArray<T extends JSObject> extends JSObject, Iterable<T> {
public interface JSArray<T extends JSObject> extends JSObject {
@JSProperty
int getLength();
@Override
@JSIndexer
T get(int index);
<S extends T> JSArray<S> cast();
@JSIndexer
void set(int index, T value);
}

View File

@ -24,7 +24,7 @@ public interface JSFunction extends JSObject {
int getLength();
@JSProperty
JSString getName();
String getName();
JSObject call(JSObject thisArg);

View File

@ -15,10 +15,16 @@
*/
package org.teavm.javascript.ni;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Alexey Andreev
*/
public interface JSString extends JSObject {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JSIndexer {
}

View File

@ -24,7 +24,7 @@ import org.teavm.model.MethodReference;
*
* @author Alexey Andreev
*/
public class JSRootNativeGenerator implements Generator {
public class JSNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
throws IOException {
@ -42,17 +42,53 @@ public class JSRootNativeGenerator implements Generator {
writer.append("return ").append(context.getParameterName(1)).append(";").softNewLine();
}
break;
case "get":
writer.append("return ").append(context.getParameterName(1)).append("[")
.append(context.getParameterName(2)).append("];").softNewLine();
break;
case "set":
writer.append(context.getParameterName(1)).append("[").append(context.getParameterName(2))
.append("] = ").append(context.getParameterName(3)).softNewLine();
break;
case "invoke":
generateInvoke(context, writer, methodRef.parameterCount() - 2);
break;
case "isUndefined":
writer.append("return ").append(context.getParameterName(1)).append(" === undefined;");
break;
default:
if (methodRef.getName().startsWith("unwrap")) {
if (methodRef.getDescriptor().getResultType().isObject("java.lang.String")) {
writer.append("return $rt_str(").append(context.getParameterName(1)).append(");")
.softNewLine();
} else {
writer.append("return ").append(context.getParameterName(1)).append(";").softNewLine();
}
}
break;
}
}
private void generateWrapString(GeneratorContext context, SourceWriter writer) throws IOException {
FieldReference charsField = new FieldReference("java.lang.String", "characters");
writer.append("var result = \"\";").softNewLine();
writer.append("var data = ").append(context.getParameterName(1))
writer.append("var data = ").append(context.getParameterName(1)).append('.')
.appendField(charsField).append(".data;").softNewLine();
writer.append("for (var i = 0; i < data.length; i = (i + 1) | 0) {").indent().softNewLine();
writer.append("result += String.fromCharCode(data[i]);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return result;").softNewLine();
}
private void generateInvoke(GeneratorContext context, SourceWriter writer, int argNum) throws IOException {
writer.append("return ").append(context.getParameterName(1)).append("[")
.append(context.getParameterName(2)).append("](");
for (int i = 0; i < argNum; ++i) {
if (i > 0) {
writer.append(",").ws();
}
writer.append(context.getParameterName(i + 3));
}
writer.append(");").softNewLine();
}
}

View File

@ -20,78 +20,6 @@ package org.teavm.javascript.ni;
* @author Alexey Andreev
*/
public interface JSObject {
@JSProperty
JSObject getPrototype();
JSObject get(String name);
void set(String name, JSObject obj);
JSObject get(JSString name);
void set(JSString name, JSObject obj);
JSObject get(int index);
void set(int index, JSObject obj);
JSObject invoke(String method);
JSObject invoke(String method, JSObject a);
JSObject invoke(String method, JSObject a, JSObject b);
JSObject invoke(String method, JSObject a, JSObject b, JSObject c);
JSObject invoke(String method, JSObject a, JSObject b, JSObject c, JSObject d);
JSObject invoke(String method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e);
JSObject invoke(String method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f);
JSObject invoke(String method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f, JSObject g);
JSObject invoke(String method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f,
JSObject g, JSObject h);
JSObject invoke(JSString method);
JSObject invoke(JSString method, JSObject a);
JSObject invoke(JSString method, JSObject a, JSObject b);
JSObject invoke(JSString method, JSObject a, JSObject b, JSObject c);
JSObject invoke(JSString method, JSObject a, JSObject b, JSObject c, JSObject d);
JSObject invoke(JSString method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e);
JSObject invoke(JSString method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f);
JSObject invoke(JSString method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f,
JSObject g);
JSObject invoke(JSString method, JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f,
JSObject g, JSObject h);
@JSProperty
boolean hasOwnProperty(String property);
@JSProperty
boolean hasOwnProperty(JSString property);
boolean asBoolean();
int asInteger();
double asNumber();
String asString();
boolean isNull();
boolean isUndefined();
@JSMethod("toString")
JSString toJSString();
@Override
String toString();
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2014 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.javascript.ni;
/**
*
* @author Alexey Andreev
*/
public final class JSRoot {
private JSRoot() {
}
public static JSType getType(JSObject obj) {
switch (getTypeName(obj).asString()) {
case "boolean":
return JSType.OBJECT;
case "number":
return JSType.NUMBER;
case "string":
return JSType.STRING;
case "function":
return JSType.FUNCTION;
case "object":
return JSType.OBJECT;
case "undefined":
return JSType.UNDEFINED;
}
throw new AssertionError("Unexpected type");
}
@GeneratedBy(JSRootNativeGenerator.class)
public static native JSString getTypeName(JSObject obj);
@GeneratedBy(JSRootNativeGenerator.class)
public static native JSObject getGlobal();
@GeneratedBy(JSRootNativeGenerator.class)
public static native JSString wrap(String str);
@GeneratedBy(JSRootNativeGenerator.class)
public static native JSNumber wrap(int num);
@GeneratedBy(JSRootNativeGenerator.class)
public static native JSNumber wrap(float num);
@GeneratedBy(JSRootNativeGenerator.class)
public static native JSNumber wrap(double num);
}

View File

@ -23,6 +23,19 @@
</parent>
<artifactId>teavm-samples</artifactId>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>

View File

@ -15,22 +15,48 @@
*/
package org.teavm.samples;
import org.teavm.dom.core.Document;
import org.teavm.dom.core.Element;
import org.teavm.dom.core.Window;
import org.teavm.javascript.ni.JS;
/**
*
* @author Alexey Andreev
*/
public class HelloWorld {
private static Window window;
private static Document document;
private static Element body;
public static void main(String[] args) {
System.out.println("Hello, world!");
System.out.println("Here is the Fibonacci sequence:");
window = (Window)JS.getGlobal();
document = window.getDocument();
body = document.getDocumentElement().getElementsByTagName("body").item(0);
println("Hello, world!");
println("Here is the Fibonacci sequence:");
long a = 0;
long b = 1;
for (int i = 0; i < 70; ++i) {
System.out.println(a);
println(a);
long c = a + b;
a = b;
b = c;
}
System.out.println("And so on...");
println("And so on...");
}
private static void println(Object obj) {
Element elem = document.createElement("div");
elem.appendChild(document.createTextNode(String.valueOf(obj)));
body.appendChild(elem);
}
private static void println(long val) {
Element elem = document.createElement("div");
elem.appendChild(document.createTextNode(String.valueOf(val)));
body.appendChild(elem);
}
}