mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 08:34:11 -08:00
Add emitter. Refactor metadata generator. Fix bugs in timezone
formatting and parsing
This commit is contained in:
parent
bfd97bcae7
commit
e7a88d087c
|
@ -230,8 +230,8 @@ public abstract class TDateFormat extends TFormat {
|
||||||
public TDate parse(String string) throws TParseException {
|
public TDate parse(String string) throws TParseException {
|
||||||
TParsePosition position = new TParsePosition(0);
|
TParsePosition position = new TParsePosition(0);
|
||||||
TDate date = parse(string, position);
|
TDate date = parse(string, position);
|
||||||
if (position.getIndex() == 0) {
|
if (position.getErrorIndex() > 0) {
|
||||||
throw new TParseException("Unparseable date" + string, position.getErrorIndex());
|
throw new TParseException("Unparseable date: " + string, position.getErrorIndex());
|
||||||
}
|
}
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,6 +400,7 @@ abstract class TDateFormatElement {
|
||||||
if (position.getIndex() + 1 < text.length()) {
|
if (position.getIndex() + 1 < text.length()) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
prepareTrie();
|
||||||
TTimeZone tz = match(searchTrie, text, position);
|
TTimeZone tz = match(searchTrie, text, position);
|
||||||
if (tz != null) {
|
if (tz != null) {
|
||||||
date.setTimeZone(tz);
|
date.setTimeZone(tz);
|
||||||
|
@ -415,12 +416,11 @@ abstract class TDateFormatElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TTimeZone match(TrieNode node, String text, TParsePosition position) {
|
public TTimeZone match(TrieNode node, String text, TParsePosition position) {
|
||||||
prepareTrie();
|
|
||||||
int start = position.getIndex();
|
int start = position.getIndex();
|
||||||
int index = start;
|
int index = start;
|
||||||
int lastMatch = start;
|
int lastMatch = start;
|
||||||
TTimeZone tz = null;
|
TTimeZone tz = null;
|
||||||
while (node.childNodes.length > 0) {
|
while (node.childNodes != null && node.childNodes.length > 0) {
|
||||||
if (node.tz != null) {
|
if (node.tz != null) {
|
||||||
lastMatch = index;
|
lastMatch = index;
|
||||||
tz = node.tz;
|
tz = node.tz;
|
||||||
|
@ -432,7 +432,11 @@ abstract class TDateFormatElement {
|
||||||
if (next < 0) {
|
if (next < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
node = node.childNodes[index];
|
node = node.childNodes[next];
|
||||||
|
}
|
||||||
|
if (node.tz != null) {
|
||||||
|
lastMatch = index;
|
||||||
|
tz = node.tz;
|
||||||
}
|
}
|
||||||
position.setIndex(lastMatch);
|
position.setIndex(lastMatch);
|
||||||
return tz;
|
return tz;
|
||||||
|
@ -459,6 +463,7 @@ abstract class TDateFormatElement {
|
||||||
TTimeZone tz = TTimeZone.getTimeZone(tzId);
|
TTimeZone tz = TTimeZone.getTimeZone(tzId);
|
||||||
builder.add(tz.getID(), tz);
|
builder.add(tz.getID(), tz);
|
||||||
}
|
}
|
||||||
|
idSearchTrie = builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,6 +490,7 @@ abstract class TDateFormatElement {
|
||||||
position.setErrorIndex(index);
|
position.setErrorIndex(index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
++index;
|
||||||
|
|
||||||
if (index + 2 > text.length() || !Character.isDigit(text.charAt(index)) ||
|
if (index + 2 > text.length() || !Character.isDigit(text.charAt(index)) ||
|
||||||
!Character.isDigit(text.charAt(index + 1))) {
|
!Character.isDigit(text.charAt(index + 1))) {
|
||||||
|
@ -511,10 +517,9 @@ abstract class TDateFormatElement {
|
||||||
TrieNodeBuilder root = new TrieNodeBuilder();
|
TrieNodeBuilder root = new TrieNodeBuilder();
|
||||||
|
|
||||||
public void add(String text, TTimeZone tz) {
|
public void add(String text, TTimeZone tz) {
|
||||||
int index = 0;
|
|
||||||
TrieNodeBuilder node = root;
|
TrieNodeBuilder node = root;
|
||||||
while (index < text.length()) {
|
for (int i = 0; i < text.length(); ++i) {
|
||||||
char c = Character.toLowerCase(text.charAt(index));
|
char c = Character.toLowerCase(text.charAt(i));
|
||||||
while (node.ch != c) {
|
while (node.ch != c) {
|
||||||
if (node.ch == '\0') {
|
if (node.ch == '\0') {
|
||||||
node.ch = c;
|
node.ch = c;
|
||||||
|
@ -537,12 +542,15 @@ abstract class TDateFormatElement {
|
||||||
|
|
||||||
TrieNode build(TrieNodeBuilder builder) {
|
TrieNode build(TrieNodeBuilder builder) {
|
||||||
TrieNode node = new TrieNode();
|
TrieNode node = new TrieNode();
|
||||||
|
if (builder == null) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
node.tz = builder.tz;
|
node.tz = builder.tz;
|
||||||
List<TrieNodeBuilder> builders = new ArrayList<>();
|
List<TrieNodeBuilder> builders = new ArrayList<>();
|
||||||
TrieNodeBuilder tmp = builder;
|
TrieNodeBuilder tmp = builder;
|
||||||
while (tmp.ch != '\0') {
|
while (tmp.ch != '\0') {
|
||||||
builders.add(builder);
|
builders.add(tmp);
|
||||||
builder = builder.sibling;
|
tmp = tmp.sibling;
|
||||||
}
|
}
|
||||||
Collections.sort(builders, new Comparator<TrieNodeBuilder>() {
|
Collections.sort(builders, new Comparator<TrieNodeBuilder>() {
|
||||||
@Override public int compare(TrieNodeBuilder o1, TrieNodeBuilder o2) {
|
@Override public int compare(TrieNodeBuilder o1, TrieNodeBuilder o2) {
|
||||||
|
@ -553,7 +561,7 @@ abstract class TDateFormatElement {
|
||||||
node.childNodes = new TrieNode[builders.size()];
|
node.childNodes = new TrieNode[builders.size()];
|
||||||
for (int i = 0; i < node.chars.length; ++i) {
|
for (int i = 0; i < node.chars.length; ++i) {
|
||||||
node.chars[i] = builders.get(i).ch;
|
node.chars[i] = builders.get(i).ch;
|
||||||
node.childNodes[i] = build(builders.get(i));
|
node.childNodes[i] = build(builders.get(i).next);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,6 +139,12 @@ public class MethodReference {
|
||||||
return reprCache;
|
return reprCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MethodReference parse(String string) {
|
||||||
|
int index = string.lastIndexOf('.');
|
||||||
|
String className = string.substring(0, index);
|
||||||
|
return new MethodReference(className, MethodDescriptor.parse(string.substring(index + 1)));
|
||||||
|
}
|
||||||
|
|
||||||
public String signatureToString() {
|
public String signatureToString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append('(');
|
sb.append('(');
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.model.emit;
|
||||||
|
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public abstract class ForkEmitter {
|
||||||
|
public abstract void setThen(BasicBlock block);
|
||||||
|
|
||||||
|
public abstract void setElse(BasicBlock block);
|
||||||
|
|
||||||
|
public ForkEmitter and(BasicBlock block, final ForkEmitter other) {
|
||||||
|
setThen(block);
|
||||||
|
return new ForkEmitter() {
|
||||||
|
@Override public void setThen(BasicBlock block) {
|
||||||
|
other.setThen(block);
|
||||||
|
}
|
||||||
|
@Override public void setElse(BasicBlock block) {
|
||||||
|
ForkEmitter.this.setElse(block);
|
||||||
|
other.setElse(block);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForkEmitter or(BasicBlock block, final ForkEmitter other) {
|
||||||
|
setElse(block);
|
||||||
|
return new ForkEmitter() {
|
||||||
|
@Override public void setThen(BasicBlock block) {
|
||||||
|
ForkEmitter.this.setThen(block);
|
||||||
|
other.setThen(block);
|
||||||
|
}
|
||||||
|
@Override public void setElse(BasicBlock block) {
|
||||||
|
other.setElse(block);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForkEmitter not() {
|
||||||
|
return new ForkEmitter() {
|
||||||
|
@Override public void setThen(BasicBlock block) {
|
||||||
|
ForkEmitter.this.setElse(block);
|
||||||
|
}
|
||||||
|
@Override public void setElse(BasicBlock block) {
|
||||||
|
ForkEmitter.this.setThen(block);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,217 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.model.emit;
|
||||||
|
|
||||||
|
import org.teavm.model.*;
|
||||||
|
import org.teavm.model.instructions.ConstructInstruction;
|
||||||
|
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.JumpInstruction;
|
||||||
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public final class ProgramEmitter {
|
||||||
|
private Program program;
|
||||||
|
private BasicBlock block;
|
||||||
|
private InstructionLocation currentLocation;
|
||||||
|
|
||||||
|
private ProgramEmitter(Program program, BasicBlock block) {
|
||||||
|
this.program = program;
|
||||||
|
this.block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Program getProgram() {
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicBlock getBlock() {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlock(BasicBlock block) {
|
||||||
|
this.block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicBlock createBlock() {
|
||||||
|
BasicBlock block = program.createBasicBlock();
|
||||||
|
setBlock(block);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter constant(String value) {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
StringConstantInstruction insn = new StringConstantInstruction();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
insn.setConstant(value);
|
||||||
|
addInstruction(insn);
|
||||||
|
return wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter constant(int value) {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
IntegerConstantInstruction insn = new IntegerConstantInstruction();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
insn.setConstant(value);
|
||||||
|
addInstruction(insn);
|
||||||
|
return wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter constant(long value) {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
LongConstantInstruction insn = new LongConstantInstruction();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
insn.setConstant(value);
|
||||||
|
addInstruction(insn);
|
||||||
|
return wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter constant(float value) {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
FloatConstantInstruction insn = new FloatConstantInstruction();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
insn.setConstant(value);
|
||||||
|
addInstruction(insn);
|
||||||
|
return wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter constant(double value) {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
DoubleConstantInstruction insn = new DoubleConstantInstruction();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
insn.setConstant(value);
|
||||||
|
addInstruction(insn);
|
||||||
|
return wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter constantNull() {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
NullConstantInstruction insn = new NullConstantInstruction();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
addInstruction(insn);
|
||||||
|
return wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter getField(FieldReference field, ValueType type) {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
GetFieldInstruction insn = new GetFieldInstruction();
|
||||||
|
insn.setField(field);
|
||||||
|
insn.setFieldType(type);
|
||||||
|
insn.setReceiver(var);
|
||||||
|
addInstruction(insn);
|
||||||
|
return wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramEmitter setField(FieldReference field, ValueType type, ValueEmitter value) {
|
||||||
|
PutFieldInstruction insn = new PutFieldInstruction();
|
||||||
|
insn.setField(field);
|
||||||
|
insn.setFieldType(type);
|
||||||
|
insn.setValue(value.getVariable());
|
||||||
|
addInstruction(insn);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter invoke(MethodReference method, ValueEmitter... arguments) {
|
||||||
|
Variable result = null;
|
||||||
|
if (method.getReturnType() != ValueType.VOID) {
|
||||||
|
result = program.createVariable();
|
||||||
|
}
|
||||||
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
|
insn.setType(InvocationType.SPECIAL);
|
||||||
|
insn.setMethod(method);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
for (ValueEmitter arg : arguments) {
|
||||||
|
insn.getArguments().add(arg.variable);
|
||||||
|
}
|
||||||
|
addInstruction(insn);
|
||||||
|
return result != null ? wrap(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramEmitter invokeAndIgnore(MethodReference method, ValueEmitter... arguments) {
|
||||||
|
invoke(method, arguments);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter construct(MethodReference method, ValueEmitter... arguments) {
|
||||||
|
Variable var = program.createVariable();
|
||||||
|
ConstructInstruction insn = new ConstructInstruction();
|
||||||
|
insn.setReceiver(var);
|
||||||
|
insn.setType(method.getClassName());
|
||||||
|
addInstruction(insn);
|
||||||
|
ValueEmitter instance = wrap(var);
|
||||||
|
instance.invokeSpecial(method, arguments);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramEmitter jump(BasicBlock block) {
|
||||||
|
JumpInstruction insn = new JumpInstruction();
|
||||||
|
insn.setTarget(block);
|
||||||
|
addInstruction(insn);
|
||||||
|
this.block = block;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exit() {
|
||||||
|
ExitInstruction insn = new ExitInstruction();
|
||||||
|
addInstruction(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter wrap(Variable var) {
|
||||||
|
return new ValueEmitter(this, block, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter wrapNew() {
|
||||||
|
return wrap(program.createVariable());
|
||||||
|
}
|
||||||
|
|
||||||
|
public InstructionLocation getCurrentLocation() {
|
||||||
|
return currentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentLocation(InstructionLocation currentLocation) {
|
||||||
|
this.currentLocation = currentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addInstruction(Instruction insn) {
|
||||||
|
if (currentLocation != null) {
|
||||||
|
insn.setLocation(currentLocation);
|
||||||
|
}
|
||||||
|
block.getInstructions().add(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProgramEmitter create(MethodHolder method) {
|
||||||
|
Program program = new Program();
|
||||||
|
method.setProgram(program);
|
||||||
|
BasicBlock zeroBlock = program.createBasicBlock();
|
||||||
|
BasicBlock block = program.createBasicBlock();
|
||||||
|
|
||||||
|
JumpInstruction insn = new JumpInstruction();
|
||||||
|
insn.setTarget(block);
|
||||||
|
zeroBlock.getInstructions().add(insn);
|
||||||
|
|
||||||
|
return new ProgramEmitter(program, block);
|
||||||
|
}
|
||||||
|
}
|
280
teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java
Normal file
280
teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.model.emit;
|
||||||
|
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.Incoming;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Phi;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingCondition;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryOperation;
|
||||||
|
import org.teavm.model.instructions.BranchingCondition;
|
||||||
|
import org.teavm.model.instructions.BranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.CastInstruction;
|
||||||
|
import org.teavm.model.instructions.CastIntegerDirection;
|
||||||
|
import org.teavm.model.instructions.CastIntegerInstruction;
|
||||||
|
import org.teavm.model.instructions.CastNumberInstruction;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.GetElementInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.IntegerSubtype;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.IsInstanceInstruction;
|
||||||
|
import org.teavm.model.instructions.NegateInstruction;
|
||||||
|
import org.teavm.model.instructions.NumericOperandType;
|
||||||
|
import org.teavm.model.instructions.PutFieldInstruction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class ValueEmitter {
|
||||||
|
ProgramEmitter pe;
|
||||||
|
BasicBlock block;
|
||||||
|
Variable variable;
|
||||||
|
|
||||||
|
ValueEmitter(ProgramEmitter programEmitter, BasicBlock block, Variable variable) {
|
||||||
|
this.pe = programEmitter;
|
||||||
|
this.block = block;
|
||||||
|
this.variable = variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramEmitter getProgramEmitter() {
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicBlock getBlock() {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Variable getVariable() {
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter getField(FieldReference field, ValueType type) {
|
||||||
|
Variable var = pe.getProgram().createVariable();
|
||||||
|
GetFieldInstruction insn = new GetFieldInstruction();
|
||||||
|
insn.setField(field);
|
||||||
|
insn.setFieldType(type);
|
||||||
|
insn.setReceiver(var);
|
||||||
|
insn.setInstance(variable);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField(FieldReference field, ValueType type, ValueEmitter value) {
|
||||||
|
PutFieldInstruction insn = new PutFieldInstruction();
|
||||||
|
insn.setField(field);
|
||||||
|
insn.setFieldType(type);
|
||||||
|
insn.setInstance(variable);
|
||||||
|
insn.setValue(value.getVariable());
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter binary(BinaryOperation op, NumericOperandType type, ValueEmitter other) {
|
||||||
|
Variable var = pe.getProgram().createVariable();
|
||||||
|
BinaryInstruction insn = new BinaryInstruction(op, type);
|
||||||
|
insn.setFirstOperand(variable);
|
||||||
|
insn.setSecondOperand(other.variable);
|
||||||
|
insn.setReceiver(var);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter add(NumericOperandType type, ValueEmitter other) {
|
||||||
|
return binary(BinaryOperation.ADD, type, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter iadd(ValueEmitter other) {
|
||||||
|
return add(NumericOperandType.INT, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter sub(NumericOperandType type, ValueEmitter other) {
|
||||||
|
return binary(BinaryOperation.SUBTRACT, type, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter isub(ValueEmitter other) {
|
||||||
|
return sub(NumericOperandType.INT, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter compare(NumericOperandType type, ValueEmitter other) {
|
||||||
|
return binary(BinaryOperation.COMPARE, type, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter icompare(ValueEmitter other) {
|
||||||
|
return compare(NumericOperandType.INT, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter neg(NumericOperandType type) {
|
||||||
|
Variable var = pe.getProgram().createVariable();
|
||||||
|
NegateInstruction insn = new NegateInstruction(type);
|
||||||
|
insn.setOperand(variable);
|
||||||
|
insn.setReceiver(var);
|
||||||
|
return pe.wrap(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter ineg() {
|
||||||
|
return neg(NumericOperandType.INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter invoke(InvocationType type, MethodReference method, ValueEmitter... arguments) {
|
||||||
|
Variable result = null;
|
||||||
|
if (method.getReturnType() != ValueType.VOID) {
|
||||||
|
result = pe.getProgram().createVariable();
|
||||||
|
}
|
||||||
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
|
insn.setType(type);
|
||||||
|
insn.setMethod(method);
|
||||||
|
insn.setInstance(variable);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
for (ValueEmitter arg : arguments) {
|
||||||
|
insn.getArguments().add(arg.variable);
|
||||||
|
}
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return result != null ? pe.wrap(result) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter invokeSpecial(MethodReference method, ValueEmitter... arguments) {
|
||||||
|
return invoke(InvocationType.SPECIAL, method, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter invokeVirtual(MethodReference method, ValueEmitter... arguments) {
|
||||||
|
return invoke(InvocationType.VIRTUAL, method, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter join(ValueEmitter other) {
|
||||||
|
Variable var = pe.getProgram().createVariable();
|
||||||
|
Phi phi = new Phi();
|
||||||
|
phi.setReceiver(var);
|
||||||
|
Incoming incoming = new Incoming();
|
||||||
|
incoming.setSource(block);
|
||||||
|
incoming.setValue(variable);
|
||||||
|
phi.getIncomings().add(incoming);
|
||||||
|
incoming = new Incoming();
|
||||||
|
incoming.setSource(other.block);
|
||||||
|
incoming.setValue(other.variable);
|
||||||
|
phi.getIncomings().add(incoming);
|
||||||
|
pe.getBlock().getPhis().add(phi);
|
||||||
|
return new ValueEmitter(pe, pe.getBlock(), var);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForkEmitter fork(BinaryBranchingCondition condition, ValueEmitter other) {
|
||||||
|
final BinaryBranchingInstruction insn = new BinaryBranchingInstruction(condition);
|
||||||
|
insn.setFirstOperand(variable);
|
||||||
|
insn.setSecondOperand(other.variable);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return new ForkEmitter() {
|
||||||
|
@Override public void setThen(BasicBlock block) {
|
||||||
|
insn.setConsequent(block);
|
||||||
|
}
|
||||||
|
@Override public void setElse(BasicBlock block) {
|
||||||
|
insn.setAlternative(block);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForkEmitter fork(BranchingCondition condition) {
|
||||||
|
final BranchingInstruction insn = new BranchingInstruction(condition);
|
||||||
|
insn.setOperand(variable);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return new ForkEmitter() {
|
||||||
|
@Override public void setThen(BasicBlock block) {
|
||||||
|
insn.setConsequent(block);
|
||||||
|
}
|
||||||
|
@Override public void setElse(BasicBlock block) {
|
||||||
|
insn.setAlternative(block);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void returnValue() {
|
||||||
|
ExitInstruction insn = new ExitInstruction();
|
||||||
|
insn.setValueToReturn(variable);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter cast(ValueType type) {
|
||||||
|
Variable result = pe.getProgram().createVariable();
|
||||||
|
CastInstruction insn = new CastInstruction();
|
||||||
|
insn.setValue(variable);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
insn.setTargetType(type);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter cast(NumericOperandType from, NumericOperandType to) {
|
||||||
|
Variable result = pe.getProgram().createVariable();
|
||||||
|
CastNumberInstruction insn = new CastNumberInstruction(from, to);
|
||||||
|
insn.setValue(variable);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter cast(IntegerSubtype subtype, CastIntegerDirection dir) {
|
||||||
|
Variable result = pe.getProgram().createVariable();
|
||||||
|
CastIntegerInstruction insn = new CastIntegerInstruction(subtype, dir);
|
||||||
|
insn.setValue(variable);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter toInteger(IntegerSubtype from) {
|
||||||
|
return cast(from, CastIntegerDirection.TO_INTEGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter fromInteger(IntegerSubtype to) {
|
||||||
|
return cast(to, CastIntegerDirection.FROM_INTEGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter getElement(ValueEmitter index) {
|
||||||
|
Variable result = pe.getProgram().createVariable();
|
||||||
|
GetElementInstruction insn = new GetElementInstruction();
|
||||||
|
insn.setArray(variable);
|
||||||
|
insn.setIndex(index.variable);
|
||||||
|
insn.setReceiver(variable);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter arrayLength() {
|
||||||
|
Variable result = pe.getProgram().createVariable();
|
||||||
|
ArrayLengthInstruction insn = new ArrayLengthInstruction();
|
||||||
|
insn.setArray(variable);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEmitter instanceOf(ValueType type) {
|
||||||
|
Variable result = pe.getProgram().createVariable();
|
||||||
|
IsInstanceInstruction insn = new IsInstanceInstruction();
|
||||||
|
insn.setValue(variable);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
insn.setType(type);
|
||||||
|
pe.addInstruction(insn);
|
||||||
|
return pe.wrap(result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,18 +33,12 @@ import org.teavm.platform.metadata.Resource;
|
||||||
public class MetadataProviderNativeGenerator implements Generator {
|
public class MetadataProviderNativeGenerator implements Generator {
|
||||||
@Override
|
@Override
|
||||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||||
// Validate method
|
|
||||||
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
||||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||||
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
||||||
if (providerAnnot == null) {
|
|
||||||
return;
|
AnnotationReader refAnnot = method.getAnnotations().get(MetadataProviderRef.class.getName());
|
||||||
}
|
methodRef = MethodReference.parse(refAnnot.getValue("value").getString());
|
||||||
if (!method.hasModifier(ElementModifier.NATIVE)) {
|
|
||||||
context.getDiagnostics().error(new CallLocation(methodRef), "Method {{m0}} is marked with " +
|
|
||||||
"{{c1}} annotation, but it is not native", methodRef, MetadataProvider.class.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find and instantiate metadata generator
|
// Find and instantiate metadata generator
|
||||||
ValueType generatorType = providerAnnot.getValue("value").getJavaClass();
|
ValueType generatorType = providerAnnot.getValue("value").getJavaClass();
|
||||||
|
@ -78,12 +72,8 @@ public class MetadataProviderNativeGenerator implements Generator {
|
||||||
|
|
||||||
// Generate resource loader
|
// Generate resource loader
|
||||||
Resource resource = generator.generateMetadata(metadataContext, methodRef);
|
Resource resource = generator.generateMetadata(metadataContext, methodRef);
|
||||||
writer.append("if (!window.hasOwnProperty(\"").appendMethodBody(methodRef).append("$$resource\")) {")
|
writer.append("return ");
|
||||||
.indent().softNewLine();
|
|
||||||
writer.append("window.").appendMethodBody(methodRef).append("$$resource = ");
|
|
||||||
ResourceWriterHelper.write(writer, resource);
|
ResourceWriterHelper.write(writer, resource);
|
||||||
writer.append(';').softNewLine();
|
writer.append(';').softNewLine();
|
||||||
writer.outdent().append('}').softNewLine();
|
|
||||||
writer.append("return ").appendMethodBody(methodRef).append("$$resource;").softNewLine();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.platform.plugin;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@interface MetadataProviderRef {
|
||||||
|
String value();
|
||||||
|
}
|
|
@ -18,6 +18,10 @@ package org.teavm.platform.plugin;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.javascript.spi.GeneratedBy;
|
import org.teavm.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
|
import org.teavm.model.emit.ForkEmitter;
|
||||||
|
import org.teavm.model.emit.ProgramEmitter;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingCondition;
|
||||||
|
import org.teavm.model.util.ModelUtils;
|
||||||
import org.teavm.platform.PlatformClass;
|
import org.teavm.platform.PlatformClass;
|
||||||
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
||||||
import org.teavm.platform.metadata.MetadataProvider;
|
import org.teavm.platform.metadata.MetadataProvider;
|
||||||
|
@ -27,15 +31,14 @@ import org.teavm.platform.metadata.MetadataProvider;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
class MetadataProviderTransformer implements ClassHolderTransformer {
|
class MetadataProviderTransformer implements ClassHolderTransformer {
|
||||||
|
static int fieldIdGen;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
||||||
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
||||||
if (providerAnnot != null) {
|
if (providerAnnot != null) {
|
||||||
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
|
transformMetadataMethod(cls, method, diagnostics);
|
||||||
genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
|
|
||||||
MetadataProviderNativeGenerator.class.getName())));
|
|
||||||
method.getAnnotations().add(genAnnot);
|
|
||||||
}
|
}
|
||||||
providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName());
|
providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName());
|
||||||
if (providerAnnot != null) {
|
if (providerAnnot != null) {
|
||||||
|
@ -53,4 +56,58 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void transformMetadataMethod(ClassHolder cls, MethodHolder method, Diagnostics diagnostics) {
|
||||||
|
if (!validate(method, diagnostics)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldHolder field = new FieldHolder("$$metadata$$" + fieldIdGen++);
|
||||||
|
field.setType(method.getResultType());
|
||||||
|
field.setLevel(AccessLevel.PRIVATE);
|
||||||
|
field.getModifiers().add(ElementModifier.STATIC);
|
||||||
|
cls.addField(field);
|
||||||
|
|
||||||
|
MethodHolder createMethod = new MethodHolder(method.getName() + "$$create", method.getSignature());
|
||||||
|
createMethod.setLevel(AccessLevel.PRIVATE);
|
||||||
|
createMethod.getModifiers().add(ElementModifier.NATIVE);
|
||||||
|
createMethod.getModifiers().add(ElementModifier.STATIC);
|
||||||
|
cls.addMethod(createMethod);
|
||||||
|
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
|
||||||
|
genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
|
||||||
|
MetadataProviderNativeGenerator.class.getName())));
|
||||||
|
createMethod.getAnnotations().add(genAnnot);
|
||||||
|
ModelUtils.copyAnnotations(method.getAnnotations(), createMethod.getAnnotations());
|
||||||
|
|
||||||
|
AnnotationHolder refAnnot = new AnnotationHolder(MetadataProviderRef.class.getName());
|
||||||
|
refAnnot.getValues().put("value", new AnnotationValue(method.getReference().toString()));
|
||||||
|
createMethod.getAnnotations().add(refAnnot);
|
||||||
|
|
||||||
|
method.getModifiers().remove(ElementModifier.NATIVE);
|
||||||
|
ProgramEmitter pe = ProgramEmitter.create(method);
|
||||||
|
ForkEmitter fork = pe.getField(field.getReference(), field.getType()).fork(
|
||||||
|
BinaryBranchingCondition.REFERENCE_NOT_EQUAL, pe.constantNull());
|
||||||
|
|
||||||
|
BasicBlock resourceFound = pe.createBlock();
|
||||||
|
fork.setThen(resourceFound);
|
||||||
|
pe.getField(field.getReference(), field.getType()).returnValue();
|
||||||
|
|
||||||
|
fork.setElse(pe.createBlock());
|
||||||
|
pe.setField(field.getReference(), field.getType(), pe.invoke(createMethod.getReference()));
|
||||||
|
pe.jump(resourceFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validate(MethodHolder method, Diagnostics diagnostics) {
|
||||||
|
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
||||||
|
if (providerAnnot == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!method.hasModifier(ElementModifier.NATIVE)) {
|
||||||
|
diagnostics.error(new CallLocation(method.getReference()), "Method {{m0}} is marked with " +
|
||||||
|
"{{c1}} annotation, but it is not native", method.getReference(),
|
||||||
|
MetadataProvider.class.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user