mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -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 {
|
||||
TParsePosition position = new TParsePosition(0);
|
||||
TDate date = parse(string, position);
|
||||
if (position.getIndex() == 0) {
|
||||
throw new TParseException("Unparseable date" + string, position.getErrorIndex());
|
||||
if (position.getErrorIndex() > 0) {
|
||||
throw new TParseException("Unparseable date: " + string, position.getErrorIndex());
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
|
|
@ -400,6 +400,7 @@ abstract class TDateFormatElement {
|
|||
if (position.getIndex() + 1 < text.length()) {
|
||||
|
||||
}
|
||||
prepareTrie();
|
||||
TTimeZone tz = match(searchTrie, text, position);
|
||||
if (tz != null) {
|
||||
date.setTimeZone(tz);
|
||||
|
@ -415,12 +416,11 @@ abstract class TDateFormatElement {
|
|||
}
|
||||
|
||||
public TTimeZone match(TrieNode node, String text, TParsePosition position) {
|
||||
prepareTrie();
|
||||
int start = position.getIndex();
|
||||
int index = start;
|
||||
int lastMatch = start;
|
||||
TTimeZone tz = null;
|
||||
while (node.childNodes.length > 0) {
|
||||
while (node.childNodes != null && node.childNodes.length > 0) {
|
||||
if (node.tz != null) {
|
||||
lastMatch = index;
|
||||
tz = node.tz;
|
||||
|
@ -432,7 +432,11 @@ abstract class TDateFormatElement {
|
|||
if (next < 0) {
|
||||
return null;
|
||||
}
|
||||
node = node.childNodes[index];
|
||||
node = node.childNodes[next];
|
||||
}
|
||||
if (node.tz != null) {
|
||||
lastMatch = index;
|
||||
tz = node.tz;
|
||||
}
|
||||
position.setIndex(lastMatch);
|
||||
return tz;
|
||||
|
@ -459,6 +463,7 @@ abstract class TDateFormatElement {
|
|||
TTimeZone tz = TTimeZone.getTimeZone(tzId);
|
||||
builder.add(tz.getID(), tz);
|
||||
}
|
||||
idSearchTrie = builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,6 +490,7 @@ abstract class TDateFormatElement {
|
|||
position.setErrorIndex(index);
|
||||
return;
|
||||
}
|
||||
++index;
|
||||
|
||||
if (index + 2 > text.length() || !Character.isDigit(text.charAt(index)) ||
|
||||
!Character.isDigit(text.charAt(index + 1))) {
|
||||
|
@ -511,10 +517,9 @@ abstract class TDateFormatElement {
|
|||
TrieNodeBuilder root = new TrieNodeBuilder();
|
||||
|
||||
public void add(String text, TTimeZone tz) {
|
||||
int index = 0;
|
||||
TrieNodeBuilder node = root;
|
||||
while (index < text.length()) {
|
||||
char c = Character.toLowerCase(text.charAt(index));
|
||||
for (int i = 0; i < text.length(); ++i) {
|
||||
char c = Character.toLowerCase(text.charAt(i));
|
||||
while (node.ch != c) {
|
||||
if (node.ch == '\0') {
|
||||
node.ch = c;
|
||||
|
@ -537,12 +542,15 @@ abstract class TDateFormatElement {
|
|||
|
||||
TrieNode build(TrieNodeBuilder builder) {
|
||||
TrieNode node = new TrieNode();
|
||||
if (builder == null) {
|
||||
return node;
|
||||
}
|
||||
node.tz = builder.tz;
|
||||
List<TrieNodeBuilder> builders = new ArrayList<>();
|
||||
TrieNodeBuilder tmp = builder;
|
||||
while (tmp.ch != '\0') {
|
||||
builders.add(builder);
|
||||
builder = builder.sibling;
|
||||
builders.add(tmp);
|
||||
tmp = tmp.sibling;
|
||||
}
|
||||
Collections.sort(builders, new Comparator<TrieNodeBuilder>() {
|
||||
@Override public int compare(TrieNodeBuilder o1, TrieNodeBuilder o2) {
|
||||
|
@ -553,7 +561,7 @@ abstract class TDateFormatElement {
|
|||
node.childNodes = new TrieNode[builders.size()];
|
||||
for (int i = 0; i < node.chars.length; ++i) {
|
||||
node.chars[i] = builders.get(i).ch;
|
||||
node.childNodes[i] = build(builders.get(i));
|
||||
node.childNodes[i] = build(builders.get(i).next);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -139,6 +139,12 @@ public class MethodReference {
|
|||
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() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
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 {
|
||||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
// Validate method
|
||||
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
|
||||
if (providerAnnot == null) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
AnnotationReader refAnnot = method.getAnnotations().get(MetadataProviderRef.class.getName());
|
||||
methodRef = MethodReference.parse(refAnnot.getValue("value").getString());
|
||||
|
||||
// Find and instantiate metadata generator
|
||||
ValueType generatorType = providerAnnot.getValue("value").getJavaClass();
|
||||
|
@ -78,12 +72,8 @@ public class MetadataProviderNativeGenerator implements Generator {
|
|||
|
||||
// Generate resource loader
|
||||
Resource resource = generator.generateMetadata(metadataContext, methodRef);
|
||||
writer.append("if (!window.hasOwnProperty(\"").appendMethodBody(methodRef).append("$$resource\")) {")
|
||||
.indent().softNewLine();
|
||||
writer.append("window.").appendMethodBody(methodRef).append("$$resource = ");
|
||||
writer.append("return ");
|
||||
ResourceWriterHelper.write(writer, resource);
|
||||
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.javascript.spi.GeneratedBy;
|
||||
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.metadata.ClassScopedMetadataProvider;
|
||||
import org.teavm.platform.metadata.MetadataProvider;
|
||||
|
@ -27,15 +31,14 @@ import org.teavm.platform.metadata.MetadataProvider;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
class MetadataProviderTransformer implements ClassHolderTransformer {
|
||||
static int fieldIdGen;
|
||||
|
||||
@Override
|
||||
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());
|
||||
if (providerAnnot != null) {
|
||||
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
|
||||
genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
|
||||
MetadataProviderNativeGenerator.class.getName())));
|
||||
method.getAnnotations().add(genAnnot);
|
||||
transformMetadataMethod(cls, method, diagnostics);
|
||||
}
|
||||
providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName());
|
||||
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