/*
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package ru.malik.elaborarer.avtoo.compiler;
import avt.io.*;
import avt.util.*;
import ru.malik.elaborarer.avtoo.lang.*;
public class ImmediateBuilder(TableBuilder, AVTOOConstants, AVTOORecompilable, AVTOOService)
{
private static void requiresValue(Node value) {
Type type = value.type;
if(type == null || type.isVoid()) switch(value.instruction)
{
case STORE_LOCAL:
case STORE_STATIC:
{
value.type = type = ((TypedItem) value.operand1).type;
value.parentCode.createAndAppendNode(value).setData(-1, null, DUP1, type);
}
break;
case WRITE_FIELD:
case WRITE_SPECIAL:
case WRITE_PROPERTY:
{
value.type = type = ((TypedItem) value.operand1).type;
value.parentCode.createAndAppendNode(value).setData(-1, null, DUP1X1, type);
}
break;
case WRITE_COMPONENT:
{
value.type = type = (Type) value.operand1;
value.parentCode.createAndAppendNode(value).setData(-1, null, DUP1X2, type);
}
break;
case INVOKE_SERVICE:
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
Callable callable = (Callable) value.operand1;
if(callable instanceof Operator && ((Operator) callable).kind == WRITE_COMPONENT)
{
value.type = type = callable.arguments[1].type;
value.parentCode.createAndAppendNode(value).setData(-1, null, DUP1X2, type);
}
}
}
private static void defineAttainability(byte[] attainability, Code code, int length) {
for(boolean added = false, int cindex = 0; ; )
{
Node node = code[cindex];
int instruction = node.instruction;
if(node.persistent && instruction != BEGIN || instruction == METHOD_ENTER || instruction >= EXCEPT_ENTER && instruction <= EXCEPT_LEAVE || attainability[cindex] != 0)
{
for(attainability[cindex] = -1, int jindex = node.getJumpCasesLength(); jindex-- > -1; )
{
Node target = jindex < 0 ? node.jumpDefault : node.getJumpCaseNodeAt(jindex);
if(target != null)
{
int order = target.order;
if(order >= 0 && attainability[order] == 0)
{
attainability[order] = -1;
added = true;
}
}
}
}
if(++cindex >= length)
{
if(!added) break;
added = false;
cindex = 0;
}
}
}
private static void appendPropertyIndexCode(int position, Node parent, Constant constant, TypedMember member) {
if(constant != null)
{
parent.parentCode.createAndAppendNode(parent).setData(position, constant.type, LOAD_CONST, constant);
return;
}
if(member instanceof Field)
{
Code code = parent.parentCode;
Callable enclosingCallable = code.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
Node index = code.createAndAppendNode(parent).setData(position, member.type, READ_FIELD, member);
code.createAndAppendNode(index).setData(position, enclosingClassType.getRealType(), LOAD_LOCAL, enclosingCallable.arguments.thisArgument);
return;
}
if(member instanceof Method)
{
Code code = parent.parentCode;
Callable enclosingCallable = code.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
Node index = code.createAndAppendNode(parent).setData(position, member.type, invokeInstructionFor(member, enclosingClassType), member);
code.createAndAppendNode(index).setData(position, enclosingClassType.getRealType(), LOAD_LOCAL, enclosingCallable.arguments.thisArgument);
}
}
private static boolean isLogicalConditionNode(Node node) {
Node subnode = node[1];
switch(subnode.instruction)
{
case BOOL_OR:
case BOOL_AND:
case BOOL_NOT:
return true;
case BOOL_COND:
if(isLogicalConditionNode(subnode)) return true;
}
switch((subnode = node[-1]).instruction)
{
case BOOL_OR:
case BOOL_AND:
case BOOL_NOT:
return true;
case BOOL_COND:
return isLogicalConditionNode(subnode);
}
return false;
}
private static boolean isHandledException(ClassType type, Node parent, Callable callable) {
for(Node handler = parent; handler != null; handler = handler.parentNode) if(handler.instruction == BEGIN) for(int index = (handler = handler.parentNode).length; index-- > 1; )
{
Node node = handler[index];
if(node.instruction == CATCH && ((ClassType) node.reference1).isAssignableFrom(type)) return true;
}
return callable.canThrown(type);
}
private static int invokeInstructionFor(Member foundCallable, ClassType foundPlace) {
return foundCallable.visibility <= PRIVATE || foundCallable.isFinal() || foundPlace.isFinal() || foundCallable.parentType.isHelper() ? (
INVOKE_SPECIAL
) : foundPlace.isService() ? (
INVOKE_SERVICE
) : (
INVOKE_VIRTUAL
);
}
private static ClassType getUnhandledException(Method method, Node parent, Callable callable) {
for(int index = method.getThrowablesLength(); index-- > 0; )
{
ClassType type = method.getThrowableTypeAt(index);
if(!type.isFreeThrowableType() && !isHandledException(type, parent, callable)) return type;
}
return null;
}
private static Node cast(Node value, Type newType) {
Type oldType = value.type;
if(newType != oldType)
{
if(oldType.isNull())
{
if(!newType.isPrimitive())
{
value.type = newType;
}
}
else if(oldType.isPrimitive())
{
if(newType.isPrimitive())
{
TableItem operand = value.operand1;
if(value.instruction == LOAD_CONST)
{
value.type = newType;
value.operand1 = ((Constant) operand).castTo(newType);
}
else if(newType.isInt() && !oldType.isStackable())
{
value.type = newType;
}
else
{
newType.makeCompilable();
Code code = value.parentCode;
Node cast = code.createAndInsertNode(value.parentNode, value.index).setData(-1, newType, CAST_TO, newType, oldType);
code.moveNode(value, cast, 0);
return cast;
}
}
}
else
{
if(!newType.isPrimitive())
{
if(newType.isAssignableFrom(oldType))
{
value.type = newType;
}
else
{
newType.makeCompilable();
Code code = value.parentCode;
Node cast = code.createAndInsertNode(value.parentNode, value.index).setData(-1, newType, CAST_TO, newType, oldType);
code.moveNode(value, cast, 0);
return cast;
}
}
}
}
return value;
}
private Constant fldNull;
private Constant fldTrue;
private Constant fldFalse;
private NullType fldTypeNull;
private ClassType fldTypeClass;
private ClassType fldTypeObject;
private ClassType fldTypeString;
private ClassType fldTypeStruct;
private ClassType fldTypePackage;
private ClassType fldTypeThrowable;
private PrimitiveType fldTypeVoid;
private PrimitiveType fldTypeBoolean;
private PrimitiveType fldTypeInt;
private PrimitiveType fldTypeLong;
private ConstantFactory fldConstantFactory;
private CompilerParallelWorker fldThreadItemHolder;
private final boolean fldLibrary;
private final boolean fldStaticFieldsOnly;
private final ImmediateBuilderItemHolder fldGlobalItemHolder;
public (int pointerSize): super(pointerSize) {
fldGlobalItemHolder = new ImmediateBuilderItemHolder();
}
public (int pointerSize, boolean staticFieldsOnly): super(pointerSize) {
fldStaticFieldsOnly = staticFieldsOnly;
fldGlobalItemHolder = new ImmediateBuilderItemHolder();
}
public (int pointerSize, boolean staticFieldsOnly, boolean library): super(pointerSize) {
fldLibrary = library;
fldStaticFieldsOnly = staticFieldsOnly;
fldGlobalItemHolder = new ImmediateBuilderItemHolder();
}
public void compile() throws IOException, CompilerException {
/* -- предыдущие стадии -- */
super.compile();
/* -- константы и типы, используемые в следующей стадии -- */
ConstantFactory factory = getConstantFactory();
fldNull = factory.createNull();
fldTrue = factory.createBoolean(true);
fldFalse = factory.createBoolean(false);
fldTypeNull = getNullType();
fldTypeClass = getClassType(PACKNAME_LANG + "." + TYPENAME_CLASS);
fldTypeObject = getClassType(PACKNAME_LANG + "." + TYPENAME_OBJECT);
fldTypeString = getClassType(PACKNAME_LANG + "." + TYPENAME_STRING);
fldTypeStruct = getClassType(PACKNAME_LANG + "." + TYPENAME_STRUCT);
fldTypePackage = getClassType(PACKNAME_LANG + "." + TYPENAME_PACKAGE);
fldTypeThrowable = getClassType(PACKNAME_LANG + "." + TYPENAME_THROWABLE);
fldTypeVoid = getPrimitiveType(VOID);
fldTypeBoolean = getPrimitiveType(BOOLEAN);
fldTypeInt = getPrimitiveType(INT);
fldTypeLong = getPrimitiveType(LONG);
fldConstantFactory = factory;
/* 6. Стадия построения исполняемого кода проекта */
Library project = project;
ClassType[] classes = project.classes.clone();
ArrayType[] arrays = arrays.clone();
int clength = classes.length;
int alength = arrays.length;
int maxThreads = maxThreads;
boolean isLibrary = library;
boolean isStaticFieldsOnly = staticFieldsOnly;
for(int cindex = 0; cindex < clength; cindex++)
{
ClassType type = classes[cindex];
ClassInit staticBlock = type.getStaticBlock();
for(int tlength = type.length, int mindex = 0; mindex < tlength; mindex++)
{
Member member = type[mindex];
if(member instanceof Field) parseStaticFieldValue((Field) member, staticBlock);
}
if(staticBlock != null && staticBlock.declarationPosition < 0 && staticBlock.code.root.isEmpty()) type.removeStaticBlock();
}
if(isStaticFieldsOnly)
{
return;
}
if(!isLibrary)
{
int tlength = 0;
ClassType[] types = null;
for(LibraryArray libraries = libraries, int llength = libraries.length, int lindex = 0; lindex < llength; lindex++)
{
Library library = libraries[lindex];
if(project != library)
{
ClassType[] content = library.classes.clone();
if(types == null)
{
tlength = content.length;
Array.copy(content, 0, types = new ClassType[getBestArrayCapacity(tlength)], 0, tlength);
} else
{
int dlength = content.length;
int nlength = tlength + dlength;
if(nlength > types.length)
{
Array.copy(types, 0, types = new ClassType[getBestArrayCapacity(nlength)], 0, tlength);
}
Array.copy(content, 0, types, tlength, dlength);
tlength = nlength;
}
}
}
if(tlength != types.length)
{
Array.copy(types, 0, types = new ClassType[tlength], 0, tlength);
}
with(new CompilerParallelWorker(maxThreads))
{
targets = types;
run(new ImmediateBuilderForBinarySources(this));
}
}
for(int cindex = 0; cindex < clength; cindex++)
{
ClassType type = classes[cindex];
for(int tlength = type.length, int mindex = 0; mindex < tlength; mindex++)
{
Member member = type[mindex];
if(!member.isAbstract() && member instanceof Property) parsePropertySpecifiers((Property) member);
}
}
for(int aindex = 0; aindex < alength; aindex++)
{
ArrayType type = arrays[aindex];
Type componentType = type.componentType;
if(!(componentType instanceof PrimitiveType) && componentType != fldTypeObject)
{
alength = aindex;
break;
}
for(int tlength = type.length, int tindex = 0; tindex < tlength; tindex++)
{
Member member = type[tindex];
if(!member.isAbstract() && member instanceof Property) buildPropertySpecifiers((Property) member);
}
}
{
ClassType[] types = new ClassType[clength + alength];
Array.copy(classes, 0, types, 0, clength);
Array.copy(arrays, 0, types, clength, alength);
with(fldThreadItemHolder = new CompilerParallelWorker(maxThreads)) try
{
targets = types;
run(new ImmediateBuilderForTextSources(this));
} finally
{
fldThreadItemHolder = null;
}
}
/* 7. Стадия разметки данных */
Type[] types = types.clone();
int tlength = types.length;
if(!isLibrary) for(int tindex = 0; tindex < tlength; tindex++)
{
Type type = types[tindex];
if(type instanceof ClassType) ((ClassType) type).markupClass();
}
for(int tindex = 0; tindex < tlength; tindex++)
{
Type type = types[tindex];
if(type instanceof ClassType) ((ClassType) type).markupStruct();
}
}
public boolean library { read = fldLibrary }
public boolean staticFieldsOnly { read = fldStaticFieldsOnly }
final void readCallableBody(Callable callable) throws BinarySourceException, IOException {
Code code = callable.code;
ClassType enclosing = callable.parentType;
BinarySource source = (BinarySource) callable.source;
ConstantFactory factory = fldConstantFactory;
Constant constFalse = fldFalse;
Constant constTrue = fldTrue;
Constant constNull = fldNull;
Object[] constants = (Object[]) source[1];
with(source.chunks[callable.declarationPosition + 1]) if(type == CHUNK_CODE && code != null)
{
/* чтение аргументов и локальных переменных */
Hashtable primLocals = new Hashtable();
Hashtable refsLocals = new Hashtable();
ArgumentArray arguments = callable.arguments;
Local thisArgument = arguments.thisArgument;
if(thisArgument != null)
{
refsLocals[SPECNAME_THIS] = thisArgument;
}
for(int length = arguments.length, int index = 0; index < length; index++)
{
Local argument = arguments[index];
(argument.type.isPrimitive() ? primLocals : refsLocals)[argument.specialSimpleName] = argument;
}
for(int length = readUnsignedShort(), int index = 0; index < length; index++)
{
int type = readInt();
int name = readInt();
String localName = (String) constants[name];
Type localType = ((TypeElement) constants[type]).getItem();
(localType.isPrimitive() ? primLocals : refsLocals)[localName] = code.createLocal(false, localType, localName, null, -1);
}
/* чтение перекомпилируемого кода */
int dlength = 0x0f;
int llength = 0x0f;
int2[][] jmap = new int2[0x0f][];
Node[] debugs = new Node[dlength];
Node[] labels = new Node[llength];
Type typeObject = fldTypeObject;
Node root = code.root;
for(int cindex = 0; available() > 0; cindex++)
{
if(cindex == jmap.length) Array.copy(jmap, 0, jmap = new int2[cindex << 1 | 1][], 0, cindex);
int decoded;
int lineIndex = -1;
int labelIndex = -1;
int debugIndex = -1;
int encoded = readUnsignedShort();
if(!isInstruction(encoded) && !decodeDeclareLabel(encoded))
{
if(isLongNumber(encoded))
{
encoded = encoded << 0x10 | readUnsignedShort();
}
lineIndex = decodeDeclareNumber(encoded);
encoded = readUnsignedShort();
}
if(!isInstruction(encoded) && decodeDeclareLabel(encoded))
{
if(isLongNumber(encoded))
{
encoded = encoded << 0x10 | readUnsignedShort();
}
if((decoded = decodeDeclareNumber(encoded)) >= 0)
{
labelIndex = decoded;
} else
{
debugIndex = ~decoded;
if(code.createDebugIndex(lineIndex) != debugIndex)
{
throw new BinarySourceException(package.getResourceString("binary.invalid-debug-label-index")) { source = source, offset = dataOffsetToSourceOffset(position) };
}
}
encoded = readUnsignedShort();
}
if(!isInstruction(encoded))
{
throw new BinarySourceException(package.getResourceString("binary.expected.instruction-code")) { source = source, offset = dataOffsetToSourceOffset(position) };
}
boolean hasBooleanJump = false;
Node node = null;
switch(encoded >> 8)
{
case INST_METHOD_ENTER >> 8:
int operand1 = readIndex();
node = code.createAndAppendNode(root).setData(-1, METHOD_ENTER, new Int(operand1));
break;
case INST_SWAP >> 8:
Type operand1 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
node = code.createAndAppendNode(root).setData(-1, null, SWAP, operand1);
break;
case INST_BOUND >> 8:
node = code.createAndAppendNode(root).setData(-1, BOUND);
break;
case INST_THROW >> 8:
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
node = code.createAndAppendNode(root).setData(-1, THROW, operand1);
break;
case INST_LOAD_STATIC >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int global = readIndex();
Field operand1 = ((FieldElement) constants[global]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, LOAD_STATIC, operand1);
break;
case INST_LOAD_STATICW >> 8:
int global = readIndex();
Field operand1 = ((FieldElement) constants[global]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, LOAD_STATIC, operand1);
node.weak = true;
break;
case INST_LOAD_LOCAL >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int local = readIndex();
Type operand2 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
Local operand1 = local <= 0 ? thisArgument : (Local) (decoded == REF ? refsLocals : primLocals).operator []((String) constants[local]);
node = code.createAndAppendNode(root).setData(-1, null, LOAD_LOCAL, operand1, operand2);
break;
case INST_LOAD_LOCALW >> 8:
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) refsLocals.operator []((String) constants[local]);
node = code.createAndAppendNode(root).setData(-1, null, LOAD_LOCAL, operand1, typeObject);
node.weak = true;
break;
case INST_LOAD_CONST >> 8:
case INST_LOAD_CONSTW >> 8:
int value = readIndex();
Object element = constants[value];
Constant operand1 = factory.createFrom(!(element instanceof RecompilableElement) ? element : ((RecompilableElement) element).getItem());
if(operand1.isClass()) ((Type) operand1.asObject()).makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, LOAD_CONST, operand1);
if((encoded & FLAG_WEAK) != 0) node.weak = true;
break;
case INST_READ_ELEMENT >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, READ_ELEMENT, operand1);
break;
case INST_READ_ELEMENTI >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
Constant operand2 = factory.createInt(decodeVectorIndex(encoded));
node = code.createAndAppendNode(root).setData(-1, null, READ_ELEMENT, operand1, operand2);
break;
case INST_READ_COMPONENT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, READ_COMPONENT, operand1, operand2);
break;
case INST_READ_FIELD >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int fieldoid = readIndex();
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Field operand1 = ((FieldElement) constants[fieldoid]).getItem();
TableItem operand2 = getAdditionalOperand(operand, refsLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, READ_FIELD, operand1, operand2);
break;
case INST_READ_SPECIAL >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int fieldoid = readIndex();
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Property operand1 = ((PropertyElement) constants[fieldoid]).getItem();
TableItem operand2 = getAdditionalOperand(operand, refsLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, READ_SPECIAL, operand1, operand2);
break;
case INST_READ_PROPERTY >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int fieldoid = readIndex();
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Property operand1 = ((PropertyElement) constants[fieldoid]).getItem();
TableItem operand2 = getAdditionalOperand(operand, refsLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, READ_PROPERTY, operand1, operand2);
break;
case INST_STORE_STATIC >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int global = readIndex();
Field operand1 = ((FieldElement) constants[global]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, STORE_STATIC, operand1);
break;
case INST_STORE_STATIC_NULL >> 8:
int global = readIndex();
Field operand1 = ((FieldElement) constants[global]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, STORE_STATIC, operand1, constNull);
break;
case INST_STORE_STATIC_SHORT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int global = readIndex();
int value = readShort();
Field operand1 = ((FieldElement) constants[global]).getItem();
Constant operand2 = operand1.type.isBoolean() ? value != 0 ? constTrue : constFalse : factory.createInt(value);
node = code.createAndAppendNode(root).setData(-1, null, STORE_STATIC, operand1, operand2);
break;
case INST_STORE_STATIC_INT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int global = readIndex();
int value = readInt();
Field operand1 = ((FieldElement) constants[global]).getItem();
Constant operand2 = operand1.type.isBoolean() ? value != 0 ? constTrue : constFalse : factory.createInt(value);
node = code.createAndAppendNode(root).setData(-1, null, STORE_STATIC, operand1, operand2);
break;
case INST_STORE_LOCAL >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int store = decodeStore(encoded) - STORE_NORMAL;
int local = readIndex();
Type operand2 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
Local operand1 = local <= 0 ? thisArgument : (Local) (decoded == REF ? refsLocals : primLocals).operator []((String) constants[local]);
node = code.createAndAppendNode(root).setData(-1, null, STORE_LOCAL + store, operand1, operand2);
break;
case INST_STORE_LOCAL_NULL >> 8:
int store = decodeStore(encoded) - STORE_NORMAL;
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) refsLocals.operator []((String) constants[local]);
node = code.createAndAppendNode(root).setData(-1, null, STORE_LOCAL + store, operand1, constNull);
break;
case INST_STORE_LOCAL_SHORT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int store = decodeStore(encoded) - STORE_NORMAL;
int local = readIndex();
int value = readShort();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Constant operand2 = factory.createInt(value);
node = code.createAndAppendNode(root).setData(-1, null, STORE_LOCAL + store, operand1, operand2);
break;
case INST_STORE_LOCAL_INT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int store = decodeStore(encoded) - STORE_NORMAL;
int local = readIndex();
int value = readInt();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Constant operand2 = factory.createInt(value);
node = code.createAndAppendNode(root).setData(-1, null, STORE_LOCAL + store, operand1, operand2);
break;
case INST_INC_PRED_LOAD_LOCAL >> 8:
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Type operand2 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, INC_PRED_LOAD_LOCAL, operand1, operand2);
break;
case INST_INC_POST_LOAD_LOCAL >> 8:
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Type operand2 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, INC_POST_LOAD_LOCAL, operand1, operand2);
break;
case INST_DEC_PRED_LOAD_LOCAL >> 8:
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Type operand2 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, DEC_PRED_LOAD_LOCAL, operand1, operand2);
break;
case INST_DEC_POST_LOAD_LOCAL >> 8:
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Type operand2 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, DEC_POST_LOAD_LOCAL, operand1, operand2);
break;
case INST_WRITE_COMPONENT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
Type operand1 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
node = code.createAndAppendNode(root).setData(-1, null, WRITE_COMPONENT, operand1);
break;
case INST_WRITE_FIELD >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int fieldoid = readIndex();
Field operand1 = ((FieldElement) constants[fieldoid]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, WRITE_FIELD, operand1);
break;
case INST_WRITE_SPECIAL >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int fieldoid = readIndex();
Property operand1 = ((PropertyElement) constants[fieldoid]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, WRITE_SPECIAL, operand1);
break;
case INST_WRITE_PROPERTY >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int fieldoid = readIndex();
Property operand1 = ((PropertyElement) constants[fieldoid]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, WRITE_PROPERTY, operand1);
break;
case INST_SWITCH_TABLE >> 8:
int jvalue = readInt();
int jlength = readIndex();
int2[] jumps = new int2[jlength + 1];
for(int jindex = 0; jindex < jlength; jvalue++, jindex++)
{
int jlabel = readLabel();
jumps[jindex] = new int2 { jlabel, jvalue };
}
{
int jlabel = readLabel();
jumps[jlength] = jlabel;
}
jmap[cindex] = jumps;
node = code.createAndAppendNode(root).setData(-1, BRANCH);
break;
case INST_SWITCH_LOOKUP >> 8:
int jlength = readIndex();
int2[] jumps = new int2[jlength + 1];
for(int jindex = 0; jindex < jlength; jindex++)
{
int jvalue = readInt();
int jlabel = readLabel();
jumps[jindex] = new int2 { jlabel, jvalue };
}
{
int jlabel = readLabel();
jumps[jlength] = jlabel;
}
jmap[cindex] = jumps;
node = code.createAndAppendNode(root).setData(-1, BRANCH);
break;
case INST_JUMP >> 8:
int jlabel = readLabel();
jmap[cindex] = new int2[] { jlabel };
node = code.createAndAppendNode(root).setData(-1, JUMP);
break;
case INST_LOAD_INTERRUPT >> 8:
int method = readIndex();
Callable operand1 = ((CallableElement) constants[method]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, LOAD_INTERRUPT, operand1);
break;
case INST_LOAD_CONST_BYTE >> 8:
Constant operand1 = factory.createInt((byte) encoded);
node = code.createAndAppendNode(root).setData(-1, null, LOAD_CONST, operand1);
break;
case INST_LOAD_CONST_NULL >> 8:
node = code.createAndAppendNode(root).setData(-1, null, LOAD_CONST, constNull);
break;
case INST_LOAD_CONST_SHORT >> 8:
int value = readShort();
Constant operand1 = factory.createInt(value);
node = code.createAndAppendNode(root).setData(-1, null, LOAD_CONST, operand1);
break;
case INST_LOAD_CONST_INT >> 8:
int value = readInt();
Constant operand1 = factory.createInt(value);
node = code.createAndAppendNode(root).setData(-1, null, LOAD_CONST, operand1);
break;
case INST_REF_EQ >> 8:
case INST_REF_EQW >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
TableItem operand1 = getAdditionalOperand(operand, refsLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, REF_EQ, operand1);
if((encoded & FLAG_WEAK) != 0) node.weak = true;
break;
case INST_REF_NE >> 8:
case INST_REF_NEW >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
TableItem operand1 = getAdditionalOperand(operand, refsLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, REF_NE, operand1);
if((encoded & FLAG_WEAK) != 0) node.weak = true;
break;
case INST_REF_IS_NULL >> 8:
case INST_REF_IS_NULLW >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
node = code.createAndAppendNode(root).setData(-1, null, REF_IS_NULL);
if((encoded & FLAG_WEAK) != 0) node.weak = true;
break;
case INST_REF_IS_OBJECT >> 8:
case INST_REF_IS_OBJECTW >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
node = code.createAndAppendNode(root).setData(-1, null, REF_IS_OBJECT);
if((encoded & FLAG_WEAK) != 0) node.weak = true;
break;
case INST_CLINIT_TRY_LOCK >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, CLINIT_TRY_LOCK, operand1);
break;
case INST_CLINIT_UNLOCK >> 8:
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, CLINIT_UNLOCK, operand1);
break;
case INST_MONITOR_ENTER >> 8:
node = code.createAndAppendNode(root).setData(-1, MONITOR_ENTER);
break;
case INST_MONITOR_LEAVE >> 8:
node = code.createAndAppendNode(root).setData(-1, MONITOR_LEAVE);
break;
case INST_FINALLY_ENTER >> 8:
node = code.createAndAppendNode(root).setData(-1, FINALLY_ENTER);
break;
case INST_FINALLY_LEAVE >> 8:
node = code.createAndAppendNode(root).setData(-1, FINALLY_LEAVE);
break;
case INST_NEW_ARRAY >> 8:
int type = readIndex();
int length = readInt();
Type operand1 = ((TypeElement) constants[type]).getItem();
Constant operand2 = factory.createInt(length);
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, NEW_ARRAY, operand1, operand2);
break;
case INST_INVOKE_FINALLY >> 8:
int tlabel = readLabel();
jmap[cindex] = new int2[] { tlabel };
node = code.createAndAppendNode(root).setData(-1, INVOKE_FINALLY, null);
break;
case INST_INVOKE_STATIC >> 8:
case INST_INVOKE_STATICD >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int method = readIndex();
Callable operand1 = ((CallableElement) constants[method]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, INVOKE_STATIC, operand1);
if((encoded & FLAG_DISCARD) != 0) node.weak = true;
break;
case INST_INVOKE_SPECIAL >> 8:
case INST_INVOKE_SPECIALD >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int method = readIndex();
Callable operand1 = ((CallableElement) constants[method]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, INVOKE_SPECIAL, operand1);
if((encoded & FLAG_DISCARD) != 0) node.weak = true;
break;
case INST_INVOKE_VIRTUAL >> 8:
case INST_INVOKE_VIRTUALD >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int method = readIndex();
Callable operand1 = ((CallableElement) constants[method]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, INVOKE_VIRTUAL, operand1);
if((encoded & FLAG_DISCARD) != 0) node.weak = true;
break;
case INST_INVOKE_SERVICE >> 8:
case INST_INVOKE_SERVICED >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int method = readIndex();
Callable operand1 = ((CallableElement) constants[method]).getItem();
node = code.createAndAppendNode(root).setData(-1, null, INVOKE_SERVICE, operand1);
if((encoded & FLAG_DISCARD) != 0) node.weak = true;
break;
case INST_VECT_DIV >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_DIV, operand1, operand2);
break;
case INST_VECT_PCK >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_PCK, operand1);
break;
case INST_VECT_LUP >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_LUP, operand1);
break;
case INST_VECT_UUP >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_UUP, operand1);
break;
case INST_VECT_MUL >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_MUL, operand1, operand2);
break;
case INST_VECT_SHL >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SHL, operand1, operand2);
break;
case INST_VECT_SHR >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SHR, operand1, operand2);
break;
case INST_VECT_SHRU >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SHRU, operand1, operand2);
break;
case INST_VECT_ADD >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_ADD, operand1, operand2);
break;
case INST_VECT_SUB >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SUB, operand1, operand2);
break;
case INST_VECT_EQ >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_EQ, operand1, operand2);
break;
case INST_VECT_NE >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_NE, operand1, operand2);
break;
case INST_VECT_GT >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_GT, operand1, operand2);
break;
case INST_VECT_GE >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_GE, operand1, operand2);
break;
case INST_VECT_LT >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_LT, operand1, operand2);
break;
case INST_VECT_LE >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_LE, operand1, operand2);
break;
case INST_SCAL_DIV >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_DIV, operand1, operand2);
break;
case INST_SCAL_DIVU >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_DIVU, operand1, operand2);
break;
case INST_SCAL_REM >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_REM, operand1, operand2);
break;
case INST_SCAL_REMU >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_REMU, operand1, operand2);
break;
case INST_SCAL_MUL >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_MUL, operand1, operand2);
break;
case INST_SCAL_SHL >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_SHL, operand1, operand2);
break;
case INST_SCAL_SHR >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_SHR, operand1, operand2);
break;
case INST_SCAL_SHRU >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_SHRU, operand1, operand2);
break;
case INST_SCAL_ADD >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_ADD, operand1, operand2);
break;
case INST_SCAL_SUB >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_SUB, operand1, operand2);
break;
case INST_SCAL_EQ >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_EQ, operand1, operand2);
break;
case INST_SCAL_NE >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_NE, operand1, operand2);
break;
case INST_SCAL_GT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_GT, operand1, operand2);
break;
case INST_SCAL_GE >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_GE, operand1, operand2);
break;
case INST_SCAL_LT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_LT, operand1, operand2);
break;
case INST_SCAL_LE >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_LE, operand1, operand2);
break;
case INST_VECT_NEG >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_NEG, operand1);
break;
case INST_CAST_TO >> 8:
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
Type operand2 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, CAST_TO, operand1, operand2);
break;
case INST_INC_LOCAL >> 8:
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Type operand2 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, INC_LOCAL, operand1, operand2);
break;
case INST_DEC_LOCAL >> 8:
int local = readIndex();
Local operand1 = local <= 0 ? thisArgument : (Local) primLocals.operator []((String) constants[local]);
Type operand2 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, DEC_LOCAL, operand1, operand2);
break;
case INST_BIT_NOT >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, O_BIT_NOT, operand1);
break;
case INST_BIT_AND >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_BIT_AND, operand1, operand2);
break;
case INST_BIT_OR >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_BIT_OR, operand1, operand2);
break;
case INST_BIT_XOR >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_BIT_XOR, operand1, operand2);
break;
case INST_DUP1 >> 8:
Type operand1 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
node = code.createAndAppendNode(root).setData(-1, null, DUP1, operand1);
break;
case INST_DUP2 >> 8:
Type operand1 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
node = code.createAndAppendNode(root).setData(-1, null, DUP2, operand1);
break;
case INST_VECT_HMUL >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_HMUL, operand1, operand2);
break;
case INST_VECT_HMULU >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_HMULU, operand1, operand2);
break;
case INST_VECT_SADD >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SADD, operand1, operand2);
break;
case INST_VECT_SADDU >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SADDU, operand1, operand2);
break;
case INST_VECT_SSUB >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SSUB, operand1, operand2);
break;
case INST_VECT_SSUBU >> 8:
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, O_VECT_SSUBU, operand1, operand2);
break;
case INST_SCAL_NEG >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, O_SCAL_NEG, operand1);
break;
case INST_INSTANCE_OF >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, INSTANCEOF, operand1);
break;
case INST_TEST_EQZ >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, TEST_EQZ, operand1, operand2);
break;
case INST_TEST_NEZ >> 8:
hasBooleanJump = (encoded & FLAG_BOOLEAN_JUMP) != 0;
int operand = decodeOperand(encoded);
int index = operand == OPERAND_NONE ? -1 : readIndex();
Type operand1 = getPrimitiveType(decodeType(encoded));
TableItem operand2 = getAdditionalOperand(operand, primLocals, constants, index);
node = code.createAndAppendNode(root).setData(-1, null, TEST_NEZ, operand1, operand2);
break;
case INST_NEW_VECTOR >> 8:
Type operand1 = getPrimitiveType(decodeType(encoded));
node = code.createAndAppendNode(root).setData(-1, null, NEW_VECTOR, operand1);
break;
case INST_NEW_INSTANCE >> 8:
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, NEW_INSTANCE, operand1);
break;
case INST_NEW_ARRAY_MONO >> 8:
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, NEW_ARRAY_MONO, operand1);
break;
case INST_NEW_ARRAY_MULTI >> 8:
int type = readIndex();
Type operand1 = ((TypeElement) constants[type]).getItem();
operand1.makeCompilable();
node = code.createAndAppendNode(root).setData(-1, null, NEW_ARRAY_MULTI, operand1);
break;
case INST_DUP1X1 >> 8:
Type operand1 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
node = code.createAndAppendNode(root).setData(-1, null, DUP1X1, operand1);
break;
case INST_DUP1X2 >> 8:
Type operand1 = (decoded = decodeType(encoded)) == REF ? typeObject : getPrimitiveType(decoded);
node = code.createAndAppendNode(root).setData(-1, null, DUP1X2, operand1);
break;
case INST_METHOD_LEAVE >> 8:
node = code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
break;
case INST_EXCEPT_ENTER >> 8:
node = code.createAndAppendNode(root).setData(-1, EXCEPT_ENTER);
break;
case INST_EXCEPT_TRY >> 8:
int blabel = readLabel();
int elabel = readLabel();
jmap[cindex] = new int2[] { blabel, elabel };
node = code.createAndAppendNode(root).setData(-1, EXCEPT_TRY, null, null);
break;
case INST_EXCEPT_CATCH >> 8:
int blabel = readLabel();
int type = readIndex();
Type operand2 = ((TypeElement) constants[type]).getItem();
jmap[cindex] = new int2[] { blabel };
node = code.createAndAppendNode(root).setData(-1, EXCEPT_CATCH, null, operand2);
break;
case INST_EXCEPT_FINALLY >> 8:
int blabel = readLabel();
jmap[cindex] = new int2[] { blabel };
node = code.createAndAppendNode(root).setData(-1, EXCEPT_FINALLY, null);
break;
case INST_EXCEPT_LEAVE >> 8:
node = code.createAndAppendNode(root).setData(-1, EXCEPT_LEAVE);
}
if(hasBooleanJump)
{
int tlabel = readLabel();
int flabel = readLabel();
jmap[cindex] = new int2[] { flabel, tlabel };
}
node.location = new int2 { lineIndex, -1 };
if((node.debugIndex = debugIndex) >= 0)
{
if(debugIndex >= dlength)
{
int capacity = getBestArrayCapacity(debugIndex + 1);
Array.copy(debugs, 0, debugs = new Node[capacity], 0, dlength);
dlength = capacity;
}
debugs[debugIndex] = node;
}
if((node.labelIndex = labelIndex) >= 0)
{
if(labelIndex >= llength)
{
int capacity = getBestArrayCapacity(labelIndex + 1);
Array.copy(labels, 0, labels = new Node[capacity], 0, llength);
llength = capacity;
}
labels[labelIndex] = node;
}
code.assignOrder(node, cindex);
}
/* расстановка переходов */
for(Node next = null, int cindex = root.length; cindex-- > 0; )
{
Node node = root[cindex];
switch(node.instruction)
{
case BRANCH:
int2[] jumps = jmap[cindex];
int jlength = jumps.length - 1;
for(int jindex = 0; jindex < jlength; jindex++)
{
int2 jcase = jumps[jindex];
int jlabel = jcase[0];
node.setJumpCase(jcase[1], jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel]);
}
{
int2 jcase = jumps[jlength];
int jlabel = jcase[0];
node.jumpDefault = jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel];
}
break;
case JUMP:
int jlabel = jmap[cindex][0][0];
node.jumpDefault = jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel];
break;
case EXCEPT_CATCH:
case EXCEPT_FINALLY:
case INVOKE_FINALLY:
int jlabel = jmap[cindex][0][0];
node.reference1 = jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel];
break;
case EXCEPT_TRY:
int2[] jumps = jmap[cindex];
{
int jlabel = jumps[0][0];
node.reference1 = jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel];
}
{
int jlabel = jumps[1][0];
node.reference2 = jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel];
}
break;
default:
int2[] jumps = jmap[cindex];
if(jumps == null)
{
break;
}
{
int jlabel = jumps[0][0];
node.jumpIsFalse = jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel];
}
{
int jlabel = jumps[1][0];
node.jumpIsTrue = jlabel == NEXT ? next : jlabel < 0 ? debugs[~jlabel] : labels[jlabel];
}
}
next = node;
}
}
}
final void parseCallableBody(Callable callable) throws TextSourceException {
Code code = callable.code;
ClassType enclosing = callable.parentType;
TextSource source = (TextSource) callable.source;
if(source != null && callable.specialSimpleName.indexOf('.') < 0)
{
int position = callable.implementationPosition;
label0:
{
label1:
{
if(callable instanceof InstInit)
{
/* --- конструктор (метод инициализации объекта), добавленный компилятором --- */
if(position < 0)
{
position = enclosing.declarationPosition;
ClassType superclass = enclosing.getSuperclassType();
if(superclass == null)
{
/* вставка пустого тела */
Node root = code.root.setData(-1, METHOD_ENTER, null);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
break label0;
}
/* вставка инструкции вызова конструктора из суперкласса */
InstInit superconstructor = (InstInit) superclass.getChildCallable(SPECNAME_INST_INIT, (Type[]) null);
if(superconstructor == null)
{
throw new TextSourceException(String.format(
package.getResourceString("required-explicit-constructor.no-default-constructor"), new Object[] { superclass.specialCanonicalName + ArgumentArray.toString(null) }
)) { source = source, position = position };
}
if(!superconstructor.isVisibleFrom(enclosing, enclosing))
{
throw new TextSourceException(String.format(
package.getResourceString("required-explicit-constructor.invisible-default-constructor"), new Object[] { superconstructor, enclosing.specialSimpleName }
)) { source = source, position = position };
}
ClassType type = getUnhandledException(superconstructor, null, callable);
if(type != null)
{
throw new TextSourceException(String.format(
package.getResourceString("required-explicit-constructor.unhandled-exception"), new Object[] { superconstructor, type }
)) { source = source, position = position };
}
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node constructor = code.createAndPrependNode(root).setData(-1, null, INVOKE_SPECIAL, superconstructor);
code.createAndPrependNode(constructor).setData(-1, superclass, LOAD_LOCAL, callable.arguments.thisArgument);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
break label0;
}
/* --- конструктор (метод инициализации объекта), написанный в исходном коде --- */
if(source.getLexemeKind(position) != COLON)
{
ClassType superclass = enclosing.getSuperclassType();
if(superclass != null)
{
/* вставка инструкции вызова конструктора из суперкласса */
InstInit superconstructor = (InstInit) superclass.getChildCallable(SPECNAME_INST_INIT, (Type[]) null);
if(superconstructor == null)
{
throw new TextSourceException(String.format(
package.getResourceString("required-explicit-constructor.no-default-constructor"),
new Object[] { superclass.specialCanonicalName + ArgumentArray.toString(null) }
)) { source = source, position = position };
}
if(!superconstructor.isVisibleFrom(enclosing, enclosing))
{
throw new TextSourceException(String.format(
package.getResourceString("required-explicit-constructor.invisible-default-constructor"), new Object[] { superconstructor, enclosing.specialSimpleName }
)) { source = source, position = position };
}
ClassType type = getUnhandledException(superconstructor, null, callable);
if(type != null)
{
throw new TextSourceException(String.format(
package.getResourceString("required-explicit-constructor.unhandled-exception"), new Object[] { superconstructor, type }
)) { source = source, position = position };
}
Node constructor = code.createAndPrependNode(null).setData(-1, null, INVOKE_SPECIAL, superconstructor);
code.createAndPrependNode(constructor).setData(-1, superclass, LOAD_LOCAL, callable.arguments.thisArgument);
}
break label1;
}
/* вставка вызова другого конструктора из этого класса или суперкласса */
ClassType place;
switch(source.getLexemeKind(++position))
{
case SUPER:
place = enclosing.getSuperclassType();
break;
case THIS:
place = enclosing;
break;
default:
throw new TextSourceException(package.getResourceString("expected.super-or-this")) { source = source, position = position };
}
if(place == null)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-use.super"), new Object[] { enclosing.specialSimpleName }
)) { source = source, position = position };
}
int before = position;
if(source.getLexemeKind(++position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
Node constructor = code.createAndPrependNode(null);
label2: if(source.getLexemeKind(++position) != PARENTH_CLOSED) do
{
position = parseExpression(constructor, source, position, true);
requiresValue(constructor[-1]);
switch(source.getLexemeKind(position))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
case PARENTH_CLOSED:
break label2;
case COMMA:
position++;
}
} while(true);
position++;
int length = constructor.length;
Type[] arguments = new Type[length];
for(int index = 0; index < length; index++) arguments[index] = constructor[index].type;
InstInit[] foundConstructors = place.findConstructors(arguments, enclosing);
int foundLength = foundConstructors == null ? 0 : foundConstructors.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("not-found.constructor"),
new Object[] { place == enclosing ? place.specialSimpleName : place.specialCanonicalName, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
InstInit foundConstructor = foundConstructors[0];
if(!foundConstructor.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.constructor"), new Object[] { foundConstructor, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundConstructor.isVisibleFrom(enclosing, enclosing))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.constructor"), new Object[] { enclosing.specialSimpleName, foundConstructor }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.constructor"),
new Object[] { (place == enclosing ? place.specialSimpleName : place.specialCanonicalName) + foundConstructor.arguments.toString() }
)) { source = source, position = before };
}
for(ArgumentArray foundArguments = foundConstructor.arguments, int index = 0; index < length; index++) cast(constructor[index], foundArguments[index].type);
code.createAndPrependNode(constructor).setData(before, place, LOAD_LOCAL, callable.arguments.thisArgument);
constructor.setData(before, null, INVOKE_SPECIAL, foundConstructor);
break label1;
}
if(callable instanceof ClassInit)
{
/* --- статичный блок (метод инициализации типа), добавленный компилятором --- */
if(position < 0)
{
position = enclosing.declarationPosition;
Node root = code.root.setData(-1, METHOD_ENTER, null);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
break label0;
}
/* --- статичный блок (метод инициализации типа), написанный в исходном коде --- */
break label1;
}
if(code == null)
{
/* --- абстрактный или родной метод --- */
if(source.getLexemeKind(position) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
return;
}
}
/* чтение тела метода */
if(source.getLexemeKind(position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
Node root = code.root.setData(position, METHOD_ENTER, null);
label1: if(source.getLexemeKind(++position) != CURLY_CLOSED) do
{
switch(source.getLexemeKind(position = parseControl(root, source, position)))
{
case L_END:
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
case CURLY_CLOSED:
break label1;
}
} while(true);
code.createAndAppendNode(root).setData(position, METHOD_LEAVE);
}
/* проверка обязательной обработки исключений */
label0: for(Node node = code.root, Node parent = null, int index = -1; ; )
{
label1: switch(node.instruction)
{
case INVOKE_STATIC:
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
case INVOKE_SERVICE:
ClassType type = null;
TableItem item = node.operand1;
if(item instanceof Method && (type = getUnhandledException((Method) item, parent, callable)) != null)
{
throw new TextSourceException(String.format(package.getResourceString("unhandled-exception"), new Object[] { type })) { source = source, position = node.position };
}
break;
case THROW:
ClassType type = (ClassType) node.reference1;
if(!type.isFreeThrowableType() && !isHandledException(type, parent, callable))
{
throw new TextSourceException(String.format(package.getResourceString("unhandled-exception"), new Object[] { type })) { source = source, position = node.position };
}
}
if(node.length > 0)
{
node = (parent = node)[index = 0];
continue;
}
if(parent == null)
{
break;
}
if(++index < parent.length)
{
node = parent[index];
continue;
}
do
{
index = parent.index + 1;
if((parent = parent.parentNode) == null)
{
break label0;
}
if(index < parent.length)
{
node = parent[index];
break;
}
} while(true);
}
}
/* подготовка к дальнейшей работе с кодом */
if(code == null) return;
Node root = code.root;
Node exit = root[-1];
Constant constTrue = fldTrue;
Constant constFalse = fldFalse;
ClassType typeObject = fldTypeObject;
PrimitiveType typeBoolean = fldTypeBoolean;
/* обёртывание тела статичного блока специальными инструкциями */
if(callable instanceof ClassInit)
{
enclosing.makeCompilable();
Node control = code.createAndPrependNode(root).setData(-1, IF);
code.createAndAppendNode(control).setData(-1, typeBoolean, CLINIT_TRY_LOCK, enclosing);
Node blockTry = code.createAndAppendNode(control).setData(-1, TRY);
Node cover = code.createAndAppendNode(blockTry).setData(-1, BEGIN);
Node blockFinally = code.createAndAppendNode(blockTry).setData(-1, FINALLY_ENTER);
code.createAndAppendNode(blockFinally).setData(-1, null, CLINIT_UNLOCK, enclosing);
code.createAndAppendNode(blockFinally).setData(-1, FINALLY_LEAVE).special = true;
blockTry = code.createAndAppendNode(cover).setData(-1, END);
code.createAndAppendNode(blockTry).setData(-1, INVOKE_FINALLY, blockFinally).special = true;
code.createAndAppendNode(blockTry).setData(-1, JUMP).special = true;
for(int index = root.length - 1; index-- > 1; ) code.moveNode(root[index], cover, 0);
}
/* обёртывание синхронизированного метода специальными инструкциями */
if(callable.isSynchronized())
{
Local monitor = code.createMonitorLocal(typeObject, !callable.isStatic() ? null : fldConstantFactory.createClass(enclosing));
Node control = code.createAndPrependNode(root).setData(-1, BLOCK);
Node declare = code.createAndAppendNode(control).setData(-1, null, DECLARE_LOCAL, monitor);
Constant value = monitor.value;
boolean isConstant = monitor.isConstant();
if(!isConstant)
{
code.createAndAppendNode(declare).setData(-1, typeObject, LOAD_LOCAL, callable.arguments.thisArgument);
}
Node enter = code.createAndAppendNode(control).setData(-1, MONITOR_ENTER);
if(isConstant)
{
code.createAndAppendNode(enter).setData(-1, typeObject, LOAD_CONST, value);
} else
{
code.createAndAppendNode(enter).setData(-1, typeObject, LOAD_LOCAL, monitor);
}
Node blockTry = code.createAndAppendNode(control).setData(-1, TRY);
Node cover = code.createAndAppendNode(blockTry).setData(-1, BEGIN);
Node blockFinally = code.createAndAppendNode(blockTry).setData(-1, FINALLY_ENTER);
Node leave = code.createAndAppendNode(blockFinally).setData(-1, MONITOR_LEAVE);
if(isConstant)
{
code.createAndAppendNode(leave).setData(-1, typeObject, LOAD_CONST, value);
} else
{
code.createAndAppendNode(leave).setData(-1, typeObject, LOAD_LOCAL, monitor);
}
code.createAndAppendNode(blockFinally).setData(-1, FINALLY_LEAVE).special = true;
blockTry = code.createAndAppendNode(cover).setData(-1, END);
code.createAndAppendNode(blockTry).setData(-1, INVOKE_FINALLY, blockFinally).special = true;
code.createAndAppendNode(blockTry).setData(-1, JUMP).special = true;
for(int index = root.length - 1; index-- > 1; ) code.moveNode(root[index], cover, 0);
}
/* вставка инструкций обработки исключений, дополнительных узлов, а также оптимизация кода */
label0: for(code.createAndPrependNode(exit).setData(-1, EXCEPT_LEAVE), boolean isNeedExceptEnter = false, Node node = root, Node parent = null, int pindex = -1; ; )
{
if(node == exit)
{
if(isNeedExceptEnter) code.createAndPrependNode(exit).setData(-1, EXCEPT_ENTER);
break;
}
label1:
{
int instruction = node.instruction;
label2: switch(instruction)
{
case METHOD_ENTER:
if(callable.visibility > PRIVATE && (callable.isStatic() || callable instanceof InstInit))
{
ClassInit block = enclosing.getStaticBlock();
if(block != null && block != callable) code.createAndPrependNode(node).setData(node.position, null, INVOKE_STATIC, block);
}
break;
case TRY:
for(isNeedExceptEnter = true, int nindex = node.length; nindex-- > 0; )
{
Node subblock = node[nindex];
switch(subblock.instruction)
{
case FINALLY_ENTER:
subblock.persistent = true;
code.createAndPrependNode(exit).setData(-1, EXCEPT_FINALLY, subblock);
break;
case CATCH:
Node markable = subblock[0];
markable.persistent = true;
code.createAndPrependNode(exit).setData(-1, EXCEPT_CATCH, markable, subblock.reference1);
break;
case BEGIN:
Node markable = subblock[-1];
subblock.persistent = true;
markable.persistent = true;
code.createAndPrependNode(exit).setData(-1, EXCEPT_TRY, subblock, markable);
}
}
break;
case BREAK:
case RETURN:
case CONTINUE:
int position = node.position;
for(Object target = node.reference1, Node control = parent; control != null && control != target; control = control.parentNode)
{
Node block = control[-1];
if(control.instruction == TRY && block.instruction == FINALLY_ENTER) code.createAndAppendNode(node).setData(position, INVOKE_FINALLY, block);
}
if(instruction != RETURN)
{
code.createAndAppendNode(node).setData(position, JUMP);
}
break;
case BOOL_COND:
if(!node.type.isBoolean())
{
code.createAndInsertNode(node, 2).setData(-1, JUMP);
break;
}
/* падение через */
case BOOL_OR:
case BOOL_AND:
case BOOL_NOT:
switch(parent.instruction)
{
case IF:
if(pindex != 0) break;
break label2;
case DO:
case FOR:
case WHILE:
if(pindex != parent.length - 1) break;
break label2;
case BOOL_OR:
case BOOL_AND:
case BOOL_NOT:
case BOOL_COND:
break label2;
}
if(instruction == BOOL_COND && !isLogicalConditionNode(node))
{
code.createAndInsertNode(node, 2).setData(-1, JUMP);
break;
}
Node cover = code.createAndInsertNode(parent, pindex).setData(-1, typeBoolean, BOOL_COND);
code.moveNode(node, node = cover, 0);
code.createAndAppendNode(cover).setData(-1, typeBoolean, LOAD_CONST, constTrue);
code.createAndAppendNode(cover).setData(-1, JUMP);
code.createAndAppendNode(cover).setData(-1, typeBoolean, LOAD_CONST, constFalse);
break;
case REF_EQ:
case REF_NE:
Node child;
Node relation1 = node[0];
Node relation2 = node[1];
label3:
{
if(relation1.instruction == LOAD_CONST && ((Constant) relation1.operand1).isNull())
{
node.instruction = instruction + (REF_IS_NULL - REF_EQ);
code.removeNode(relation1);
child = relation2;
break label3;
}
if(relation2.instruction == LOAD_CONST && ((Constant) relation2.operand1).isNull())
{
node.instruction = instruction + (REF_IS_NULL - REF_EQ);
code.removeNode(relation2);
child = relation1;
break label3;
}
break;
}
if((instruction = child.instruction) == LOAD_STATIC || instruction == LOAD_LOCAL || instruction == LOAD_CONST && !((Constant) child.operand1).isString())
{
node.weak = child.weak = true;
}
break;
case O_SCAL_EQ:
case O_SCAL_NE:
if(((Type) node.operand1).isLong())
{
Node relation1 = node[0];
Node relation2 = node[1];
if(relation1.instruction == O_BIT_AND && relation2.instruction == LOAD_CONST && ((Constant) relation2.operand1).isDefaultValue())
{
node.instruction = instruction + (TEST_EQZ - O_SCAL_EQ);
code.moveNode(relation1[0], node, 0);
code.moveNode(relation1[0], node, 1);
code.removeNode(relation1);
code.removeNode(relation2);
break;
}
if(relation2.instruction == O_BIT_AND && relation1.instruction == LOAD_CONST && ((Constant) relation1.operand1).isDefaultValue())
{
node.instruction = instruction + (TEST_EQZ - O_SCAL_EQ);
code.moveNode(relation2[0], node, 0);
code.moveNode(relation2[0], node, 1);
code.removeNode(relation1);
code.removeNode(relation2);
}
}
break;
case LOAD_STATIC:
ClassType type = ((Member) node.operand1).parentType;
if(enclosing != type)
{
ClassInit block = type.getStaticBlock();
if(block != null)
{
code.createAndPrependNode(node).setData(node.position, null, INVOKE_STATIC, block);
break;
}
}
/* падение через */
case LOAD_LOCAL:
case LOAD_CONST:
if(pindex == parent.length - 1)
{
switch(parent.instruction)
{
default:
break label2;
case STORE_LOCAL:
case STORE_STATIC:
case DECLARE_WITH:
case DECLARE_LOCAL:
if(pindex == 0 && instruction == LOAD_CONST)
{
Constant value = (Constant) node.operand1;
Type type = value.type;
if(type.isInt() || type.isBoolean() || value.isNull())
{
parent.operand2 = value;
break;
}
}
break label2;
case REF_EQ:
case REF_NE:
if(instruction == LOAD_CONST && ((Constant) node.operand1).isString()) break label2;
Node child = parent[0];
if((instruction = child.instruction) == LOAD_STATIC || instruction == LOAD_LOCAL || instruction == LOAD_CONST && !((Constant) child.operand1).isString())
{
parent.weak = child.weak = true;
}
parent.operand1 = node.operand1;
break;
case READ_ELEMENT:
if(instruction != LOAD_CONST) break label2;
parent.operand2 = node.operand1;
break;
case READ_FIELD:
case READ_SPECIAL:
case READ_PROPERTY:
if(instruction == LOAD_CONST && ((Constant) node.operand1).isString()) break label2;
/* падение через */
case READ_COMPONENT:
case TEST_EQZ:
case TEST_NEZ:
case O_BIT_AND:
case O_BIT_OR:
case O_BIT_XOR:
case O_SCAL_MUL:
case O_SCAL_DIV:
case O_SCAL_DIVU:
case O_SCAL_REM:
case O_SCAL_REMU:
case O_SCAL_ADD:
case O_SCAL_SUB:
case O_SCAL_SHR:
case O_SCAL_SHRU:
case O_SCAL_SHL:
case O_SCAL_GT:
case O_SCAL_GE:
case O_SCAL_LT:
case O_SCAL_LE:
case O_SCAL_EQ:
case O_SCAL_NE:
case O_VECT_MUL:
case O_VECT_DIV:
case O_VECT_ADD:
case O_VECT_SUB:
case O_VECT_SHR:
case O_VECT_SHRU:
case O_VECT_SHL:
case O_VECT_GT:
case O_VECT_GE:
case O_VECT_LT:
case O_VECT_LE:
case O_VECT_EQ:
case O_VECT_NE:
case O_VECT_HMUL:
case O_VECT_HMULU:
case O_VECT_SADD:
case O_VECT_SADDU:
case O_VECT_SSUB:
case O_VECT_SSUBU:
parent.operand2 = node.operand1;
}
code.removeNode(node);
pindex--;
break label1;
}
}
if(node.length > 0)
{
node = (parent = node)[pindex = 0];
continue;
}
if(parent == null) break;
}
if(++pindex < parent.length)
{
node = parent[pindex];
continue;
}
do
{
pindex = parent.index + 1;
if((parent = parent.parentNode) == null)
{
break label0;
}
if(pindex < parent.length)
{
node = parent[pindex];
break;
}
} while(true);
}
/* нумерация узлов */
label0: for(code.assignOrder(root, 0), Node node = root, Node parent = null, int pindex = -1; ; )
{
int order = node.order;
switch(node.instruction)
{
case NOP:
case IF:
case SWITCH:
case CASE:
case DEFAULT:
case LABEL:
case DO:
case FOR:
case WHILE:
case BLOCK:
case BREAK:
case CONTINUE:
case TRY:
case CATCH:
case BOOL_OR:
case BOOL_AND:
case BOOL_NOT:
case BOOL_COND:
/* нумеруются только дочерние узлы, этот узел не нумеруется */
for(code.clearOrder(node), int nlength = node.length, int nindex = 0; nindex < nlength; nindex++)
{
code.assignOrder(node[nindex], order++);
}
break;
case BEGIN:
case FINALLY_ENTER:
case METHOD_ENTER:
case METHOD_LEAVE:
case NEW_ARRAY:
case NEW_INSTANCE:
/* сперва нумеруется этот узел, а затем — дочерние узлы */
for(int nlength = node.length, int nindex = 0; nindex < nlength; nindex++)
{
code.assignOrder(node[nindex], ++order);
}
break;
case DECLARE_WITH:
case DECLARE_LOCAL:
/* не нумеруется узел с объявлением локальной константы */
if(node.isEmpty() && ((Local) node.operand1).isConstant())
{
code.clearOrder(node);
}
/* падение через */
default:
/* сперва нумеруются дочерние узлы, а затем — этот узел */
for(int nlength = node.length, int nindex = 0; nindex < nlength; nindex++)
{
code.assignOrder(node[nindex], order++);
}
}
if(node.length > 0)
{
node = (parent = node)[pindex = 0];
continue;
}
if(parent == null)
{
break;
}
if(++pindex < parent.length)
{
node = parent[pindex];
continue;
}
do
{
pindex = parent.index + 1;
if((parent = parent.parentNode) == null)
{
break label0;
}
if(pindex < parent.length)
{
node = parent[pindex];
break;
}
} while(true);
}
/* расстановка переходов и замена условных переходов по константам типа boolean на безусловные переходы */
label0: for(Node node = root, Node parent = null, int pindex = -1; ; )
{
switch(node.instruction)
{
case IF:
boolean hasElse = node.length > 3;
int after = node.maxOrder() + 1;
int isTrue = node[1].minOrder();
int isFalse = !hasElse ? after : node[3].minOrder();
if(isTrue < 0) isTrue = after;
if(isFalse < 0) isFalse = after;
with(node[0])
{
jumpIsTrue = code[isTrue];
jumpIsFalse = code[isFalse];
}
if(hasElse)
{
node[2].jumpDefault = code[after];
}
break;
case SWITCH:
int after = node.maxOrder() + 1;
with(node[0]) for(int nindex = node.length; nindex-- > 1; )
{
Node subnode = node[nindex];
int isCase = subnode.minOrder();
if(isCase < 0)
{
isCase = after;
} else
{
after = isCase;
}
if(subnode.instruction == CASE)
{
setJumpCase(((Int) subnode.reference1).intValue, code[isCase]);
continue;
}
jumpDefault = code[isCase];
}
break;
case DO:
int after = node.maxOrder() + 1;
int isTrue = node[-2].minOrder();
with(node[-1])
{
if(isTrue < 0) isTrue = minOrder();
jumpIsTrue = code[isTrue];
jumpIsFalse = code[after];
}
break;
case FOR:
int after = node.maxOrder() + 1;
int isTrue = node[-3].minOrder();
with(node[-1])
{
int condition = minOrder();
if(isTrue < 0 && (isTrue = node[-2].minOrder()) < 0) isTrue = condition;
node[-4].jumpDefault = code[condition];
jumpIsTrue = code[isTrue];
jumpIsFalse = code[after];
}
break;
case WHILE:
int after = node.maxOrder() + 1;
int isTrue = node[-2].minOrder();
with(node[-1])
{
int condition = minOrder();
if(isTrue < 0) isTrue = condition;
node[-3].jumpDefault = code[condition];
jumpIsTrue = code[isTrue];
jumpIsFalse = code[after];
}
break;
case BREAK:
node[-1].jumpDefault = code.operator [](((Node) node.reference1).maxOrder() + 1);
break;
case CONTINUE:
int condition;
Node target = (Node) node.reference1;
if(target.instruction != FOR)
{
condition = target[-1].minOrder();
} else
{
int step = target[-2].minOrder();
condition = step >= 0 ? step : target[-1].minOrder();
}
node[-1].jumpDefault = code[condition];
break;
case RETURN:
node.jumpDefault = exit;
break;
case TRY:
for(Node after = code.operator [](node.maxOrder() + 1), node[0][-1][-1].jumpDefault = after, int nindex = node.length - 1; nindex-- > 1; )
{
node[nindex][-1].jumpDefault = after;
}
break;
case BOOL_OR:
Node isTrue = node.jumpIsTrue;
Node isFalse = node.jumpIsFalse;
Node subnode0 = node[0];
Node subnode1 = node[1];
subnode0.jumpIsTrue = isTrue;
subnode0.jumpIsFalse = code.operator [](subnode1.minOrder());
subnode1.jumpIsTrue = isTrue;
subnode1.jumpIsFalse = isFalse;
node.jumpIsTrue = null;
node.jumpIsFalse = null;
break;
case BOOL_AND:
Node isTrue = node.jumpIsTrue;
Node isFalse = node.jumpIsFalse;
Node subnode0 = node[0];
Node subnode1 = node[1];
subnode0.jumpIsTrue = code.operator [](subnode1.minOrder());
subnode0.jumpIsFalse = isFalse;
subnode1.jumpIsTrue = isTrue;
subnode1.jumpIsFalse = isFalse;
node.jumpIsTrue = null;
node.jumpIsFalse = null;
break;
case BOOL_NOT:
Node isTrue = node.jumpIsTrue;
Node isFalse = node.jumpIsFalse;
with(node[0])
{
jumpIsTrue = isFalse;
jumpIsFalse = isTrue;
}
node.jumpIsTrue = null;
node.jumpIsFalse = null;
break;
case BOOL_COND:
Node isTrue = node.jumpIsTrue;
Node isFalse = node.jumpIsFalse;
Node branchTrue = node[1];
Node branchFalse = node[-1];
with(node[0])
{
jumpIsTrue = code.operator [](branchTrue.minOrder());
jumpIsFalse = code.operator [](branchFalse.minOrder());
}
if(isTrue == null || isFalse == null)
{
node[2].jumpDefault = code.operator [](node.maxOrder() + 1);
} else
{
branchTrue.jumpIsTrue = branchFalse.jumpIsTrue = isTrue;
branchTrue.jumpIsFalse = branchFalse.jumpIsFalse = isFalse;
}
node.jumpIsTrue = null;
node.jumpIsFalse = null;
break;
case LOAD_CONST:
Node isTrue = node.jumpIsTrue;
Node isFalse = node.jumpIsFalse;
Constant value = (Constant) node.operand1;
if(value.isBoolean() && isTrue != null && isFalse != null)
{
node.setData(node.position, JUMP);
node.clearJumpCases();
node.jumpDefault = value.asBoolean() ? isTrue : isFalse;
}
break;
case METHOD_LEAVE:
node.special = true;
/* падение через */
case THROW:
case FINALLY_LEAVE:
node.endPoint = true;
}
if(node.length > 0)
{
node = (parent = node)[pindex = 0];
continue;
}
if(parent == null)
{
break;
}
if(++pindex < parent.length)
{
node = parent[pindex];
continue;
}
do
{
pindex = parent.index + 1;
if((parent = parent.parentNode) == null)
{
break label0;
}
if(pindex < parent.length)
{
node = parent[pindex];
break;
}
} while(true);
}
/* проверка и оптимизация связности кода */
{
int clength = code.length;
byte[] attainability = new byte[clength];
/* проверка наличия недостижимых узлов и отмена нумерации для специальных из них */
{
Node unattained = null;
defineAttainability(attainability, code, clength);
for(int cindex = clength - 1; cindex >= 0 && (cindex = Array.lastIndexOf(0, attainability, cindex, 0)) >= 0; )
{
Node node = code[cindex--];
if(!node.special || node.instruction == BEGIN)
{
unattained = node;
continue;
}
if(!node.persistent)
{
clength--;
code.clearOrder(node);
}
}
if(unattained != null) do
{
int position = unattained.position;
if(position >= 0)
{
throw new TextSourceException(package.getResourceString("detected.unreachable-code")) { source = source, position = position };
}
if(unattained.instruction == JUMP)
{
unattained = unattained.jumpDefault;
continue;
}
unattained = code[unattained.order + 1];
} while(true);
}
/* проверка обязательного возвращения значения */
if(!callable.type.isVoid()) for(int cindex = clength; cindex-- > 0; )
{
Node node = code[cindex];
if(node.instruction != RETURN && node.hasJumpsTo(exit))
{
throw new TextSourceException(package.getResourceString("required.return")) { source = source, position = exit.position };
}
}
/* оптимизация переходов, отмена нумерации для узлов — переходов на следующий по номеру узел */
for(Node[] jumps = new Node[0x0f], int jlength = 0, int cindex = clength; cindex-- > 0; )
{
Node node = code[cindex];
int instruction = node.instruction;
int jindex = node.getJumpCasesLength();
if(instruction != JUMP && instruction != RETURN)
{
if(instruction == BEGIN) node.position = -1;
if(jindex <= 0) continue;
jlength = 0;
} else
{
Node target = node.jumpDefault;
if(target.order == node.order + 1)
{
clength--;
code.clearOrder(node);
code.replaceJumpNode(node, target);
continue;
}
jlength = 1;
jumps[0] = node;
}
while(jindex-- > -1)
{
Node target = jindex < 0 ? node.jumpDefault : node.getJumpCaseNodeAt(jindex);
if(target != null)
{
while(((instruction = target.instruction) == RETURN || instruction == JUMP) && (jlength <= 0 || Array.indexOf(target, jumps, 0, jlength) < 0))
{
if(jlength == jumps.length) Array.copy(jumps, 0, jumps = new Node[jlength << 1 | 1], 0, jlength);
jumps[jlength++] = target;
target = target.jumpDefault;
}
if(jindex < 0)
{
node.jumpDefault = target;
continue;
}
node.setJumpCase(node.getJumpCaseValueAt(jindex), target);
}
}
}
/* отмена нумерации для недостижимых узлов, возможно образовавшихся в результате оптимизации переходов */
{
Array.fill(attainability, 0, clength, 0);
defineAttainability(attainability, code, clength);
for(int cindex = clength - 1; cindex >= 0 && (cindex = Array.lastIndexOf(0, attainability, cindex, 0)) >= 0; )
{
Node node = code[cindex--];
if(!node.persistent) code.clearOrder(node);
}
}
}
/* массив инструкций */
Node[] list = code.clone();
int clength = list.length;
/* расстановка меток */
{
for(Node next = null, int cindex = clength; cindex-- > 0; )
{
Node node = list[cindex];
if(node.persistent)
{
node.labelIndex = 0;
}
for(int jindex = node.getJumpCasesLength(); jindex-- > -1; )
{
Node target = jindex < 0 ? node.jumpDefault : node.getJumpCaseNodeAt(jindex);
if(target != null && target != next) target.labelIndex = 0;
}
next = node;
}
for(int labelIndex = 0, int lastIndex = -1, int cindex = 0; cindex < clength; cindex++)
{
Node node = list[cindex];
int lineIndex = (int) node.location;
if(lineIndex >= 0 && lastIndex != lineIndex)
{
node.labelIndex = -1;
node.debugIndex = code.createDebugIndex(lineIndex);
lastIndex = lineIndex;
continue;
}
if(node.labelIndex == 0) node.labelIndex = labelIndex++;
}
}
/* определение максимального количества занимаемых элементов стака */
{
ElementStack stack = new ElementStack();
for(int cindex = 1; cindex < clength; cindex++)
{
Node node = list[cindex];
int stackElements = node.stackElements;
if(stackElements >= 0)
{
stack.stackElements = stackElements;
}
switch(node.instruction)
{
default:
continue;
case INSTANCEOF:
case REF_IS_NULL:
case REF_IS_OBJECT:
break;
case RETURN:
case METHOD_LEAVE:
stack.reset();
continue;
case THROW:
case BRANCH:
case FINALLY_LEAVE:
case MONITOR_ENTER:
case MONITOR_LEAVE:
stack.change(-1);
continue;
case CLINIT_TRY_LOCK:
stack.change(+1);
break;
case NEW_ARRAY:
case NEW_INSTANCE:
case FINALLY_ENTER:
case LOAD_INTERRUPT:
stack.change(+1);
continue;
case LOAD_CONST:
case LOAD_LOCAL:
case LOAD_STATIC:
stack.change(((TypedItem) node.operand1).type.stackElements);
break;
case INC_PRED_LOAD_LOCAL:
case DEC_PRED_LOAD_LOCAL:
case INC_POST_LOAD_LOCAL:
case DEC_POST_LOAD_LOCAL:
stack.change(((TypedItem) node.operand1).type.stackElements);
continue;
case READ_ELEMENT:
stack.change((node.operand2 == null ? +0 : +1) - ((Type) node.operand1).stackElements);
continue;
case READ_COMPONENT:
stack.change((node.operand2 == null ? -2 : -1) + ((Type) node.operand1).stackElements);
break;
case READ_FIELD:
case READ_SPECIAL:
case READ_PROPERTY:
stack.change((node.operand2 == null ? -1 : +0) + ((TypedItem) node.operand1).type.stackElements);
break;
case DUP1:
case DUP1X1:
case DUP1X2:
stack.change(((Type) node.operand1).stackElements);
continue;
case DUP2:
stack.change(((Type) node.operand1).stackElements + 1);
continue;
case INVOKE_STATIC:
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
case INVOKE_SERVICE:
Callable method = (Callable) node.operand1;
stack.change((node.weak ? +0 : method.type.stackElements) - method.arguments.stackElements);
break;
case NEW_VECTOR:
PrimitiveType type = (PrimitiveType) node.operand1;
stack.change(type.stackElements - type.vectorLength);
continue;
case CAST_TO:
stack.change(((Type) node.operand1).stackElements - ((Type) node.operand2).stackElements);
continue;
case REF_EQ:
case REF_NE:
stack.change(node.operand1 != null ? +0 : -1);
break;
case TEST_EQZ:
case TEST_NEZ:
stack.change(node.operand2 != null ? +0 : -1);
break;
case O_BIT_OR:
case O_BIT_AND:
case O_BIT_XOR:
stack.change(node.operand2 != null ? +0 : -((Type) node.operand1).stackElements);
break;
case O_SCAL_MUL:
case O_SCAL_DIV:
case O_SCAL_DIVU:
case O_SCAL_REM:
case O_SCAL_REMU:
case O_SCAL_ADD:
case O_SCAL_SUB:
case O_VECT_MUL:
case O_VECT_DIV:
case O_VECT_ADD:
case O_VECT_SUB:
case O_VECT_EQ:
case O_VECT_NE:
case O_VECT_GT:
case O_VECT_GE:
case O_VECT_LT:
case O_VECT_LE:
case O_VECT_HMUL:
case O_VECT_HMULU:
case O_VECT_SADD:
case O_VECT_SADDU:
case O_VECT_SSUB:
case O_VECT_SSUBU:
stack.change(node.operand2 != null ? +0 : -((Type) node.operand1).stackElements);
continue;
case O_SCAL_SHR:
case O_SCAL_SHRU:
case O_SCAL_SHL:
case O_VECT_SHR:
case O_VECT_SHRU:
case O_VECT_SHL:
stack.change(node.operand2 != null ? +0 : -1);
continue;
case O_SCAL_EQ:
case O_SCAL_NE:
case O_SCAL_GT:
case O_SCAL_GE:
case O_SCAL_LT:
case O_SCAL_LE:
stack.change(1 - (((Type) node.operand1).stackElements << (node.operand2 == null ? 1 : 0)));
break;
case O_VECT_LUP:
case O_VECT_UUP:
case O_VECT_PCK:
stack.change(node.type.stackElements - ((Type) node.operand1).stackElements);
continue;
case STORE_LOCAL:
case STORE_STATIC:
case DECLARE_WITH:
case DECLARE_LOCAL:
stack.change(node.operand2 != null ? +0 : -((TypedItem) node.operand1).type.stackElements);
break;
case WRITE_COMPONENT:
stack.change(-(((Type) node.operand1).stackElements + 2));
break;
case WRITE_FIELD:
case WRITE_SPECIAL:
case WRITE_PROPERTY:
stack.change(-(((TypedItem) node.operand1).type.stackElements + 1));
}
Node jumpIsTrue = node.jumpIsTrue;
Node jumpIsFalse = node.jumpIsFalse;
if(jumpIsTrue != null && jumpIsFalse != null)
{
stack.change(-1);
if(jumpIsTrue.order > cindex && jumpIsFalse.order > cindex) jumpIsTrue.stackElements = jumpIsFalse.stackElements = stack.stackElements;
}
}
root.setData(root.position, METHOD_ENTER, new Int(stack.maximumElements));
}
}
private void buildPropertySpecifiers(Property property) {
ClassType factEnclosing = property.parentType;
ClassType realEnclosing = factEnclosing.getRealType();
Method method = property.indexSynthetic;
TypedMember indexMember = property.indexMember;
Constant indexConstant = property.indexConstant;
boolean hasIndex = indexConstant != null || indexMember != null;
label0: if(method != null)
{
Type type = method.type;
Code code = method.code;
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node control = code.createAndAppendNode(root).setData(-1, RETURN);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
if(indexConstant != null)
{
code.createAndAppendNode(control).setData(-1, type, LOAD_CONST, indexConstant.castTo(type));
break label0;
}
if(indexMember instanceof Field)
{
Node value = code.createAndAppendNode(control).setData(-1, indexMember.type, READ_FIELD, indexMember);
code.createAndPrependNode(value).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, type);
break label0;
}
if(indexMember instanceof Method)
{
Node value = code.createAndAppendNode(control).setData(-1, indexMember.type, invokeInstructionFor(indexMember, factEnclosing), indexMember);
code.createAndPrependNode(value).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, type);
}
}
label0: if((method = property.readSynthetic) != null)
{
Type type = method.type;
Code code = method.code;
TypedMember readMember = property.readMember;
Constant readConstant = property.readConstant;
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node control = code.createAndAppendNode(root).setData(-1, RETURN);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
if(readConstant != null)
{
code.createAndAppendNode(control).setData(-1, type, LOAD_CONST, readConstant.castTo(type));
break label0;
}
if(readMember instanceof Field)
{
Node value = code.createAndAppendNode(control).setData(-1, readMember.type, READ_FIELD, readMember);
code.createAndPrependNode(value).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, type);
break label0;
}
if(readMember instanceof Method)
{
Node value = code.createAndAppendNode(control).setData(-1, readMember.type, invokeInstructionFor(readMember, factEnclosing), readMember);
if(hasIndex) appendPropertyIndexCode(-1, value, indexConstant, indexMember);
code.createAndPrependNode(value).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, type);
}
}
label0: if((method = property.writeSynthetic) != null)
{
Code code = method.code;
Local value = method.getArgument(SPECNAME_VALUE);
TypedMember writeMember = property.writeMember;
Node root = code.root.setData(-1, METHOD_ENTER, null);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
if(writeMember instanceof Field)
{
Node write = code.createAndPrependNode(root).setData(-1, null, WRITE_FIELD, writeMember);
code.createAndAppendNode(write).setData(-1, value.type, LOAD_LOCAL, value);
code.createAndPrependNode(write).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
break label0;
}
if(writeMember instanceof Method)
{
Node write = code.createAndPrependNode(root).setData(-1, null, invokeInstructionFor(writeMember, factEnclosing), writeMember);
if(hasIndex) appendPropertyIndexCode(-1, write, indexConstant, indexMember);
code.createAndAppendNode(write).setData(-1, value.type, LOAD_LOCAL, value);
code.createAndPrependNode(write).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
}
}
label0: if((method = property.storedSynthetic) != null)
{
Type type = method.type;
Code code = method.code;
TypedMember storedMember = property.storedMember;
Constant storedConstant = property.storedConstant;
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node control = code.createAndAppendNode(root).setData(-1, RETURN);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
if(storedConstant != null)
{
code.createAndAppendNode(control).setData(-1, type, LOAD_CONST, storedConstant.castTo(type));
break label0;
}
if(storedMember instanceof Field)
{
Node value = code.createAndAppendNode(control).setData(-1, storedMember.type, READ_FIELD, storedMember);
code.createAndPrependNode(value).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, type);
break label0;
}
if(storedMember instanceof Method)
{
Node value = code.createAndAppendNode(control).setData(-1, storedMember.type, invokeInstructionFor(storedMember, factEnclosing), storedMember);
if(hasIndex) appendPropertyIndexCode(-1, value, indexConstant, indexMember);
code.createAndPrependNode(value).setData(-1, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, type);
}
}
}
private void parsePropertySpecifiers(Property property) throws TextSourceException {
TextSource source = (TextSource) property.source;
ClassType factEnclosing = property.parentType;
ClassType realEnclosing = factEnclosing.getRealType();
Method method = property.indexSynthetic;
TypedMember indexMember = method;
Constant indexConstant = null;
Type typeInt = fldTypeInt;
int indexPosition = 0;
boolean hasIndex = method != null;
/* index */
label0: if(hasIndex)
{
int position = method.implementationPosition;
Type targetType = method.type;
Code code = method.code;
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node control = code.createAndAppendNode(root).setData(-1, RETURN);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
indexPosition = position - 2;
if(source.getLexemeKind(position) == L_NAME && source.getLexemeKind(position + 1) == COMMA)
{
String name = source.getLexemeString(position);
Member member = factEnclosing.resolveName(name, factEnclosing, true);
if(member instanceof Fieldoid)
{
TypedMember[] foundFieldoids = factEnclosing.findFieldoids(name, factEnclosing);
int foundLength = foundFieldoids == null ? 0 : foundFieldoids.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
TypedMember foundFieldoid = foundFieldoids[0];
if(!foundFieldoid.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString(foundFieldoid instanceof Property ? "invisible.property" : "invisible.field"), new Object[] { factEnclosing.specialSimpleName, foundFieldoid }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.fieldoid"), new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name }
)) { source = source, position = position };
}
if(foundFieldoid instanceof Field)
{
Field foundField = (Field) foundFieldoid;
Type foundType = foundField.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.field-type"), new Object[] { foundField, foundType, targetType }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control);
if(!foundField.isStatic())
{
if(targetType.isAssignableFrom(foundType)) property.indexMember = indexMember = foundField;
value.setData(position, foundType, READ_FIELD, foundField);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
} else
{
switch(foundField.state)
{
case Field.COMPUTING:
throw new TextSourceException(String.format(
package.getResourceString("field.self-dependent-value"), new Object[] { foundField }
)) { source = source, position = position };
case Field.NOT_COMPUTED:
parseStaticFieldValue(foundField, foundField.parentType.getStaticBlock());
}
Constant foundValue = foundField.value;
if(foundField.isFinal() && foundValue != null)
{
property.indexConstant = indexConstant = foundValue = foundValue.castTo(targetType);
value.setData(position, foundValue.type, LOAD_CONST, foundValue);
} else
{
value.setData(position, foundType, LOAD_STATIC, foundField);
}
}
cast(value, targetType);
break label0;
}
if(foundFieldoid instanceof Property)
{
Property foundProperty = (Property) foundFieldoid;
if(!foundProperty.hasRead())
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.property-write-only"), new Object[] { foundProperty }
)) { source = source, position = position };
}
Type foundType = foundProperty.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.property-type"), new Object[] { foundProperty, foundType, targetType }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control).setData(position, foundType, READ_PROPERTY, foundProperty);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, targetType);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(member instanceof Method)
{
Method[] foundMethods = factEnclosing.findMethods(name, null, factEnclosing);
int foundLength = foundMethods == null ? 0 : foundMethods.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.method"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
Method foundMethod = foundMethods[0];
if(foundMethod.isInterrupt())
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.method-interrupt"), new Object[] { foundMethod }
)) { source = source, position = position };
}
if(!foundMethod.isConvertableArguments(null))
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.method-arguments"), new Object[] { foundMethod, ArgumentArray.toString(null) }
)) { source = source, position = position };
}
if(!foundMethod.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.method"), new Object[] { factEnclosing.specialSimpleName, foundMethod }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.method"), new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name + ArgumentArray.toString(null) }
)) { source = source, position = position };
}
Type foundType = foundMethod.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.method-return-type"), new Object[] { foundMethod, foundType, targetType }
)) { source = source, position = position };
}
ClassType foundThrowable = foundMethod.firstNonFreeThrowableType();
if(foundThrowable != null)
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.method-throws"), new Object[] { foundMethod, foundThrowable }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control);
if(foundMethod.isStatic())
{
value.setData(position, foundType, INVOKE_STATIC, foundMethod);
} else
{
if(targetType.isAssignableFrom(foundType)) property.indexMember = indexMember = foundMethod;
value.setData(position, foundType, invokeInstructionFor(foundMethod, factEnclosing), foundMethod);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
}
cast(value, targetType);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.member"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(source.getLexemeKind(position = parseExpression(control, source, position, false)) != COMMA)
{
throw new TextSourceException(package.getResourceString("expected.comma")) { source = source, position = position };
}
Node value = control[-1];
requiresValue(value);
Type valueType = value.type;
if(!targetType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.index.expression-type"), new Object[] { valueType, targetType }
)) { source = source, position = position };
}
cast(value, targetType);
if(value.instruction == LOAD_CONST) property.indexConstant = indexConstant = (Constant) value.operand1;
}
/* read */
label0: if((method = property.readSynthetic) != null)
{
int kind;
int position = method.implementationPosition;
Type targetType = method.type;
Code code = method.code;
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node control = code.createAndAppendNode(root).setData(-1, RETURN);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
if(source.getLexemeKind(position) == L_NAME && ((kind = source.getLexemeKind(position + 1)) == COMMA || kind == CURLY_CLOSED))
{
String name = source.getLexemeString(position);
Member member = factEnclosing.resolveName(name, factEnclosing, true);
if(member instanceof Fieldoid)
{
TypedMember[] foundFieldoids = factEnclosing.findFieldoids(name, factEnclosing);
int foundLength = foundFieldoids == null ? 0 : foundFieldoids.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
TypedMember foundFieldoid = foundFieldoids[0];
if(!foundFieldoid.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString(foundFieldoid instanceof Property ? "invisible.property" : "invisible.field"), new Object[] { factEnclosing.specialSimpleName, foundFieldoid }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.fieldoid"), new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name }
)) { source = source, position = position };
}
if(foundFieldoid instanceof Field)
{
Field foundField = (Field) foundFieldoid;
Type foundType = foundField.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.field-type"), new Object[] { foundField, foundType, targetType }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control);
if(!foundField.isStatic())
{
if(targetType.isAssignableFrom(foundType)) property.readMember = foundField;
value.setData(position, foundType, READ_FIELD, foundField);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
} else
{
switch(foundField.state)
{
case Field.COMPUTING:
throw new TextSourceException(String.format(
package.getResourceString("field.self-dependent-value"), new Object[] { foundField }
)) { source = source, position = position };
case Field.NOT_COMPUTED:
parseStaticFieldValue(foundField, foundField.parentType.getStaticBlock());
}
Constant foundValue = foundField.value;
if(foundField.isFinal() && foundValue != null)
{
property.readConstant = foundValue = foundValue.castTo(targetType);
value.setData(position, foundValue.type, LOAD_CONST, foundValue);
} else
{
value.setData(position, foundType, LOAD_STATIC, foundField);
}
}
cast(value, targetType);
break label0;
}
if(foundFieldoid instanceof Property)
{
Property foundProperty = (Property) foundFieldoid;
if(!foundProperty.hasRead())
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.property-write-only"), new Object[] { foundProperty }
)) { source = source, position = position };
}
Type foundType = foundProperty.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.property-type"), new Object[] { foundProperty, foundType, targetType }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control).setData(position, foundType, READ_PROPERTY, foundProperty);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, targetType);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(member instanceof Method)
{
Type[] arguments = !hasIndex ? null : new Type[] { typeInt };
Method[] foundMethods = factEnclosing.findMethods(name, arguments, factEnclosing);
int foundLength = foundMethods == null ? 0 : foundMethods.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.method"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
Method foundMethod = foundMethods[0];
if(foundMethod.isInterrupt())
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.method-interrupt"), new Object[] { foundMethod }
)) { source = source, position = position };
}
if(!foundMethod.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.method-arguments"), new Object[] { foundMethod, ArgumentArray.toString(arguments) }
)) { source = source, position = position };
}
if(!foundMethod.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.method"), new Object[] { factEnclosing.specialSimpleName, foundMethod }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.method"),
new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name + ArgumentArray.toString(arguments) }
)) { source = source, position = position };
}
Type foundType = foundMethod.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.method-return-type"), new Object[] { foundMethod, foundType, targetType }
)) { source = source, position = position };
}
ClassType foundThrowable = foundMethod.firstNonFreeThrowableType();
if(foundThrowable != null)
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.method-throws"), new Object[] { foundMethod, foundThrowable }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control);
if(foundMethod.isStatic())
{
value.setData(position, foundType, INVOKE_STATIC, foundMethod);
if(hasIndex) appendPropertyIndexCode(position, value, indexConstant, indexMember);
for(ArgumentArray foundArguments = foundMethod.arguments, int index = foundArguments.length; index-- > 0; ) cast(value[index], foundArguments[index].type);
} else
{
if(targetType.isAssignableFrom(foundType) && foundMethod.isAssignableArguments(arguments)) property.readMember = foundMethod;
value.setData(position, foundType, invokeInstructionFor(foundMethod, factEnclosing), foundMethod);
if(hasIndex) appendPropertyIndexCode(position, value, indexConstant, indexMember);
for(ArgumentArray foundArguments = foundMethod.arguments, int index = foundArguments.length; index-- > 0; ) cast(value[index], foundArguments[index].type);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
}
cast(value, targetType);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.member"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(hasIndex)
{
Node index = code.createAndPrependNode(root).setData(-1, null, DECLARE_LOCAL, code.createLocal(true, typeInt, SPECNAME_INDEX, null, indexPosition));
appendPropertyIndexCode(-1, index, indexConstant, indexMember);
}
if((kind = source.getLexemeKind(position = parseExpression(control, source, position, false))) != COMMA && kind != CURLY_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
}
Node value = control[-1];
requiresValue(value);
Type valueType = value.type;
if(!targetType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.read.expression-type"), new Object[] { valueType, targetType }
)) { source = source, position = position };
}
cast(value, targetType);
if(value.instruction == LOAD_CONST) property.readConstant = (Constant) value.operand1;
}
/* write */
label0: if((method = property.writeSynthetic) != null)
{
int kind;
int position = method.implementationPosition;
Type sourceType = property.type;
Code code = method.code;
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node exit = code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
if(source.getLexemeKind(position) == L_NAME && ((kind = source.getLexemeKind(position + 1)) == COMMA || kind == CURLY_CLOSED))
{
Local value = method.getArgument(SPECNAME_VALUE);
String name = source.getLexemeString(position);
Member member = factEnclosing.resolveName(name, factEnclosing, true);
if(member instanceof Fieldoid)
{
TypedMember[] foundFieldoids = factEnclosing.findFieldoids(name, factEnclosing);
int foundLength = foundFieldoids == null ? 0 : foundFieldoids.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.member"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
TypedMember foundFieldoid = foundFieldoids[0];
if(!foundFieldoid.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString(foundFieldoid instanceof Property ? "invisible.property" : "invisible.field"), new Object[] { factEnclosing.specialSimpleName, foundFieldoid }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.fieldoid"), new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name }
)) { source = source, position = position };
}
if(foundFieldoid instanceof Field)
{
Field foundField = (Field) foundFieldoid;
if(foundField.isFinal())
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.field-final"), new Object[] { foundField }
)) { source = source, position = position };
}
Type foundType = foundField.type;
if(!foundType.isConvertableFrom(sourceType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.field-type"), new Object[] { foundField, foundType, sourceType }
)) { source = source, position = position };
}
Node write = code.createAndPrependNode(root);
if(foundField.isStatic())
{
write.setData(position, null, STORE_STATIC, foundField);
} else
{
if(foundType.isAssignableFrom(sourceType)) property.writeMember = foundField;
write.setData(position, null, WRITE_FIELD, foundField);
code.createAndPrependNode(write).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
}
cast(code.createAndAppendNode(write).setData(position, value.type, LOAD_LOCAL, value), foundType);
break label0;
}
if(foundFieldoid instanceof Property)
{
Property foundProperty = (Property) foundFieldoid;
if(!foundProperty.hasWrite())
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.property-read-only"), new Object[] { foundProperty }
)) { source = source, position = position };
}
Type foundType = foundProperty.type;
if(!foundType.isConvertableFrom(sourceType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.property-type"), new Object[] { foundProperty, foundType, sourceType }
)) { source = source, position = position };
}
Node write = code.createAndPrependNode(root).setData(position, null, WRITE_PROPERTY, foundProperty);
code.createAndPrependNode(write).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(code.createAndAppendNode(write).setData(position, value.type, LOAD_LOCAL, value), foundType);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(member instanceof Method)
{
Type[] arguments = !hasIndex ? new Type[] { sourceType } : new Type[] { typeInt, sourceType };
Method[] foundMethods = factEnclosing.findMethods(name, arguments, factEnclosing);
int foundLength = foundMethods == null ? 0 : foundMethods.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.method"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
Method foundMethod = foundMethods[0];
if(foundMethod.isInterrupt())
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.method-interrupt"), new Object[] { foundMethod }
)) { source = source, position = position };
}
if(!foundMethod.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.method-arguments"), new Object[] { foundMethod, ArgumentArray.toString(arguments) }
)) { source = source, position = position };
}
if(!foundMethod.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.method"), new Object[] { factEnclosing.specialSimpleName, foundMethod }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.method"),
new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name + ArgumentArray.toString(arguments) }
)) { source = source, position = position };
}
Type foundType = foundMethod.type;
if(!foundType.isVoid())
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.method-return-type"), new Object[] { foundMethod, foundType, fldTypeVoid }
)) { source = source, position = position };
}
ClassType foundThrowable = foundMethod.firstNonFreeThrowableType();
if(foundThrowable != null)
{
throw new TextSourceException(String.format(
package.getResourceString("property.write.method-throws"), new Object[] { foundMethod, foundThrowable }
)) { source = source, position = position };
}
if(foundMethod.isStatic())
{
Node write = code.createAndPrependNode(root).setData(position, null, INVOKE_STATIC, foundMethod);
if(hasIndex) appendPropertyIndexCode(position, write, indexConstant, indexMember);
code.createAndAppendNode(write).setData(position, value.type, LOAD_LOCAL, value);
for(ArgumentArray foundArguments = foundMethod.arguments, int index = foundArguments.length; index-- > 0; ) cast(write[index], foundArguments[index].type);
break label0;
}
if(foundMethod.isAssignableArguments(arguments)) property.writeMember = foundMethod;
Node write = code.createAndPrependNode(root).setData(position, null, invokeInstructionFor(foundMethod, factEnclosing), foundMethod);
if(hasIndex) appendPropertyIndexCode(position, write, indexConstant, indexMember);
code.createAndAppendNode(write).setData(position, value.type, LOAD_LOCAL, value);
for(ArgumentArray foundArguments = foundMethod.arguments, int index = foundArguments.length; index-- > 0; ) cast(write[index], foundArguments[index].type);
code.createAndPrependNode(write).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.member"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(hasIndex)
{
Node index = code.createAndPrependNode(root).setData(-1, null, DECLARE_LOCAL, code.createLocal(true, typeInt, SPECNAME_INDEX, null, indexPosition));
appendPropertyIndexCode(-1, index, indexConstant, indexMember);
}
if((kind = source.getLexemeKind(position = parseDeclareLocal(root, source, position, false))) != COMMA && kind != CURLY_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
}
code.moveNode(exit, root.length);
}
/* stored */
label0: if((method = property.storedSynthetic) != null)
{
int position = method.implementationPosition;
Type targetType = method.type;
Code code = method.code;
Node root = code.root.setData(-1, METHOD_ENTER, null);
Node control = code.createAndAppendNode(root).setData(-1, RETURN);
code.createAndAppendNode(root).setData(-1, METHOD_LEAVE);
if(source.getLexemeKind(position) == L_NAME && source.getLexemeKind(position + 1) == CURLY_CLOSED)
{
String name = source.getLexemeString(position);
Member member = factEnclosing.resolveName(name, factEnclosing, true);
if(member instanceof Fieldoid)
{
TypedMember[] foundFieldoids = factEnclosing.findFieldoids(name, factEnclosing);
int foundLength = foundFieldoids == null ? 0 : foundFieldoids.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
TypedMember foundFieldoid = foundFieldoids[0];
if(!foundFieldoid.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString(foundFieldoid instanceof Property ? "invisible.property" : "invisible.field"), new Object[] { factEnclosing.specialSimpleName, foundFieldoid }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.fieldoid"), new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name }
)) { source = source, position = position };
}
if(foundFieldoid instanceof Field)
{
Field foundField = (Field) foundFieldoid;
Type foundType = foundField.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.field-type"), new Object[] { foundField, foundType, targetType }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control);
if(!foundField.isStatic())
{
if(targetType.isAssignableFrom(foundType)) property.storedMember = foundField;
value.setData(position, foundType, READ_FIELD, foundField);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
} else
{
switch(foundField.state)
{
case Field.COMPUTING:
throw new TextSourceException(String.format(
package.getResourceString("field.self-dependent-value"), new Object[] { foundField }
)) { source = source, position = position };
case Field.NOT_COMPUTED:
parseStaticFieldValue(foundField, foundField.parentType.getStaticBlock());
}
Constant foundValue = foundField.value;
if(foundField.isFinal() && foundValue != null)
{
property.storedConstant = foundValue = foundValue.castTo(targetType);
value.setData(position, foundValue.type, LOAD_CONST, foundValue);
} else
{
value.setData(position, foundType, LOAD_STATIC, foundField);
}
}
cast(value, targetType);
break label0;
}
if(foundFieldoid instanceof Property)
{
Property foundProperty = (Property) foundFieldoid;
if(!foundProperty.hasRead())
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.property-write-only"), new Object[] { foundProperty }
)) { source = source, position = position };
}
Type foundType = foundProperty.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.property-type"), new Object[] { foundProperty, foundType, targetType }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control).setData(position, foundType, READ_PROPERTY, foundProperty);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
cast(value, targetType);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(member instanceof Method)
{
Type[] arguments = !hasIndex ? null : new Type[] { typeInt };
Method[] foundMethods = factEnclosing.findMethods(name, arguments, factEnclosing);
int foundLength = foundMethods == null ? 0 : foundMethods.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.method"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
Method foundMethod = foundMethods[0];
if(foundMethod.isInterrupt())
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.method-interrupt"), new Object[] { foundMethod }
)) { source = source, position = position };
}
if(!foundMethod.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.method-arguments"), new Object[] { foundMethod, ArgumentArray.toString(arguments) }
)) { source = source, position = position };
}
if(!foundMethod.isVisibleFrom(factEnclosing, factEnclosing))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.method"), new Object[] { factEnclosing.specialSimpleName, foundMethod }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.method"),
new Object[] { new StringBuilder(0x0400) + factEnclosing.specialCanonicalName + '.' + name + ArgumentArray.toString(arguments) }
)) { source = source, position = position };
}
Type foundType = foundMethod.type;
if(!targetType.isConvertableFrom(foundType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.method-return-type"), new Object[] { foundMethod, foundType, targetType }
)) { source = source, position = position };
}
ClassType foundThrowable = foundMethod.firstNonFreeThrowableType();
if(foundThrowable != null)
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.method-throws"), new Object[] { foundMethod, foundThrowable }
)) { source = source, position = position };
}
Node value = code.createAndAppendNode(control);
if(foundMethod.isStatic())
{
value.setData(position, foundType, INVOKE_STATIC, foundMethod);
if(hasIndex) appendPropertyIndexCode(position, value, indexConstant, indexMember);
for(ArgumentArray foundArguments = foundMethod.arguments, int index = foundArguments.length; index-- > 0; ) cast(value[index], foundArguments[index].type);
} else
{
if(targetType.isAssignableFrom(foundType) && foundMethod.isAssignableArguments(arguments)) property.storedMember = foundMethod;
value.setData(position, foundType, invokeInstructionFor(foundMethod, factEnclosing), foundMethod);
if(hasIndex) appendPropertyIndexCode(position, value, indexConstant, indexMember);
for(ArgumentArray foundArguments = foundMethod.arguments, int index = foundArguments.length; index-- > 0; ) cast(value[index], foundArguments[index].type);
code.createAndPrependNode(value).setData(position, realEnclosing, LOAD_LOCAL, method.arguments.thisArgument);
}
cast(value, targetType);
break label0;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.member"), new Object[] { factEnclosing.specialSimpleName, name }
)) { source = source, position = position };
}
if(hasIndex)
{
Node index = code.createAndPrependNode(root).setData(-1, null, DECLARE_LOCAL, code.createLocal(true, typeInt, SPECNAME_INDEX, null, indexPosition));
appendPropertyIndexCode(-1, index, indexConstant, indexMember);
}
if(source.getLexemeKind(position = parseExpression(control, source, position, false)) != CURLY_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
}
Node value = control[-1];
requiresValue(value);
Type valueType = value.type;
if(!targetType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("property.stored.expression-type"), new Object[] { valueType, targetType }
)) { source = source, position = position };
}
cast(value, targetType);
if(value.instruction == LOAD_CONST) property.storedConstant = (Constant) value.operand1;
}
}
private void parseStaticFieldValue(Field field, ClassInit staticBlock) throws TextSourceException {
if(field.state == Field.NOT_COMPUTED)
{
TextSource source = (TextSource) field.source;
int position = field.implementationPosition;
switch(source.getLexemeKind(position))
{
case SEMICOLON:
field.closeComputing();
break;
case EQUALS:
if(field.isStatic())
{
Code code = staticBlock.code;
field.openComputing();
try
{
int before = position;
Node store = code.createAndAppendNode(null);
if(source.getLexemeKind(position = parseExpression(store, source, position + 1, false)) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
Node value = store[-1];
requiresValue(value);
Type fieldType = field.type;
Type valueType = value.type;
if(!fieldType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, fieldType }
)) { source = source, position = position };
}
if((value = cast(value, fieldType)).instruction != LOAD_CONST || !fieldType.isPrimitive() && !field.isFinal())
{
store.setData(before, null, STORE_STATIC, field);
} else
{
field.setComputedValue((Constant) value.operand1);
code.removeNode(store);
}
} finally
{
field.closeComputing();
}
break;
}
/* падение через */
default:
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
}
}
private int parsePostfix(Node parent, TextSource source, int position, boolean isStaticOnly, boolean isImplicitPeriod) throws TextSourceException {
Code code = parent.parentCode;
Callable enclosingCallable = code.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
label0: for(Node child1 = parent[-1], boolean isUseSuper = child1.useSuper; ; isImplicitPeriod = isUseSuper = false, position++)
{
int operation = source.getLexemeKind(position);
if(isUseSuper && operation != PERIOD && operation != PARENTH_OPENED && operation != BRACKET_OPENED)
{
throw new TextSourceException(package.getResourceString("error.expression.super")) { source = source, position = position };
}
boolean isPeriod = false;
if(isImplicitPeriod)
{
isPeriod = true;
}
else if(operation == PERIOD)
{
isPeriod = true;
position++;
}
int before = position;
Type argument1Type = child1.type;
if(isPeriod)
{
if(argument1Type != null && !(argument1Type instanceof ClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.dereference.type"), new Object[] { argument1Type }
)) { source = source, position = position };
}
int context;
ClassType dereferenceClassType;
if(child1.instruction == CLASS)
{
context = -1; /* это точно статичный контекст */
dereferenceClassType = (ClassType) child1.operand1;
} else
{
context = isImplicitPeriod ? 0 /* неопределённый контекст */ : 1 /* это точно инстанционный контекст */;
dereferenceClassType = (ClassType) argument1Type;
}
int kind = 0;
String name = null;
switch(source.getLexemeKind(position))
{
case OPERATOR:
ImmediateBuilderItemHolder operatorHolder = getItemHolder();
position = parseOperator(source, position + 1, operatorHolder) - 1;
kind = operatorHolder.resultKind;
name = Operator.kindToSpecialSimpleName(kind);
break;
case L_NAME:
name = source.getLexemeString(position);
break;
default:
throw new TextSourceException(package.getResourceString("expected.name.member")) { source = source, position = position };
}
Member resolvedMember = dereferenceClassType.resolveName(name, enclosingClassType, false);
if(resolvedMember instanceof Fieldoid)
{
TypedMember[] foundFieldoids = dereferenceClassType.findFieldoids(name, enclosingClassType);
int foundLength = foundFieldoids == null ? 0 : foundFieldoids.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { dereferenceClassType, name }
)) { source = source, position = before };
}
TypedMember foundFieldoid = foundFieldoids[0];
if(!foundFieldoid.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString(foundFieldoid instanceof Property ? "invisible.property" : "invisible.field"),
new Object[] { enclosingClassType.specialSimpleName, foundFieldoid }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.fieldoid"), new Object[] { new StringBuilder(0x0400) + dereferenceClassType.specialCanonicalName + '.' + name }
)) { source = source, position = before };
}
if(foundFieldoid instanceof Field)
{
Field foundField = (Field) foundFieldoid;
if(context > 0)
{
if(foundField.isStatic())
{
throw new TextSourceException(String.format(
package.getResourceString("must-be.access.static-field"), new Object[] { foundField }
)) { source = source, position = before };
}
Node result = code.createAndAppendNode(parent).setData(before, foundField.type, READ_FIELD, foundField);
code.moveNode(child1, child1 = result, 0);
continue;
}
if(!foundField.isStatic())
{
if(context < 0)
{
throw new TextSourceException(String.format(
package.getResourceString("must-be.access.instance-field"), new Object[] { foundField }
)) { source = source, position = before };
}
Node result = code.createAndAppendNode(parent).setData(before, foundField.type, READ_FIELD, foundField);
code.moveNode(child1, child1 = result, 0);
continue;
}
switch(foundField.state)
{
case Field.COMPUTING:
throw new TextSourceException(String.format(
package.getResourceString("field.self-dependent-value"), new Object[] { foundField }
)) { source = source, position = before };
case Field.NOT_COMPUTED:
parseStaticFieldValue(foundField, foundField.parentType.getStaticBlock());
}
Constant foundValue = foundField.value;
if(foundField.isFinal() && foundValue != null)
{
child1.setData(before, foundValue.type, LOAD_CONST, foundValue);
continue;
}
child1.setData(before, foundField.type, LOAD_STATIC, foundField);
continue;
}
if(foundFieldoid instanceof Property)
{
Property foundProperty = (Property) foundFieldoid;
if(context < 0)
{
throw new TextSourceException(String.format(
package.getResourceString("must-be.access.property"), new Object[] { foundProperty }
)) { source = source, position = before };
}
Node result = code.createAndAppendNode(parent);
if(foundProperty.hasRead())
{
if(isUseSuper)
{
if(foundProperty.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.property.read"), new Object[] { foundProperty }
)) { source = source, position = before };
}
result.setData(before, foundProperty.type, READ_SPECIAL, foundProperty);
} else
{
result.setData(before, foundProperty.type, READ_PROPERTY, foundProperty);
}
} else
{
if(source.getLexemeKind(position + 1) != EQUALS)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.property-write-only.read"), new Object[] { foundProperty }
)) { source = source, position = before };
}
if(isUseSuper)
{
if(foundProperty.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.property.write"), new Object[] { foundProperty }
)) { source = source, position = before };
}
result.setData(before, foundProperty.type, WRITE_SPECIAL, foundProperty);
} else
{
result.setData(before, foundProperty.type, WRITE_PROPERTY, foundProperty);
}
}
code.moveNode(child1, child1 = result, 0);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { dereferenceClassType, name }
)) { source = source, position = before };
}
if(resolvedMember instanceof Callable)
{
if(source.getLexemeKind(position + 1) != PARENTH_OPENED)
{
if(kind != 0)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position + 1 };
}
Callable[] foundInterrupts = dereferenceClassType.findInterrupts(name, enclosingClassType);
int foundLength = foundInterrupts == null ? 0 : foundInterrupts.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.interrupt"), new Object[] { dereferenceClassType, name }
)) { source = source, position = before };
}
Callable foundInterrupt = foundInterrupts[0];
if(!foundInterrupt.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.interrupt"), new Object[] { enclosingClassType.specialSimpleName, foundInterrupt }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.interrupt"), new Object[] { new StringBuilder(0x0400) + dereferenceClassType.specialCanonicalName + '.' + name }
)) { source = source, position = before };
}
if(context > 0)
{
throw new TextSourceException(String.format(
package.getResourceString("must-be.access.static-method"), new Object[] { foundInterrupt }
)) { source = source, position = before };
}
child1.setData(before, fldTypeLong, LOAD_INTERRUPT, foundInterrupt);
continue;
}
Node result = code.createAndAppendNode(parent);
label1: if(source.getLexemeKind(position += 2) != PARENTH_CLOSED) do
{
position = parseExpression(result, source, position, isStaticOnly);
requiresValue(result[-1]);
switch(source.getLexemeKind(position))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
case PARENTH_CLOSED:
break label1;
case COMMA:
position++;
}
} while(true);
int length = result.length;
Type[] arguments = new Type[length];
for(int index = 0; index < length; index++) arguments[index] = result[index].type;
Callable[] foundCallables = kind != 0 ? (
(Callable[]) dereferenceClassType.findOperators(kind, arguments, enclosingClassType)
) : (
(Callable[]) dereferenceClassType.findMethods(name, arguments, enclosingClassType)
);
int foundLength = foundCallables == null ? 0 : foundCallables.length;
if(foundLength < 1)
{
throw new TextSourceException(kind != 0 ? String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(kind) }
) : String.format(
package.getResourceString("can-not-be.converted.method"), new Object[] { dereferenceClassType, name }
)) { source = source, position = before };
}
Callable foundCallable = foundCallables[0];
if(foundCallable.isInterrupt())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.invoke-interrupt"), new Object[] { foundCallable }
)) { source = source, position = before };
}
if(!foundCallable.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString(kind != 0 ? "not-applicable.operator" : "not-applicable.method"), new Object[] { foundCallable, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundCallable.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString(kind != 0 ? "invisible.operator" : "invisible.method"), new Object[] { enclosingClassType.specialSimpleName, foundCallable }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(kind != 0 ? String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(kind) + foundCallable.arguments }
) : String.format(
package.getResourceString("ambiguous.method"), new Object[] { new StringBuilder(0x0400) + dereferenceClassType + '.' + name + foundCallable.arguments }
)) { source = source, position = before };
}
if(isUseSuper && foundCallable.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString(kind > 0 ? "can-not-be.direct-access-abstract.operator" : "can-not-be.direct-access-abstract.method"), new Object[] { foundCallable }
)) { source = source, position = before };
}
for(ArgumentArray foundArguments = foundCallable.arguments, int index = 0; index < length; index++)
{
cast(result[index], foundArguments[index].type);
}
if(context < 0)
{
if(!foundCallable.isStatic())
{
throw new TextSourceException(String.format(
package.getResourceString(kind != 0 ? "must-be.access.operator" : "must-be.access.instance-method"), new Object[] { foundCallable }
)) { source = source, position = before };
}
result.setData(before, foundCallable.type, INVOKE_STATIC, foundCallable);
code.removeNode(child1);
child1 = result;
continue;
}
if(foundCallable.isStatic())
{
if(context > 0)
{
throw new TextSourceException(String.format(
package.getResourceString("must-be.access.static-method"), new Object[] { foundCallable }
)) { source = source, position = before };
}
result.setData(before, foundCallable.type, INVOKE_STATIC, foundCallable);
code.removeNode(child1);
child1 = result;
continue;
}
result.setData(before, foundCallable.type, isUseSuper ? INVOKE_SPECIAL : invokeInstructionFor(foundCallable, dereferenceClassType), foundCallable);
code.moveNode(child1, child1 = result, 0);
continue;
}
throw new TextSourceException(kind > 0 ? String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(kind) }
) : String.format(
package.getResourceString("can-not-be.converted.member"), new Object[] { dereferenceClassType, name }
)) { source = source, position = before };
}
switch(operation)
{
case PARENTH_OPENED:
if(argument1Type instanceof ClassType)
{
Node result = code.createAndAppendNode(parent);
ClassType dereferenceClassType = (ClassType) argument1Type;
label1: if(source.getLexemeKind(++position) != PARENTH_CLOSED) do
{
position = parseExpression(result, source, position, isStaticOnly);
requiresValue(result[-1]);
switch(source.getLexemeKind(position))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
case PARENTH_CLOSED:
break label1;
case COMMA:
position++;
}
} while(true);
int length = result.length;
Type[] arguments = new Type[length];
for(int index = 0; index < length; index++) arguments[index] = result[index].type;
Operator[] foundOperators = dereferenceClassType.findOperators(INVOKE_VIRTUAL, arguments, enclosingClassType);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(INVOKE_VIRTUAL) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosingClassType.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(INVOKE_VIRTUAL) + foundOperator.arguments }
)) { source = source, position = before };
}
if(isUseSuper && foundOperator.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.operator"), new Object[] { foundOperator }
)) { source = source, position = before };
}
for(ArgumentArray foundArguments = foundOperator.arguments, int index = 0; index < length; index++) cast(result[index], foundArguments[index].type);
result.setData(-1, foundOperator.type, isUseSuper ? INVOKE_SPECIAL : invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("operator.not-applicable-to-type"), new Object[] { argument1Type, Operator.kindToSymbol(INVOKE_VIRTUAL) }
)) { source = source, position = before };
case BRACKET_OPENED:
if(argument1Type instanceof PrimitiveType && argument1Type.isVector())
{
PrimitiveType typeInt = fldTypeInt;
PrimitiveType vectorMainType = (PrimitiveType) argument1Type;
PrimitiveType vectorBaseType = vectorMainType.vectorBaseType;
if(source.getLexemeKind(position = parseExpression(parent, source, position + 1, isStaticOnly)) != BRACKET_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-bracket")) { source = source, position = position };
}
Node child2 = parent[-1];
requiresValue(child2);
Type argument2Type = child2.type;
if(!typeInt.isConvertableFrom(argument2Type))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { argument2Type, typeInt }
)) { source = source, position = position };
}
child2 = cast(child2, typeInt);
if(child2.instruction == LOAD_CONST)
{
int index = ((Constant) child2.operand1).asInt();
if(index < 0 || index >= vectorMainType.vectorLength)
{
throw new TextSourceException(String.format(
package.getResourceString("out-of-range.vector-index"), new Object[] { Int.toString(index) }
)) { source = source, position = position };
}
if(child1.instruction == LOAD_CONST)
{
switch(vectorBaseType.kind >> 2)
{
case DOUBLE >> 2:
child1.setData(child1.position, vectorBaseType, LOAD_CONST, fldConstantFactory.createDouble(((Constant) child1.operand1).asDouble8()[index]));
break;
case FLOAT >> 2:
child1.setData(child1.position, vectorBaseType, LOAD_CONST, fldConstantFactory.createFloat(((Constant) child1.operand1).asFloat8()[index]));
break;
case BYTE >> 2:
child1.setData(child1.position, vectorBaseType, LOAD_CONST, fldConstantFactory.createByte(((Constant) child1.operand1).asByte8()[index]));
break;
case SHORT >> 2:
child1.setData(child1.position, vectorBaseType, LOAD_CONST, fldConstantFactory.createShort(((Constant) child1.operand1).asShort8()[index]));
break;
case INT >> 2:
child1.setData(child1.position, vectorBaseType, LOAD_CONST, fldConstantFactory.createInt(((Constant) child1.operand1).asInt8()[index]));
break;
case LONG >> 2:
child1.setData(child1.position, vectorBaseType, LOAD_CONST, fldConstantFactory.createLong(((Constant) child1.operand1).asLong8()[index]));
}
code.removeNode(child2);
continue;
}
}
Node result = code.createAndAppendNode(parent).setData(-1, vectorBaseType, READ_ELEMENT, vectorMainType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument1Type instanceof ArrayType)
{
PrimitiveType typeInt = fldTypeInt;
Type componentType = ((ArrayType) argument1Type).componentType;
if(source.getLexemeKind(position = parseExpression(parent, source, position + 1, isStaticOnly)) != BRACKET_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-bracket")) { source = source, position = position };
}
Node child2 = parent[-1];
requiresValue(child2);
Type argument2Type = child2.type;
if(!typeInt.isConvertableFrom(argument2Type))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { argument2Type, typeInt }
)) { source = source, position = position };
}
child2 = cast(child2, typeInt);
Node result = code.createAndAppendNode(parent).setData(-1, componentType, READ_COMPONENT, componentType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
if(source.getLexemeKind(position = parseExpression(parent, source, position + 1, isStaticOnly)) != BRACKET_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-bracket")) { source = source, position = position };
}
Node child2 = parent[-1];
requiresValue(child2);
Node result = code.createAndAppendNode(parent);
if(source.getLexemeKind(position + 1) == EQUALS)
{
result.setData(-1, null, INVOKE_VIRTUAL, null);
} else
{
Type[] arguments = new Type[] { child2.type };
Operator[] foundOperators = dereferenceClassType.findOperators(READ_COMPONENT, arguments, enclosingClassType);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(READ_COMPONENT) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosingClassType.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(READ_COMPONENT) + foundOperator.arguments }
)) { source = source, position = before };
}
if(isUseSuper && foundOperator.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.operator"), new Object[] { foundOperator }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
result.setData(-1, foundOperator.type, isUseSuper ? INVOKE_SPECIAL : invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
}
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("operator.not-applicable-to-type"), new Object[] { argument1Type, Operator.kindToSymbol(READ_COMPONENT) }
)) { source = source, position = before };
case INC_LOCAL:
case DEC_LOCAL:
int instruction = child1.instruction;
switch(instruction)
{
case LOAD_LOCAL:
{
Local foundLocal = (Local) child1.operand1;
if(foundLocal.isFinal())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.local-final.write"), new Object[] { foundLocal }
)) { source = source, position = before };
}
if(!((argument1Type = foundLocal.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
child1.setData(child1.position, argument1Type, operation == INC_LOCAL ? INC_POST_LOAD_LOCAL : DEC_POST_LOAD_LOCAL, foundLocal);
continue;
}
case LOAD_STATIC:
{
Field foundField = (Field) child1.operand1;
if(foundField.isFinal() && (!(enclosingCallable instanceof ClassInit) || foundField.parentType != enclosingClassType || foundField.value != null))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundField }
)) { source = source, position = before };
}
if(!((argument1Type = foundField.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
code.createAndAppendNode(child1).setData(child1.position, argument1Type, LOAD_STATIC, foundField);
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
code.createAndPrependNode(delta).setData(-1, null, DUP1, argument1Type);
child1.setData(-1, argument1Type, STORE_STATIC, foundField);
continue;
}
case READ_FIELD:
case READ_SPECIAL:
case READ_PROPERTY:
{
TypedMember foundFieldoid = (TypedMember) child1.operand1;
if(foundFieldoid instanceof Property)
{
if(!((Property) foundFieldoid).hasWrite())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.property-read-only.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
} else
{
Node load = child1[0];
if(
foundFieldoid.isFinal() && (
!(enclosingCallable instanceof InstInit) || foundFieldoid.parentType != enclosingClassType ||
load.instruction != LOAD_LOCAL || load.operand1 != enclosingCallable.arguments.thisArgument
)
)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
}
if(!((argument1Type = foundFieldoid.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
Node read = code.createAndAppendNode(child1).setData(child1.position, argument1Type, instruction, foundFieldoid);
code.createAndAppendNode(read).setData(-1, null, DUP1, fldTypeObject);
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
code.createAndPrependNode(delta).setData(-1, null, DUP1X1, argument1Type);
child1.setData(-1, argument1Type, instruction + A_DELTA, foundFieldoid);
continue;
}
case READ_COMPONENT:
{
if(!((argument1Type = (Type) child1.operand1) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
Node read = code.createAndAppendNode(child1).setData(child1.position, argument1Type, READ_COMPONENT, argument1Type);
code.createAndAppendNode(read).setData(-1, null, DUP2, fldTypeInt);
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
code.createAndPrependNode(delta).setData(-1, null, DUP1X2, argument1Type);
child1.setData(-1, argument1Type, WRITE_COMPONENT, argument1Type);
continue;
}
case INVOKE_SERVICE:
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
Operator foundReadOperator;
TableItem foundCallable = child1.operand1;
if(foundCallable instanceof Operator && (foundReadOperator = (Operator) foundCallable).kind == READ_COMPONENT)
{
if(!((argument1Type = foundReadOperator.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
Node load = child1[0];
ClassType dereferenceClassType = (ClassType) load.type;
Type[] arguments = new Type[] { foundReadOperator.arguments[0].type, argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(WRITE_COMPONENT, arguments, enclosingClassType);
Operator foundWriteOperator = foundOperators == null || foundOperators.length != 1 ? null : foundOperators[0];
if(foundWriteOperator == null || !foundWriteOperator.isIdentityArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-found.operator"), new Object[] { dereferenceClassType, Operator.kindToSymbol(WRITE_COMPONENT) + ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundWriteOperator.isVisibleFrom(enclosingClassType, (isUseSuper = load.useSuper) ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosingClassType.specialSimpleName, foundWriteOperator }
)) { source = source, position = before };
}
if(isUseSuper && foundWriteOperator.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.operator"), new Object[] { foundWriteOperator }
)) { source = source, position = before };
}
Node read = code.createAndAppendNode(child1).setData(child1.position, argument1Type, instruction, foundReadOperator);
code.createAndAppendNode(read).setData(-1, null, DUP2, arguments[0]);
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
code.createAndPrependNode(delta).setData(-1, null, DUP1X2, argument1Type);
child1.setData(-1, argument1Type, isUseSuper ? INVOKE_SPECIAL : invokeInstructionFor(foundWriteOperator, dereferenceClassType), foundWriteOperator);
continue;
}
}
throw new TextSourceException(String.format(
package.getResourceString("applicable.operator.increment-decrement"), new Object[] { source.getLexemeString(before) }
)) { source = source, position = before };
default:
break label0;
}
}
return position;
}
private int parsePrimary(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
boolean isImplicitPeriod = false;
int operation = source.getLexemeKind(position);
Code code = parent.parentCode;
Callable enclosingCallable = code.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
label0: switch(operation)
{
case PARENTH_OPENED:
{
if(source.getLexemeKind(position = parseExpression(parent, source, position + 1, isStaticOnly)) != PARENTH_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
}
requiresValue(parent[-1]);
break;
}
case SUPER:
{
if(isStaticOnly)
{
throw new TextSourceException(package.getResourceString("can-not-reference.this")) { source = source, position = position };
}
if(enclosingCallable.isStatic())
{
throw new TextSourceException(package.getResourceString("can-not-use.static.this")) { source = source, position = position };
}
if(enclosingClassType.isHelper())
{
throw new TextSourceException(package.getResourceString("can-not-use.helper.super")) { source = source, position = position };
}
ClassType foundClassType = enclosingClassType.getSuperclassType();
if(foundClassType == null)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-use.super"), new Object[] { enclosingClassType.specialSimpleName }
)) { source = source, position = position };
}
code.createAndAppendNode(parent).setData(position, foundClassType, LOAD_LOCAL, enclosingCallable.arguments.thisArgument).useSuper = true;
break;
}
case THIS:
{
if(isStaticOnly)
{
throw new TextSourceException(package.getResourceString("can-not-reference.this")) { source = source, position = position };
}
if(enclosingCallable.isStatic())
{
throw new TextSourceException(package.getResourceString("can-not-use.static.this")) { source = source, position = position };
}
code.createAndAppendNode(parent).setData(position, enclosingClassType.getRealType(), LOAD_LOCAL, enclosingCallable.arguments.thisArgument);
break;
}
case NEW:
int before = position++;
ImmediateBuilderItemHolder resultTypeHolder = getItemHolder();
position = parseTypeName(source, position, enclosingClassType, resultTypeHolder);
Type resultType = resultTypeHolder.resultType;
if(resultType instanceof ArrayType)
{
if(source.getLexemeKind(position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
resultType.makeCompilable();
Node result = code.createAndAppendNode(parent);
ConstantFactory factory = fldConstantFactory;
label1: if(source.getLexemeKind(++position) != CURLY_CLOSED) for(Type componentType = ((ArrayType) resultType).componentType, Type typeInt = fldTypeInt, int index = 0; ; index++)
{
Node write = code.createAndAppendNode(result).setData(-1, null, WRITE_COMPONENT, componentType);
code.createAndAppendNode(write).setData(position, resultType, DUP1, resultType);
code.createAndAppendNode(write).setData(-1, typeInt, LOAD_CONST, factory.createInt(index));
position = parseExpression(write, source, position, isStaticOnly);
Node value = write[-1];
requiresValue(value);
Type valueType = value.type;
if(!componentType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, componentType }
)) { source = source, position = position };
}
cast(value, componentType);
switch(source.getLexemeKind(position))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
case CURLY_CLOSED:
break label1;
case COMMA:
position++;
}
}
for(int index = result.length, result.setData(before, resultType, NEW_ARRAY, resultType, factory.createInt(index)); index-- > 0; )
{
Node write = result[index];
Node value = write[-1];
TableItem operand = value.operand1;
if(value.instruction == LOAD_CONST && ((Constant) operand).isDefaultValue()) code.removeNode(write);
}
break;
}
if(source.getLexemeKind(position) == BRACKET_OPENED)
{
if(resultType.isVoid())
{
throw new TextSourceException(String.format(
package.getResourceString("type.not-suitable.array-components"), new Object[] { resultType }
)) { source = source, position = position };
}
int dimCountCreate = 0;
Type typeInt = fldTypeInt;
Node result = code.createAndAppendNode(parent);
do
{
dimCountCreate++;
if(source.getLexemeKind(position = parseExpression(result, source, position + 1, isStaticOnly)) != BRACKET_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-bracket")) { source = source, position = position };
}
Node value = result[-1];
requiresValue(value);
Type valueType = value.type;
if(!typeInt.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, typeInt }
)) { source = source, position = position };
}
cast(value, typeInt);
if(dimCountCreate >= LIMIT_DIMENSIONS_COUNT || source.getLexemeKind(position + 1) != BRACKET_OPENED || source.getLexemeKind(position + 2) == BRACKET_CLOSED) break;
position++;
} while(true);
int dimCountTotal = dimCountCreate;
for(; dimCountTotal < LIMIT_DIMENSIONS_COUNT && source.getLexemeKind(position + 1) == BRACKET_OPENED && source.getLexemeKind(position + 2) == BRACKET_CLOSED; dimCountTotal++)
{
position += 2;
}
(resultType = acquireArrayType(resultType, dimCountTotal)).makeCompilable();
if(dimCountCreate <= 1)
{
result.setData(before, resultType, NEW_ARRAY_MONO, resultType);
} else
{
result.setData(before, resultType, NEW_ARRAY_MULTI, resultType);
Type typeInt01d = getArrayType(typeInt);
typeInt01d.makeCompilable();
ConstantFactory factory = fldConstantFactory;
Node array = code.createAndAppendNode(result).setData(before, typeInt01d, NEW_ARRAY, typeInt01d, factory.createInt(dimCountCreate));
for(int index = dimCountCreate; index-- > 0; )
{
Node value = result[index];
Node write = code.createAndPrependNode(array).setData(-1, null, WRITE_COMPONENT, typeInt);
code.createAndAppendNode(write).setData(-1, typeInt01d, DUP1, typeInt01d);
code.createAndAppendNode(write).setData(-1, typeInt, LOAD_CONST, factory.createInt(index));
code.moveNode(value, write, 2);
}
}
break;
}
if(resultType instanceof PrimitiveType && resultType.isVector())
{
if(source.getLexemeKind(position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
boolean isConstant = true;
Node result = code.createAndAppendNode(parent);
PrimitiveType vectorResultType = (PrimitiveType) resultType;
PrimitiveType vectorBaseType = vectorResultType.vectorBaseType;
int vectorResultLength = vectorResultType.vectorLength;
for(int index = 0; ; )
{
position = parseExpression(result, source, position + 1, isStaticOnly);
Node value = result[-1];
requiresValue(value);
Type valueType = value.type;
if(!vectorBaseType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, vectorBaseType }
)) { source = source, position = position };
}
if(cast(value, vectorBaseType).instruction != LOAD_CONST)
{
isConstant = false;
}
if(++index >= vectorResultLength)
{
break;
}
if(source.getLexemeKind(position) != COMMA)
{
throw new TextSourceException(package.getResourceString("expected.comma")) { source = source, position = position };
}
}
if(source.getLexemeKind(position) != CURLY_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
}
if(!isConstant)
{
result.setData(before, resultType, NEW_VECTOR, resultType);
} else
{
switch(vectorResultType.kind)
{
case DOUBLE2:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createDouble2(new double2 {
((Constant) result[0].operand1).asDouble(), ((Constant) result[1].operand1).asDouble()
}));
break;
case DOUBLE4:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createDouble4(new double4 {
((Constant) result[0].operand1).asDouble(), ((Constant) result[1].operand1).asDouble(),
((Constant) result[2].operand1).asDouble(), ((Constant) result[3].operand1).asDouble()
}));
break;
case DOUBLE8:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createDouble8(new double8 {
((Constant) result[0].operand1).asDouble(), ((Constant) result[1].operand1).asDouble(),
((Constant) result[2].operand1).asDouble(), ((Constant) result[3].operand1).asDouble(),
((Constant) result[4].operand1).asDouble(), ((Constant) result[5].operand1).asDouble(),
((Constant) result[6].operand1).asDouble(), ((Constant) result[7].operand1).asDouble()
}));
break;
case FLOAT2:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createFloat2(new float2 {
((Constant) result[0].operand1).asFloat(), ((Constant) result[1].operand1).asFloat()
}));
break;
case FLOAT4:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createFloat4(new float4 {
((Constant) result[0].operand1).asFloat(), ((Constant) result[1].operand1).asFloat(),
((Constant) result[2].operand1).asFloat(), ((Constant) result[3].operand1).asFloat()
}));
break;
case FLOAT8:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createFloat8(new float8 {
((Constant) result[0].operand1).asFloat(), ((Constant) result[1].operand1).asFloat(),
((Constant) result[2].operand1).asFloat(), ((Constant) result[3].operand1).asFloat(),
((Constant) result[4].operand1).asFloat(), ((Constant) result[5].operand1).asFloat(),
((Constant) result[6].operand1).asFloat(), ((Constant) result[7].operand1).asFloat()
}));
break;
case BYTE2:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createByte2(new byte2 {
((Constant) result[0].operand1).asByte(), ((Constant) result[1].operand1).asByte()
}));
break;
case BYTE4:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createByte4(new byte4 {
((Constant) result[0].operand1).asByte(), ((Constant) result[1].operand1).asByte(),
((Constant) result[2].operand1).asByte(), ((Constant) result[3].operand1).asByte()
}));
break;
case BYTE8:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createByte8(new byte8 {
((Constant) result[0].operand1).asByte(), ((Constant) result[1].operand1).asByte(),
((Constant) result[2].operand1).asByte(), ((Constant) result[3].operand1).asByte(),
((Constant) result[4].operand1).asByte(), ((Constant) result[5].operand1).asByte(),
((Constant) result[6].operand1).asByte(), ((Constant) result[7].operand1).asByte()
}));
break;
case SHORT2:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createShort2(new short2 {
((Constant) result[0].operand1).asShort(), ((Constant) result[1].operand1).asShort()
}));
break;
case SHORT4:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createShort4(new short4 {
((Constant) result[0].operand1).asShort(), ((Constant) result[1].operand1).asShort(),
((Constant) result[2].operand1).asShort(), ((Constant) result[3].operand1).asShort()
}));
break;
case SHORT8:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createShort8(new short8 {
((Constant) result[0].operand1).asShort(), ((Constant) result[1].operand1).asShort(),
((Constant) result[2].operand1).asShort(), ((Constant) result[3].operand1).asShort(),
((Constant) result[4].operand1).asShort(), ((Constant) result[5].operand1).asShort(),
((Constant) result[6].operand1).asShort(), ((Constant) result[7].operand1).asShort()
}));
break;
case INT2:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createInt2(new int2 {
((Constant) result[0].operand1).asInt(), ((Constant) result[1].operand1).asInt()
}));
break;
case INT4:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createInt4(new int4 {
((Constant) result[0].operand1).asInt(), ((Constant) result[1].operand1).asInt(),
((Constant) result[2].operand1).asInt(), ((Constant) result[3].operand1).asInt()
}));
break;
case INT8:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createInt8(new int8 {
((Constant) result[0].operand1).asInt(), ((Constant) result[1].operand1).asInt(),
((Constant) result[2].operand1).asInt(), ((Constant) result[3].operand1).asInt(),
((Constant) result[4].operand1).asInt(), ((Constant) result[5].operand1).asInt(),
((Constant) result[6].operand1).asInt(), ((Constant) result[7].operand1).asInt()
}));
break;
case LONG2:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createLong2(new long2 {
((Constant) result[0].operand1).asLong(), ((Constant) result[1].operand1).asLong()
}));
break;
case LONG4:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createLong4(new long4 {
((Constant) result[0].operand1).asLong(), ((Constant) result[1].operand1).asLong(),
((Constant) result[2].operand1).asLong(), ((Constant) result[3].operand1).asLong()
}));
break;
case LONG8:
result.setData(before, resultType, LOAD_CONST, fldConstantFactory.createLong8(new long8 {
((Constant) result[0].operand1).asLong(), ((Constant) result[1].operand1).asLong(),
((Constant) result[2].operand1).asLong(), ((Constant) result[3].operand1).asLong(),
((Constant) result[4].operand1).asLong(), ((Constant) result[5].operand1).asLong(),
((Constant) result[6].operand1).asLong(), ((Constant) result[7].operand1).asLong()
}));
}
code.removeChilds(result);
}
break;
}
if(resultType.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.instantiate.abstract-type"), new Object[] { resultType }
)) { source = source, position = before + 1 };
}
if(resultType instanceof ClassType)
{
if(source.getLexemeKind(position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
resultType.makeCompilable();
Node result = code.createAndAppendNode(parent).setData(before, resultType, NEW_INSTANCE, resultType);
Node constructor = code.createAndAppendNode(result);
ClassType objectResultType = (ClassType) resultType;
label1: if(source.getLexemeKind(++position) != PARENTH_CLOSED) do
{
position = parseExpression(constructor, source, position, isStaticOnly);
requiresValue(constructor[-1]);
switch(source.getLexemeKind(position))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
case PARENTH_CLOSED:
break label1;
case COMMA:
position++;
}
} while(true);
int length = constructor.length;
Type[] arguments = new Type[length];
for(int index = 0; index < length; index++) arguments[index] = constructor[index].type;
InstInit[] foundConstructors = objectResultType.findConstructors(arguments, enclosingClassType);
int foundLength = foundConstructors == null ? 0 : foundConstructors.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("not-found.constructor"), new Object[] { objectResultType, ArgumentArray.toString(arguments) }
)) { source = source, position = before + 1 };
}
InstInit foundConstructor = foundConstructors[0];
if(!foundConstructor.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.constructor"), new Object[] { foundConstructor, ArgumentArray.toString(arguments) }
)) { source = source, position = before + 1 };
}
if(!foundConstructor.isVisibleFrom(enclosingClassType, objectResultType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.constructor"), new Object[] { enclosingClassType.specialSimpleName, foundConstructor }
)) { source = source, position = before + 1 };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.constructor"), new Object[] { objectResultType.specialCanonicalName + ArgumentArray.toString(arguments) }
)) { source = source, position = before + 1 };
}
for(ArgumentArray foundArguments = foundConstructor.arguments, int index = 0; index < length; index++) cast(constructor[index], foundArguments[index].type);
code.createAndPrependNode(constructor).setData(-1, resultType, DUP1, resultType);
constructor.setData(before + 1, foundConstructor.type, INVOKE_SPECIAL, foundConstructor);
Callable foundMethod = fldTypeObject.getChildCallable("afterConstruction", (Type[]) null);
if(foundMethod != null && !foundMethod.isStatic() && foundMethod.type.isVoid() && !foundMethod.canThrown())
{
Node method = code.createAndAppendNode(result).setData(-1, fldTypeVoid, foundMethod.visibility <= PRIVATE ? INVOKE_SPECIAL : INVOKE_VIRTUAL, foundMethod);
code.createAndPrependNode(method).setData(-1, resultType, DUP1, resultType);
}
if(source.getLexemeKind(position + 1) == CURLY_OPENED && source.getLexemeKind(position += 2) != CURLY_CLOSED) do
{
if(source.getLexemeKind(position) != L_NAME)
{
throw new TextSourceException(String.format(
package.getResourceString("expected.name.fieldoid"), new Object[] { objectResultType }
)) { source = source, position = position };
}
String name = source.getLexemeString(position);
TypedMember[] foundFieldoids = objectResultType.findFieldoids(name, enclosingClassType);
if((foundLength = foundFieldoids == null ? 0 : foundFieldoids.length) < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { objectResultType, name }
)) { source = source, position = position };
}
TypedMember foundFieldoid = foundFieldoids[0];
if(!foundFieldoid.isVisibleFrom(enclosingClassType, objectResultType))
{
throw new TextSourceException(String.format(
package.getResourceString(foundFieldoid instanceof Property ? "invisible.property" : "invisible.field"),
new Object[] { enclosingClassType.specialSimpleName, foundFieldoid }
)) { source = source, position = position };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.fieldoid"), new Object[] { new StringBuilder(0x0400) + objectResultType.specialCanonicalName + '.' + name }
)) { source = source, position = position };
}
Node write = code.createAndAppendNode(result);
if(foundFieldoid instanceof Field)
{
if(foundFieldoid.isStatic() || foundFieldoid.isFinal())
{
throw new TextSourceException(String.format(
package.getResourceString("must-be.instance-writeable-field"), new Object[] { foundFieldoid }
)) { source = source, position = position };
}
write.setData(position + 1, null, WRITE_FIELD, foundFieldoid);
}
else if(foundFieldoid instanceof Property)
{
if(foundFieldoid.isStatic() || !((Property) foundFieldoid).hasWrite())
{
throw new TextSourceException(String.format(
package.getResourceString("must-be.writeable-property"), new Object[] { foundFieldoid }
)) { source = source, position = position };
}
write.setData(position + 1, null, WRITE_PROPERTY, foundFieldoid);
}
else
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.fieldoid"), new Object[] { objectResultType, name }
)) { source = source, position = position };
}
if(source.getLexemeKind(++position) != EQUALS)
{
throw new TextSourceException(package.getResourceString("expected.equals")) { source = source, position = position };
}
code.createAndPrependNode(write).setData(position - 1, resultType, DUP1, resultType);
position = parseExpression(write, source, position + 1, isStaticOnly);
Node value = write[-1];
requiresValue(value);
Type fieldType = foundFieldoid.type;
Type valueType = value.type;
if(!fieldType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, fieldType }
)) { source = source, position = position };
}
cast(value, fieldType);
switch(source.getLexemeKind(position))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
case CURLY_CLOSED:
break label0;
case COMMA:
position++;
}
} while(true);
break;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.instantiate.type"), new Object[] { resultType }
)) { source = source, position = before + 1 };
case VOID:
case BOOLEAN:
case CHAR:
case REAL:
case DOUBLE:
case DOUBLE2:
case DOUBLE4:
case DOUBLE8:
case FLOAT:
case FLOAT2:
case FLOAT4:
case FLOAT8:
case BYTE:
case BYTE2:
case BYTE4:
case BYTE8:
case SHORT:
case SHORT2:
case SHORT4:
case SHORT8:
case INT:
case INT2:
case INT4:
case INT8:
case LONG:
case LONG2:
case LONG4:
case LONG8:
case L_NAME:
int before = position;
TableItem foundItem;
String name = source.getLexemeString(position);
ImmediateBuilderItemHolder tableItemHolder = getItemHolder();
tableItemHolder.helpersAllowed = true;
try
{
if(operation != L_NAME)
{
position = parseTypeName(source, before, enclosingClassType, tableItemHolder) - 1;
foundItem = tableItemHolder.resultItem;
} else
{
position = tryParseName(parent, source, before, name, tableItemHolder) - 1;
if((foundItem = tableItemHolder.resultItem) == null)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.some-variable"), new Object[] { name }
)) { source = source, position = before };
}
if(foundItem instanceof Type)
{
position = parseTypeName(source, before, enclosingClassType, tableItemHolder) - 1;
foundItem = tableItemHolder.resultItem;
}
}
} finally
{
tableItemHolder.helpersAllowed = false;
}
if(foundItem instanceof Local)
{
Local foundLocal = (Local) foundItem;
if(foundLocal.isConstant())
{
Constant foundValue = foundLocal.value;
code.createAndAppendNode(parent).setData(before, foundValue.type, LOAD_CONST, foundValue);
break;
}
code.createAndAppendNode(parent).setData(before, foundLocal.type, LOAD_LOCAL, foundLocal);
break;
}
if(foundItem instanceof Member)
{
Local foundWith = tableItemHolder.resultWith;
if(foundWith == null || isStaticOnly)
{
code.createAndAppendNode(parent).setData(before, null, CLASS, enclosingClassType);
}
else if(!foundWith.isConstant())
{
code.createAndAppendNode(parent).setData(before, foundWith.type, LOAD_LOCAL, foundWith);
}
else
{
Constant foundValue = foundWith.value;
code.createAndAppendNode(parent).setData(before, foundValue.type, LOAD_CONST, foundValue);
}
isImplicitPeriod = true;
position = before;
break;
}
if(foundItem instanceof ClassType)
{
if(source.getLexemeKind(++position) != PERIOD)
{
throw new TextSourceException(package.getResourceString("expected.period")) { source = source, position = position };
}
switch(source.getLexemeKind(++position))
{
case SUPER:
if(isStaticOnly)
{
throw new TextSourceException(package.getResourceString("can-not-reference.this")) { source = source, position = position };
}
if(enclosingCallable.isStatic())
{
throw new TextSourceException(package.getResourceString("can-not-use.static.this")) { source = source, position = position };
}
if(enclosingClassType.isHelper())
{
throw new TextSourceException(package.getResourceString("can-not-use.helper.super")) { source = source, position = position };
}
ClassType foundClassType = (ClassType) foundItem;
if(foundClassType.isHelper())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.some-variable"), new Object[] { name }
)) { source = source, position = before };
}
if(foundClassType.isClass() ? enclosingClassType.getSuperclassType() != foundClassType : !enclosingClassType.isSuperservice(foundClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("type.not-direct-supertype"), new Object[] { enclosingClassType.specialSimpleName, foundClassType }
)) { source = source, position = position };
}
code.createAndAppendNode(parent).setData(before, foundClassType, LOAD_LOCAL, enclosingCallable.arguments.thisArgument).useSuper = true;
break label0;
case CLASS:
Type foundType = (Type) foundItem;
foundType.makeCompilable();
code.createAndAppendNode(parent).setData(before, fldTypeClass, LOAD_CONST, fldConstantFactory.createClass(foundType));
break label0;
case L_NAME:
ClassType foundClassType = (ClassType) foundItem;
if(foundClassType.isHelper())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.some-variable"), new Object[] { name }
)) { source = source, position = before };
}
code.createAndAppendNode(parent).setData(before, null, CLASS, foundItem);
isImplicitPeriod = true;
break label0;
default:
throw new TextSourceException(package.getResourceString("expected.name.static-member")) { source = source, position = position };
}
}
if(foundItem instanceof PrimitiveType)
{
if(source.getLexemeKind(++position) != PERIOD)
{
throw new TextSourceException(package.getResourceString("expected.period")) { source = source, position = position };
}
if(source.getLexemeKind(++position) != CLASS)
{
throw new TextSourceException(package.getResourceString("expected.class")) { source = source, position = position };
}
Type foundType = (Type) foundItem;
foundType.makeCompilable();
code.createAndAppendNode(parent).setData(before, fldTypeClass, LOAD_CONST, fldConstantFactory.createClass(foundType));
break;
}
if(foundItem instanceof Package)
{
if(source.getLexemeKind(++position) != PERIOD)
{
throw new TextSourceException(package.getResourceString("expected.period")) { source = source, position = position };
}
if(source.getLexemeKind(++position) != PACKAGE)
{
throw new TextSourceException(package.getResourceString("expected.package")) { source = source, position = position };
}
code.createAndAppendNode(parent).setData(before, fldTypePackage, LOAD_CONST, fldConstantFactory.createPackage((Package) foundItem));
break;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.some-variable"), new Object[] { name }
)) { source = source, position = before };
case OPERATOR:
{
ImmediateBuilderItemHolder operatorHolder = getItemHolder();
parseOperator(source, position + 1, operatorHolder);
int kind = operatorHolder.resultKind;
tryParseName(parent, source, position, Operator.kindToSpecialSimpleName(kind), operatorHolder);
TableItem foundItem = operatorHolder.resultItem;
if(foundItem == null)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.some-operator"), new Object[] { VIEWNAME_OPERATOR + Operator.kindToSymbol(kind) }
)) { source = source, position = position };
}
Local foundWith = operatorHolder.resultWith;
if(foundWith == null || isStaticOnly)
{
code.createAndAppendNode(parent).setData(position, null, CLASS, enclosingClassType);
}
else if(!foundWith.isConstant())
{
code.createAndAppendNode(parent).setData(position, foundWith.type, LOAD_LOCAL, foundWith);
}
else
{
Constant foundValue = foundWith.value;
code.createAndAppendNode(parent).setData(position, foundValue.type, LOAD_CONST, foundValue);
}
isImplicitPeriod = true;
break;
}
case NULL:
{
code.createAndAppendNode(parent).setData(position, fldTypeNull, LOAD_CONST, fldNull);
break;
}
case CLASS:
{
code.createAndAppendNode(parent).setData(position, fldTypeClass, LOAD_CONST, fldConstantFactory.createClass(enclosingClassType));
break;
}
case PACKAGE:
{
code.createAndAppendNode(parent).setData(position, fldTypePackage, LOAD_CONST, fldConstantFactory.createPackage(enclosingClassType.parentPackage));
break;
}
case L_STRING:
{
code.createAndAppendNode(parent).setData(position, fldTypeString, LOAD_CONST, fldConstantFactory.createString(source.getLexemeString(position)));
break;
}
case L_BOOLEAN:
{
code.createAndAppendNode(parent).setData(position, fldTypeBoolean, LOAD_CONST, source.getLexemeBoolean(position) == false ? fldFalse : fldTrue);
break;
}
case L_CHAR:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(CHAR), LOAD_CONST, fldConstantFactory.createChar(source.getLexemeChar(position)));
break;
}
case L_REAL:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(REAL), LOAD_CONST, fldConstantFactory.createReal(source.getLexemeReal(position)));
break;
}
case L_DOUBLE:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(DOUBLE), LOAD_CONST, fldConstantFactory.createDouble(source.getLexemeDouble(position)));
break;
}
case L_FLOAT:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(FLOAT), LOAD_CONST, fldConstantFactory.createFloat(source.getLexemeFloat(position)));
break;
}
case L_BYTE:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(BYTE), LOAD_CONST, fldConstantFactory.createByte((byte) source.getLexemeInt(position)));
break;
}
case L_SHORT:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(SHORT), LOAD_CONST, fldConstantFactory.createShort((short) source.getLexemeInt(position)));
break;
}
case L_INT:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(INT), LOAD_CONST, fldConstantFactory.createInt(source.getLexemeInt(position)));
break;
}
case L_LONG:
{
code.createAndAppendNode(parent).setData(position, getPrimitiveType(LONG), LOAD_CONST, fldConstantFactory.createLong(source.getLexemeLong(position)));
break;
}
default:
throw new TextSourceException(package.getResourceString("error.expression")) { source = source, position = position };
}
return parsePostfix(parent, source, isImplicitPeriod ? position : position + 1, isStaticOnly, isImplicitPeriod);
}
private int parsePrefix(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
Code code = parent.parentCode;
Callable enclosingCallable = code.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
Vector stack = null;
label0: for(; ; position++)
{
int operation = source.getLexemeKind(position);
switch(operation)
{
case INC_LOCAL:
case DEC_LOCAL:
case BOOL_NOT:
case O_BIT_NOT:
case O_VECT_LUP:
case O_VECT_UUP:
case O_VECT_PCK:
if(stack == null) stack = new Vector();
stack.append(new ImmediateBuilderUnaryOperation(position, operation));
break;
case O_SCAL_ADD:
if(stack == null) stack = new Vector();
stack.append(new ImmediateBuilderUnaryOperation(position, O_SCAL_POS));
break;
case O_SCAL_SUB:
if(stack == null) stack = new Vector();
stack.append(new ImmediateBuilderUnaryOperation(position, O_SCAL_NEG));
break;
case O_VECT_ADD:
if(stack == null) stack = new Vector();
stack.append(new ImmediateBuilderUnaryOperation(position, O_VECT_POS));
break;
case O_VECT_SUB:
if(stack == null) stack = new Vector();
stack.append(new ImmediateBuilderUnaryOperation(position, O_VECT_NEG));
break;
case PARENTH_OPENED:
int before = position++;
ImmediateBuilderItemHolder newTypeHolder = getItemHolder();
position = source.getLexemeKind(position) != L_NAME ? (
tryParseTypeName(source, position, enclosingClassType, newTypeHolder)
) : (
tryParseName(parent, source, position, source.getLexemeString(position), newTypeHolder)
);
Type newType = newTypeHolder.resultType;
if(source.getLexemeKind(position) != PARENTH_CLOSED || newType == null || !newType.isVisibleFrom(enclosingClassType))
{
position = before;
break label0;
}
if(stack == null) stack = new Vector();
stack.append(new ImmediateBuilderUnaryOperation(before, CAST_TO, newType));
break;
default:
break label0;
}
}
position = parsePrimary(parent, source, position, isStaticOnly);
if(stack != null) for(PrimitiveType typeInt = fldTypeInt, ConstantFactory factory = fldConstantFactory, Node child1 = parent[-1], int index = stack.length; index-- > 0; )
{
ImmediateBuilderUnaryOperation item = (ImmediateBuilderUnaryOperation) stack[index];
Type argument1Type = child1.type;
int operation = item.operation;
int before = item.position;
label0:
{
if(argument1Type instanceof NullType)
{
if(operation == CAST_TO)
{
Type newType = item.newType;
if(newType instanceof ClassType)
{
Node result = code.createAndAppendNode(parent).setData(before, newType, NOP);
code.moveNode(child1, child1 = result, 0);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.type-cast"), new Object[] { argument1Type, newType }
)) { source = source, position = before };
}
break label0;
}
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
switch(operation)
{
case O_BIT_NOT:
case O_SCAL_POS:
case O_SCAL_NEG:
case O_VECT_LUP:
case O_VECT_UUP:
case O_VECT_PCK:
case O_VECT_POS:
case O_VECT_NEG:
{
Operator[] foundOperators = dereferenceClassType.findOperators(operation, null, enclosingClassType);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(null))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(null) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosingClassType, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosingClassType.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
continue;
}
case CAST_TO:
Type newType = item.newType;
if(newType instanceof ClassType)
{
if(newType == argument1Type || newType.isAssignableFrom(argument1Type))
{
Node result = code.createAndAppendNode(parent).setData(before, newType, NOP);
code.moveNode(child1, child1 = result, 0);
continue;
}
if(newType.isCompatibleWith(argument1Type))
{
newType.makeCompilable();
Node result = code.createAndAppendNode(parent).setData(before, newType, CAST_TO, newType, argument1Type);
code.moveNode(child1, child1 = result, 0);
continue;
}
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.type-cast"), new Object[] { argument1Type, newType }
)) { source = source, position = before };
}
break label0;
}
if(argument1Type instanceof PrimitiveType)
{
int kind = argument1Type.kind;
int instruction = child1.instruction;
if(kind == CHAR)
{
kind = INT;
argument1Type = typeInt;
}
if(instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
label1: switch(operation)
{
case BOOL_NOT:
if(kind == BOOLEAN)
{
result = operand1.asBoolean() ? fldFalse : fldTrue;
break label1;
}
break label0;
case O_BIT_NOT:
switch(kind)
{
case BYTE:
result = factory.createByte(~operand1.asByte());
break label1;
case BYTE2:
result = factory.createByte2(~operand1.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(~operand1.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(~operand1.asByte8());
break label1;
case SHORT:
result = factory.createShort(~operand1.asShort());
break label1;
case SHORT2:
result = factory.createShort2(~operand1.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(~operand1.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(~operand1.asShort8());
break label1;
case INT:
result = factory.createInt(~operand1.asInt());
break label1;
case INT2:
result = factory.createInt2(~operand1.asInt2());
break label1;
case INT4:
result = factory.createInt4(~operand1.asInt4());
break label1;
case INT8:
result = factory.createInt8(~operand1.asInt8());
break label1;
case LONG:
result = factory.createLong(~operand1.asLong());
break label1;
case LONG2:
result = factory.createLong2(~operand1.asLong2());
break label1;
case LONG4:
result = factory.createLong4(~operand1.asLong4());
break label1;
case LONG8:
result = factory.createLong8(~operand1.asLong8());
break label1;
}
break label0;
case O_SCAL_POS:
switch(kind)
{
case REAL:
case DOUBLE:
case DOUBLE2:
case DOUBLE4:
case DOUBLE8:
case FLOAT:
case FLOAT2:
case FLOAT4:
case FLOAT8:
case BYTE:
case SHORT:
case INT:
case INT2:
case INT4:
case INT8:
case LONG:
case LONG2:
case LONG4:
case LONG8:
result = operand1;
break label1;
case BYTE2:
result = factory.createInt2(operand1.asByte2());
break label1;
case BYTE4:
result = factory.createInt4(operand1.asByte4());
break label1;
case BYTE8:
result = factory.createInt8(operand1.asByte8());
break label1;
case SHORT2:
result = factory.createInt2(operand1.asShort2());
break label1;
case SHORT4:
result = factory.createInt4(operand1.asShort4());
break label1;
case SHORT8:
result = factory.createInt8(operand1.asShort8());
break label1;
}
break label0;
case O_SCAL_NEG:
switch(kind)
{
case REAL:
result = factory.createReal(-operand1.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(-operand1.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(-operand1.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(-operand1.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(-operand1.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(-operand1.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(-operand1.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(-operand1.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(-operand1.asFloat8());
break label1;
case BYTE:
result = factory.createIntegral(-operand1.asByte());
break label1;
case BYTE2:
result = factory.createInt2(-operand1.asByte2());
break label1;
case BYTE4:
result = factory.createInt4(-operand1.asByte4());
break label1;
case BYTE8:
result = factory.createInt8(-operand1.asByte8());
break label1;
case SHORT:
result = factory.createIntegral(-operand1.asShort());
break label1;
case SHORT2:
result = factory.createInt2(-operand1.asShort2());
break label1;
case SHORT4:
result = factory.createInt4(-operand1.asShort4());
break label1;
case SHORT8:
result = factory.createInt8(-operand1.asShort8());
break label1;
case INT:
result = factory.createIntegral(-operand1.asInt());
break label1;
case INT2:
result = factory.createInt2(-operand1.asInt2());
break label1;
case INT4:
result = factory.createInt4(-operand1.asInt4());
break label1;
case INT8:
result = factory.createInt8(-operand1.asInt8());
break label1;
case LONG:
result = factory.createLong(-operand1.asLong());
break label1;
case LONG2:
result = factory.createLong2(-operand1.asLong2());
break label1;
case LONG4:
result = factory.createLong4(-operand1.asLong4());
break label1;
case LONG8:
result = factory.createLong8(-operand1.asLong8());
break label1;
}
break label0;
case O_VECT_POS:
switch(kind)
{
case DOUBLE:
case DOUBLE2:
case DOUBLE4:
case DOUBLE8:
case FLOAT:
case FLOAT2:
case FLOAT4:
case FLOAT8:
case BYTE:
case BYTE2:
case BYTE4:
case BYTE8:
case SHORT:
case SHORT2:
case SHORT4:
case SHORT8:
case INT:
case INT2:
case INT4:
case INT8:
case LONG:
case LONG2:
case LONG4:
case LONG8:
result = operand1;
break label1;
}
break label0;
case O_VECT_NEG:
switch(kind)
{
case DOUBLE:
result = factory.createDouble(----operand1.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(----operand1.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(----operand1.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(----operand1.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(----operand1.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(----operand1.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(----operand1.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(----operand1.asFloat8());
break label1;
case BYTE:
result = factory.createByte(----operand1.asByte());
break label1;
case BYTE2:
result = factory.createByte2(----operand1.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(----operand1.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(----operand1.asByte8());
break label1;
case SHORT:
result = factory.createShort(----operand1.asShort());
break label1;
case SHORT2:
result = factory.createShort2(----operand1.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(----operand1.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(----operand1.asShort8());
break label1;
case INT:
result = factory.createInt(----operand1.asInt());
break label1;
case INT2:
result = factory.createInt2(----operand1.asInt2());
break label1;
case INT4:
result = factory.createInt4(----operand1.asInt4());
break label1;
case INT8:
result = factory.createInt8(----operand1.asInt8());
break label1;
case LONG:
result = factory.createLong(----operand1.asLong());
break label1;
case LONG2:
result = factory.createLong2(----operand1.asLong2());
break label1;
case LONG4:
result = factory.createLong4(----operand1.asLong4());
break label1;
case LONG8:
result = factory.createLong8(----operand1.asLong8());
break label1;
}
break label0;
case O_VECT_PCK:
if(kind >= BYTE && kind <= BYTE8)
{
operand1 = operand1.castTo(getPrimitiveType(kind += SHORT - BYTE));
}
switch(kind)
{
case SHORT:
result = factory.createByte(@@@@operand1.asShort());
break label1;
case SHORT2:
result = factory.createByte2(@@@@operand1.asShort2());
break label1;
case SHORT4:
result = factory.createByte4(@@@@operand1.asShort4());
break label1;
case SHORT8:
result = factory.createByte8(@@@@operand1.asShort8());
break label1;
case INT:
result = factory.createShort(@@@@operand1.asInt());
break label1;
case INT2:
result = factory.createShort2(@@@@operand1.asInt2());
break label1;
case INT4:
result = factory.createShort4(@@@@operand1.asInt4());
break label1;
case INT8:
result = factory.createShort8(@@@@operand1.asInt8());
break label1;
case LONG:
result = factory.createInt(@@@@operand1.asLong());
break label1;
case LONG2:
result = factory.createInt2(@@@@operand1.asLong2());
break label1;
case LONG4:
result = factory.createInt4(@@@@operand1.asLong4());
break label1;
case LONG8:
result = factory.createInt8(@@@@operand1.asLong8());
break label1;
}
break label0;
case O_VECT_LUP:
switch(kind)
{
case BYTE:
result = factory.createShort(####operand1.asByte());
break label1;
case BYTE2:
result = factory.createShort2(####operand1.asByte2());
break label1;
case BYTE4:
result = factory.createShort4(####operand1.asByte4());
break label1;
case BYTE8:
result = factory.createShort8(####operand1.asByte8());
break label1;
case SHORT:
result = factory.createInt(####operand1.asShort());
break label1;
case SHORT2:
result = factory.createInt2(####operand1.asShort2());
break label1;
case SHORT4:
result = factory.createInt4(####operand1.asShort4());
break label1;
case SHORT8:
result = factory.createInt8(####operand1.asShort8());
break label1;
case INT:
result = factory.createLong(####operand1.asInt());
break label1;
case INT2:
result = factory.createLong2(####operand1.asInt2());
break label1;
case INT4:
result = factory.createLong4(####operand1.asInt4());
break label1;
case INT8:
result = factory.createLong8(####operand1.asInt8());
break label1;
}
break label0;
case O_VECT_UUP:
switch(kind)
{
case BYTE:
result = factory.createShort(^^^^operand1.asByte());
break label1;
case BYTE2:
result = factory.createShort2(^^^^operand1.asByte2());
break label1;
case BYTE4:
result = factory.createShort4(^^^^operand1.asByte4());
break label1;
case BYTE8:
result = factory.createShort8(^^^^operand1.asByte8());
break label1;
case SHORT:
result = factory.createInt(^^^^operand1.asShort());
break label1;
case SHORT2:
result = factory.createInt2(^^^^operand1.asShort2());
break label1;
case SHORT4:
result = factory.createInt4(^^^^operand1.asShort4());
break label1;
case SHORT8:
result = factory.createInt8(^^^^operand1.asShort8());
break label1;
case INT:
result = factory.createLong(^^^^operand1.asInt());
break label1;
case INT2:
result = factory.createLong2(^^^^operand1.asInt2());
break label1;
case INT4:
result = factory.createLong4(^^^^operand1.asInt4());
break label1;
case INT8:
result = factory.createLong8(^^^^operand1.asInt8());
break label1;
}
break label0;
case CAST_TO:
Type newType = item.newType;
if(newType.isBoolean() && argument1Type.isBoolean())
{
result = operand1;
break label1;
}
if(newType.isNumeric() && argument1Type.isNumeric())
{
result = operand1.castTo(newType);
break label1;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.type-cast"), new Object[] { argument1Type, newType }
)) { source = source, position = before };
case INC_LOCAL:
case DEC_LOCAL:
throw new TextSourceException(String.format(
package.getResourceString("applicable.operator.increment-decrement"), new Object[] { source.getLexemeString(before) }
)) { source = source, position = before };
}
child1.setData(before, result.type, LOAD_CONST, result);
continue;
}
Type resultType;
switch(operation)
{
case BOOL_NOT:
if(kind == BOOLEAN)
{
resultType = argument1Type;
break;
}
break label0;
case O_BIT_NOT:
if(kind >= BYTE && kind <= LONG8)
{
resultType = argument1Type;
break;
}
break label0;
case O_SCAL_POS:
if(kind >= BYTE && kind <= SHORT8)
{
resultType = getPrimitiveType(INT + (kind & 3));
Node result = kind != BYTE && kind != SHORT ? (
code.createAndAppendNode(parent).setData(before, resultType, CAST_TO, resultType, argument1Type)
) : (
code.createAndAppendNode(parent).setData(before, resultType, NOP)
);
code.moveNode(child1, child1 = result, 0);
continue;
}
if(argument1Type.isNumeric())
{
Node result = code.createAndAppendNode(parent).setData(before, argument1Type, NOP);
code.moveNode(child1, child1 = result, 0);
continue;
}
break label0;
case O_SCAL_NEG:
if(kind >= BYTE && kind <= SHORT8)
{
resultType = getPrimitiveType(INT + (kind & 3));
if(kind != BYTE && kind != SHORT)
{
Node result = code.createAndAppendNode(parent).setData(before, resultType, CAST_TO, resultType, argument1Type);
code.moveNode(child1, child1 = result, 0);
}
argument1Type = resultType;
break;
}
if(argument1Type.isNumeric())
{
resultType = argument1Type;
break;
}
break label0;
case O_VECT_POS:
if(kind >= DOUBLE && kind <= LONG8)
{
Node result = code.createAndAppendNode(parent).setData(before, argument1Type, NOP);
code.moveNode(child1, child1 = result, 0);
continue;
}
break label0;
case O_VECT_NEG:
if(kind >= DOUBLE && kind <= LONG8)
{
resultType = argument1Type;
break;
}
break label0;
case O_VECT_PCK:
if(kind >= BYTE && kind <= BYTE8)
{
resultType = getPrimitiveType(kind += SHORT - BYTE);
Node result = code.createAndAppendNode(parent).setData(before, resultType, CAST_TO, resultType, argument1Type);
code.moveNode(child1, child1 = result, 0);
argument1Type = resultType;
}
if(kind >= SHORT && kind <= LONG8)
{
resultType = getPrimitiveType(kind + (BYTE - SHORT));
break;
}
break label0;
case O_VECT_LUP:
case O_VECT_UUP:
if(kind >= BYTE && kind <= INT8)
{
resultType = getPrimitiveType(kind + (SHORT - BYTE));
break;
}
break label0;
case CAST_TO:
Type newType = item.newType;
if(newType.isBoolean() && argument1Type.isBoolean())
{
Node result = code.createAndAppendNode(parent).setData(before, newType, NOP);
code.moveNode(child1, child1 = result, 0);
continue;
}
if(newType.isNumeric() && argument1Type.isNumeric())
{
Node result = newType != argument1Type ? (
code.createAndAppendNode(parent).setData(before, newType, CAST_TO, newType, argument1Type)
) : (
code.createAndAppendNode(parent).setData(before, newType, NOP)
);
code.moveNode(child1, child1 = result, 0);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.type-cast"), new Object[] { argument1Type, newType }
)) { source = source, position = before };
case INC_LOCAL:
case DEC_LOCAL:
switch(instruction)
{
case LOAD_LOCAL:
{
Local foundLocal = (Local) child1.operand1;
if(foundLocal.isFinal())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.local-final.write"), new Object[] { foundLocal }
)) { source = source, position = before };
}
if(!((argument1Type = foundLocal.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
child1.setData(child1.position, argument1Type, operation == INC_LOCAL ? INC_PRED_LOAD_LOCAL : DEC_PRED_LOAD_LOCAL, foundLocal);
continue;
}
case LOAD_STATIC:
{
Field foundField = (Field) child1.operand1;
if(foundField.isFinal() && (!(enclosingCallable instanceof ClassInit) || foundField.parentType != enclosingClassType || foundField.value != null))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundField }
)) { source = source, position = before };
}
if(!((argument1Type = foundField.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
code.createAndPrependNode(delta).setData(child1.position, argument1Type, LOAD_STATIC, foundField);
code.createAndAppendNode(child1).setData(-1, null, DUP1, argument1Type);
child1.setData(-1, argument1Type, STORE_STATIC, foundField);
continue;
}
case READ_FIELD:
case READ_SPECIAL:
case READ_PROPERTY:
{
TypedMember foundFieldoid = (TypedMember) child1.operand1;
if(foundFieldoid instanceof Property)
{
if(!((Property) foundFieldoid).hasWrite())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.property-read-only.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
} else
{
Node load = child1[0];
if(
foundFieldoid.isFinal() && (
!(enclosingCallable instanceof InstInit) || foundFieldoid.parentType != enclosingClassType ||
load.instruction != LOAD_LOCAL || load.operand1 != enclosingCallable.arguments.thisArgument
)
)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
}
if(!((argument1Type = foundFieldoid.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
Node read = code.createAndPrependNode(delta).setData(child1.position, argument1Type, instruction, foundFieldoid);
code.createAndAppendNode(read).setData(-1, null, DUP1, fldTypeObject);
code.createAndAppendNode(child1).setData(-1, null, DUP1X1, argument1Type);
child1.setData(-1, argument1Type, instruction + A_DELTA, foundFieldoid);
continue;
}
case READ_COMPONENT:
{
if(!((argument1Type = (Type) child1.operand1) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
Node read = code.createAndPrependNode(delta).setData(child1.position, argument1Type, READ_COMPONENT, argument1Type);
code.createAndAppendNode(read).setData(-1, null, DUP2, fldTypeInt);
code.createAndAppendNode(child1).setData(-1, null, DUP1X2, argument1Type);
child1.setData(-1, argument1Type, WRITE_COMPONENT, argument1Type);
continue;
}
case INVOKE_SERVICE:
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
Operator foundReadOperator;
TableItem foundCallable = child1.operand1;
if(foundCallable instanceof Operator && (foundReadOperator = (Operator) foundCallable).kind == READ_COMPONENT)
{
if(!((argument1Type = foundReadOperator.type) instanceof PrimitiveType) || !argument1Type.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
Node load = child1[0];
ClassType dereferenceClassType = (ClassType) load.type;
Type[] arguments = new Type[] { foundReadOperator.arguments[0].type, argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(WRITE_COMPONENT, arguments, enclosingClassType);
Operator foundWriteOperator = foundOperators == null || foundOperators.length != 1 ? null : foundOperators[0];
if(foundWriteOperator == null || !foundWriteOperator.isIdentityArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-found.operator"),
new Object[] { dereferenceClassType, Operator.kindToSymbol(WRITE_COMPONENT) + ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
boolean isUseSuper = load.useSuper;
if(!foundWriteOperator.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosingClassType.specialSimpleName, foundWriteOperator }
)) { source = source, position = before };
}
if(isUseSuper && foundWriteOperator.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.operator"), new Object[] { foundWriteOperator }
)) { source = source, position = before };
}
Node delta = appendIncrementCode(child1, (PrimitiveType) argument1Type, operation == INC_LOCAL);
Node read = code.createAndPrependNode(delta).setData(child1.position, argument1Type, instruction, foundReadOperator);
code.createAndAppendNode(read).setData(-1, null, DUP2, arguments[0]);
code.createAndAppendNode(child1).setData(-1, null, DUP1X2, argument1Type);
child1.setData(-1, argument1Type, isUseSuper ? INVOKE_SPECIAL : invokeInstructionFor(foundWriteOperator, dereferenceClassType), foundWriteOperator);
continue;
}
}
throw new TextSourceException(String.format(
package.getResourceString("applicable.operator.increment-decrement"), new Object[] { source.getLexemeString(before) }
)) { source = source, position = before };
}
Node result = code.createAndAppendNode(parent).setData(before, resultType, operation, operation == BOOL_NOT ? null : argument1Type);
code.moveNode(child1, child1 = result, 0);
continue;
}
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"),
new Object[] { operation != CAST_TO ? source.getLexemeString(before) : package.getResourceString("operator.type-cast"), argument1Type }
)) { source = source, position = before };
}
return position;
}
private int parseMultiplicative(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
int operation = source.getLexemeKind(position = parsePrefix(parent, source, position, isStaticOnly));
if(
operation == O_SCAL_MUL || operation == O_SCAL_DIV || operation == O_SCAL_DIVU || operation == O_SCAL_REM || operation == O_SCAL_REMU ||
operation == O_VECT_MUL || operation == O_VECT_DIV || operation == O_VECT_HMUL || operation == O_VECT_HMULU
)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
position = parsePrefix(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
label1:
{
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
if(!(argument1Type instanceof PrimitiveType)) break label0;
Type commonType = operation >= O_VECT_OPERATOR ? argument1Type.getVectorCommonType(argument2Type) : argument1Type.getScalarCommonType(argument2Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
label1: switch(operation)
{
case O_SCAL_MUL:
switch(kind)
{
case REAL:
result = factory.createReal(operand1.asReal() * operand2.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(operand1.asDouble() * operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() * operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() * operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() * operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() * operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() * operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() * operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() * operand2.asFloat8());
break label1;
case INT:
result = factory.createIntegral(operand1.asInt() * operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() * operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() * operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() * operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() * operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() * operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() * operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() * operand2.asLong8());
break label1;
}
break label0;
case O_SCAL_DIV:
if((kind == INT || kind == LONG) && operand2.isDefaultValue())
{
throw new TextSourceException(package.getResourceString("error.int-div-by-zero")) { source = source, position = before };
}
switch(kind)
{
case REAL:
result = factory.createReal(operand1.asReal() / operand2.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(operand1.asDouble() / operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() / operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() / operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() / operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() / operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() / operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() / operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() / operand2.asFloat8());
break label1;
case INT:
result = factory.createIntegral(operand1.asInt() / operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() / operand2.asLong());
break label1;
}
break label0;
case O_SCAL_DIVU:
if((kind == INT || kind == LONG) && operand2.isDefaultValue())
{
throw new TextSourceException(package.getResourceString("error.int-div-by-zero")) { source = source, position = before };
}
switch(kind)
{
case REAL:
result = factory.createReal(operand1.asReal() // operand2.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(operand1.asDouble() // operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() // operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() // operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() // operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() // operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() // operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() // operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() // operand2.asFloat8());
break label1;
case INT:
result = factory.createIntegral(operand1.asInt() // operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() // operand2.asLong());
break label1;
}
break label0;
case O_SCAL_REM:
if((kind == INT || kind == LONG) && operand2.isDefaultValue())
{
throw new TextSourceException(package.getResourceString("error.int-div-by-zero")) { source = source, position = before };
}
switch(kind)
{
case REAL:
result = factory.createReal(operand1.asReal() % operand2.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(operand1.asDouble() % operand2.asDouble());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() % operand2.asFloat());
break label1;
case INT:
result = factory.createIntegral(operand1.asInt() % operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() % operand2.asLong());
break label1;
}
break label0;
case O_SCAL_REMU:
if((kind == INT || kind == LONG) && operand2.isDefaultValue())
{
throw new TextSourceException(package.getResourceString("error.int-div-by-zero")) { source = source, position = before };
}
switch(kind)
{
case REAL:
result = factory.createReal(operand1.asReal() %% operand2.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(operand1.asDouble() %% operand2.asDouble());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() %% operand2.asFloat());
break label1;
case INT:
result = factory.createIntegral(operand1.asInt() %% operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() %% operand2.asLong());
break label1;
}
break label0;
case O_VECT_MUL:
switch(kind)
{
case DOUBLE:
result = factory.createDouble(operand1.asDouble() **** operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() **** operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() **** operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() **** operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() **** operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() **** operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() **** operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() **** operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() **** operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() **** operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() **** operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() **** operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() **** operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() **** operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() **** operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() **** operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() **** operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() **** operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() **** operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() **** operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() **** operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() **** operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() **** operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() **** operand2.asLong8());
break label1;
}
break label0;
case O_VECT_DIV:
if(kind >= BYTE && kind <= LONG8)
{
kind = DOUBLE | kind & 3;
}
switch(kind)
{
case DOUBLE:
result = factory.createDouble(operand1.asDouble() //// operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() //// operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() //// operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() //// operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() //// operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() //// operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() //// operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() //// operand2.asFloat8());
break label1;
}
break label0;
case O_VECT_HMUL:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() |**| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |**| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |**| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |**| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |**| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |**| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |**| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |**| operand2.asShort8());
break label1;
}
break label0;
case O_VECT_HMULU:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() #**# operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() #**# operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() #**# operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() #**# operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() #**# operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() #**# operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() #**# operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() #**# operand2.asShort8());
break label1;
}
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
Type resultType;
switch(operation)
{
case O_SCAL_MUL:
if(kind >= REAL && kind <= FLOAT8 || kind >= INT && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
case O_SCAL_DIV:
case O_SCAL_DIVU:
if(kind >= REAL && kind <= FLOAT8 || kind == INT || kind == LONG)
{
resultType = commonType;
break;
}
break label0;
case O_SCAL_REM:
case O_SCAL_REMU:
if(kind == REAL || kind == DOUBLE || kind == FLOAT || kind == INT || kind == LONG)
{
resultType = commonType;
break;
}
break label0;
case O_VECT_MUL:
if(kind >= DOUBLE && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
case O_VECT_DIV:
if(kind >= BYTE && kind <= LONG8)
{
commonType = getPrimitiveType(kind = DOUBLE | kind & 3);
}
if(kind >= DOUBLE && kind <= FLOAT8)
{
resultType = commonType;
break;
}
break label0;
case O_VECT_HMUL:
case O_VECT_HMULU:
if(kind >= BYTE && kind <= SHORT8)
{
resultType = commonType;
break;
}
break label0;
}
child1 = cast(child1, commonType);
child2 = cast(child2, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, operation, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation += R_DELTA, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(
(operation = source.getLexemeKind(position)) == O_SCAL_MUL || operation == O_SCAL_DIV || operation == O_SCAL_DIVU || operation == O_SCAL_REM || operation == O_SCAL_REMU ||
operation == O_VECT_MUL || operation == O_VECT_DIV || operation == O_VECT_HMUL || operation == O_VECT_HMULU
);
}
return position;
}
private int parseAdditive(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
int operation = source.getLexemeKind(position = parseMultiplicative(parent, source, position, isStaticOnly));
if(
operation == O_SCAL_ADD || operation == O_SCAL_SUB || operation == O_VECT_SADD || operation == O_VECT_SADDU ||
operation == O_VECT_ADD || operation == O_VECT_SUB || operation == O_VECT_SSUB || operation == O_VECT_SSUBU
)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
position = parseMultiplicative(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
ClassType typeString = fldTypeString;
label1:
{
if(argument1Type instanceof ClassType)
{
if(operation == O_SCAL_ADD && argument1Type == typeString && child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
if(argument2Type == typeString)
{
String operand1 = (String) ((Constant) child1.operand1).asObject();
String operand2 = (String) ((Constant) child2.operand1).asObject();
if(operand1 != null && operand2 != null)
{
child1.setData(child1.position, typeString, LOAD_CONST, factory.createString(operand1 + operand2));
code.removeNode(child2);
continue;
}
}
else if(argument2Type == getPrimitiveType(CHAR))
{
String operand1 = (String) ((Constant) child1.operand1).asObject();
if(operand1 != null)
{
char operand2 = ((Constant) child2.operand1).asChar();
child1.setData(child1.position, typeString, LOAD_CONST, factory.createString(operand1 + operand2));
code.removeNode(child2);
continue;
}
}
}
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
if(!(argument1Type instanceof PrimitiveType)) break label0;
Type commonType = operation >= O_VECT_OPERATOR ? argument1Type.getVectorCommonType(argument2Type) : argument1Type.getScalarCommonType(argument2Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
label1: switch(operation)
{
case O_SCAL_ADD:
switch(kind)
{
case REAL:
result = factory.createReal(operand1.asReal() + operand2.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(operand1.asDouble() + operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() + operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() + operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() + operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() + operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() + operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() + operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() + operand2.asFloat8());
break label1;
case INT:
result = factory.createIntegral(operand1.asInt() + operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() + operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() + operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() + operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() + operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() + operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() + operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() + operand2.asLong8());
break label1;
}
break label0;
case O_SCAL_SUB:
switch(kind)
{
case REAL:
result = factory.createReal(operand1.asReal() - operand2.asReal());
break label1;
case DOUBLE:
result = factory.createDouble(operand1.asDouble() - operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() - operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() - operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() - operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() - operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() - operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() - operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() - operand2.asFloat8());
break label1;
case INT:
result = factory.createIntegral(operand1.asInt() - operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() - operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() - operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() - operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() - operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() - operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() - operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() - operand2.asLong8());
break label1;
}
break label0;
case O_VECT_ADD:
switch(kind)
{
case DOUBLE:
result = factory.createDouble(operand1.asDouble() ++++ operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() ++++ operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() ++++ operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() ++++ operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() ++++ operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() ++++ operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() ++++ operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() ++++ operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() ++++ operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() ++++ operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() ++++ operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() ++++ operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() ++++ operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() ++++ operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() ++++ operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() ++++ operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() ++++ operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() ++++ operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() ++++ operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() ++++ operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() ++++ operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() ++++ operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() ++++ operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() ++++ operand2.asLong8());
break label1;
}
break label0;
case O_VECT_SUB:
switch(kind)
{
case DOUBLE:
result = factory.createDouble(operand1.asDouble() ---- operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createDouble2(operand1.asDouble2() ---- operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createDouble4(operand1.asDouble4() ---- operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createDouble8(operand1.asDouble8() ---- operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createFloat(operand1.asFloat() ---- operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createFloat2(operand1.asFloat2() ---- operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createFloat4(operand1.asFloat4() ---- operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createFloat8(operand1.asFloat8() ---- operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() ---- operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() ---- operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() ---- operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() ---- operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() ---- operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() ---- operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() ---- operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() ---- operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() ---- operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() ---- operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() ---- operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() ---- operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() ---- operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() ---- operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() ---- operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() ---- operand2.asLong8());
break label1;
}
break label0;
case O_VECT_SADD:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() |++| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |++| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |++| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |++| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |++| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |++| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |++| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |++| operand2.asShort8());
break label1;
}
break label0;
case O_VECT_SADDU:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() #++# operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() #++# operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() #++# operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() #++# operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() #++# operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() #++# operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() #++# operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() #++# operand2.asShort8());
break label1;
}
break label0;
case O_VECT_SSUB:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() |--| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |--| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |--| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |--| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |--| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |--| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |--| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |--| operand2.asShort8());
break label1;
}
break label0;
case O_VECT_SSUBU:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() #--# operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() #--# operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() #--# operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() #--# operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() #--# operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() #--# operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() #--# operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() #--# operand2.asShort8());
break label1;
}
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
Type resultType;
switch(operation)
{
case O_SCAL_ADD:
case O_SCAL_SUB:
if(kind >= REAL && kind <= FLOAT8 || kind >= INT && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
case O_VECT_ADD:
case O_VECT_SUB:
if(kind >= DOUBLE && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
case O_VECT_SADD:
case O_VECT_SADDU:
case O_VECT_SSUB:
case O_VECT_SSUBU:
if(kind >= BYTE && kind <= SHORT8)
{
resultType = commonType;
break;
}
break label0;
}
child1 = cast(child1, commonType);
child2 = cast(child2, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, operation, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(operation == O_SCAL_ADD && argument1Type == getPrimitiveType(CHAR) && argument2Type == typeString && child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
String operand2 = (String) ((Constant) child2.operand1).asObject();
if(operand2 != null)
{
char operand1 = ((Constant) child1.operand1).asChar();
child1.setData(child1.position, typeString, LOAD_CONST, factory.createString((new StringBuilder() + operand1 + operand2).toString()));
code.removeNode(child2);
continue;
}
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation += R_DELTA, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(
(operation = source.getLexemeKind(position)) == O_SCAL_ADD || operation == O_SCAL_SUB || operation == O_VECT_SADD || operation == O_VECT_SADDU ||
operation == O_VECT_ADD || operation == O_VECT_SUB || operation == O_VECT_SSUB || operation == O_VECT_SSUBU
);
}
return position;
}
private int parseShift(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
int operation = source.getLexemeKind(position = parseAdditive(parent, source, position, isStaticOnly));
if(
operation == O_SCAL_SHR || operation == O_SCAL_SHRU || operation == O_SCAL_SHL ||
operation == O_VECT_SHR || operation == O_VECT_SHRU || operation == O_VECT_SHL
)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
position = parseAdditive(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
label1:
{
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
if(!(argument1Type instanceof PrimitiveType) || !argument2Type.isInt()) break label0;
Type commonType = operation >= O_VECT_OPERATOR ? argument1Type : argument1Type.getScalarCommonType(argument1Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
label1: switch(operation)
{
case O_SCAL_SHR:
switch(kind)
{
case INT:
result = factory.createIntegral(operand1.asInt() >> operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() >> operand2.asInt());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() >> operand2.asInt());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() >> operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() >> operand2.asInt());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() >> operand2.asInt());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() >> operand2.asInt());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() >> operand2.asInt());
break label1;
}
break label0;
case O_SCAL_SHRU:
switch(kind)
{
case INT:
result = factory.createIntegral(operand1.asInt() >>> operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() >>> operand2.asInt());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() >>> operand2.asInt());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() >>> operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() >>> operand2.asInt());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() >>> operand2.asInt());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() >>> operand2.asInt());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() >>> operand2.asInt());
break label1;
}
break label0;
case O_SCAL_SHL:
switch(kind)
{
case INT:
result = factory.createIntegral(operand1.asInt() << operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() << operand2.asInt());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() << operand2.asInt());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() << operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() << operand2.asInt());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() << operand2.asInt());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() << operand2.asInt());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() << operand2.asInt());
break label1;
}
break label0;
case O_VECT_SHR:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() >>>> operand2.asInt());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() >>>> operand2.asInt());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() >>>> operand2.asInt());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() >>>> operand2.asInt());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() >>>> operand2.asInt());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() >>>> operand2.asInt());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() >>>> operand2.asInt());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() >>>> operand2.asInt());
break label1;
case INT:
result = factory.createInt(operand1.asInt() >>>> operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() >>>> operand2.asInt());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() >>>> operand2.asInt());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() >>>> operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() >>>> operand2.asInt());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() >>>> operand2.asInt());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() >>>> operand2.asInt());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() >>>> operand2.asInt());
break label1;
}
break label0;
case O_VECT_SHRU:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() >>>>> operand2.asInt());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() >>>>> operand2.asInt());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() >>>>> operand2.asInt());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() >>>>> operand2.asInt());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() >>>>> operand2.asInt());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() >>>>> operand2.asInt());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() >>>>> operand2.asInt());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() >>>>> operand2.asInt());
break label1;
case INT:
result = factory.createInt(operand1.asInt() >>>>> operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() >>>>> operand2.asInt());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() >>>>> operand2.asInt());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() >>>>> operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() >>>>> operand2.asInt());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() >>>>> operand2.asInt());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() >>>>> operand2.asInt());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() >>>>> operand2.asInt());
break label1;
}
break label0;
case O_VECT_SHL:
switch(kind)
{
case BYTE:
result = factory.createByte(operand1.asByte() <<<< operand2.asInt());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() <<<< operand2.asInt());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() <<<< operand2.asInt());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() <<<< operand2.asInt());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() <<<< operand2.asInt());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() <<<< operand2.asInt());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() <<<< operand2.asInt());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() <<<< operand2.asInt());
break label1;
case INT:
result = factory.createInt(operand1.asInt() <<<< operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() <<<< operand2.asInt());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() <<<< operand2.asInt());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() <<<< operand2.asInt());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() <<<< operand2.asInt());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() <<<< operand2.asInt());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() <<<< operand2.asInt());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() <<<< operand2.asInt());
break label1;
}
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
Type resultType;
switch(operation)
{
case O_SCAL_SHR:
case O_SCAL_SHRU:
case O_SCAL_SHL:
if(kind >= INT && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
case O_VECT_SHR:
case O_VECT_SHRU:
case O_VECT_SHL:
if(kind >= BYTE && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
}
child1 = cast(child1, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, operation, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation += R_DELTA, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(
(operation = source.getLexemeKind(position)) == O_SCAL_SHR || operation == O_SCAL_SHRU || operation == O_SCAL_SHL ||
operation == O_VECT_SHR || operation == O_VECT_SHRU || operation == O_VECT_SHL
);
}
return position;
}
private int parseRelational(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
int operation = source.getLexemeKind(position = parseShift(parent, source, position, isStaticOnly));
if(
operation == O_SCAL_GT || operation == O_SCAL_GE || operation == O_SCAL_LT || operation == O_SCAL_LE ||
operation == O_VECT_GT || operation == O_VECT_GE || operation == O_VECT_LT || operation == O_VECT_LE ||
operation == INSTANCEOF
)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
if(operation == INSTANCEOF)
{
Type argument1Type = child1.type;
if(!(argument1Type instanceof ClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.1"), new Object[] { source.getLexemeString(before), argument1Type }
)) { source = source, position = before };
}
ImmediateBuilderItemHolder checkTypeHolder = getItemHolder();
position = parseTypeName(source, position + 1, enclosing, checkTypeHolder);
Type checkType = checkTypeHolder.resultType;
if(!(checkType instanceof ClassType))
{
throw new TextSourceException(package.getResourceString("expected.name.class-type")) { source = source, position = before + 1 };
}
if(!argument1Type.isCompatibleWith(checkType))
{
throw new TextSourceException(String.format(
package.getResourceString("incompatible-types"), new Object[] { argument1Type, checkType }
)) { source = source, position = before };
}
checkType.makeCompilable();
Node result = code.createAndAppendNode(parent).setData(before, fldTypeBoolean, INSTANCEOF, checkType);
code.moveNode(child1, child1 = result, 0);
continue;
}
position = parseShift(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
label1:
{
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
if(!(argument1Type instanceof PrimitiveType)) break label0;
Type commonType = operation >= O_VECT_OPERATOR ? argument1Type.getVectorCommonType(argument2Type) : argument1Type.getScalarCommonType(argument2Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
label1: switch(operation)
{
case O_SCAL_GT:
switch(kind)
{
case REAL:
result = operand1.asReal() > operand2.asReal() ? fldTrue : fldFalse;
break label1;
case DOUBLE:
result = operand1.asDouble() > operand2.asDouble() ? fldTrue : fldFalse;
break label1;
case FLOAT:
result = operand1.asFloat() > operand2.asFloat() ? fldTrue : fldFalse;
break label1;
case INT:
result = operand1.asInt() > operand2.asInt() ? fldTrue : fldFalse;
break label1;
case LONG:
result = operand1.asLong() > operand2.asLong() ? fldTrue : fldFalse;
break label1;
}
break label0;
case O_SCAL_GE:
switch(kind)
{
case REAL:
result = operand1.asReal() >= operand2.asReal() ? fldTrue : fldFalse;
break label1;
case DOUBLE:
result = operand1.asDouble() >= operand2.asDouble() ? fldTrue : fldFalse;
break label1;
case FLOAT:
result = operand1.asFloat() >= operand2.asFloat() ? fldTrue : fldFalse;
break label1;
case INT:
result = operand1.asInt() >= operand2.asInt() ? fldTrue : fldFalse;
break label1;
case LONG:
result = operand1.asLong() >= operand2.asLong() ? fldTrue : fldFalse;
break label1;
}
break label0;
case O_SCAL_LT:
switch(kind)
{
case REAL:
result = operand1.asReal() < operand2.asReal() ? fldTrue : fldFalse;
break label1;
case DOUBLE:
result = operand1.asDouble() < operand2.asDouble() ? fldTrue : fldFalse;
break label1;
case FLOAT:
result = operand1.asFloat() < operand2.asFloat() ? fldTrue : fldFalse;
break label1;
case INT:
result = operand1.asInt() < operand2.asInt() ? fldTrue : fldFalse;
break label1;
case LONG:
result = operand1.asLong() < operand2.asLong() ? fldTrue : fldFalse;
break label1;
}
break label0;
case O_SCAL_LE:
switch(kind)
{
case REAL:
result = operand1.asReal() <= operand2.asReal() ? fldTrue : fldFalse;
break label1;
case DOUBLE:
result = operand1.asDouble() <= operand2.asDouble() ? fldTrue : fldFalse;
break label1;
case FLOAT:
result = operand1.asFloat() <= operand2.asFloat() ? fldTrue : fldFalse;
break label1;
case INT:
result = operand1.asInt() <= operand2.asInt() ? fldTrue : fldFalse;
break label1;
case LONG:
result = operand1.asLong() <= operand2.asLong() ? fldTrue : fldFalse;
break label1;
}
break label0;
case O_VECT_GT:
switch(kind)
{
case DOUBLE:
result = factory.createLong(operand1.asDouble() |>>| operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createLong2(operand1.asDouble2() |>>| operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createLong4(operand1.asDouble4() |>>| operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createLong8(operand1.asDouble8() |>>| operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createInt(operand1.asFloat() |>>| operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createInt2(operand1.asFloat2() |>>| operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createInt4(operand1.asFloat4() |>>| operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createInt8(operand1.asFloat8() |>>| operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() |>>| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |>>| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |>>| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |>>| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |>>| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |>>| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |>>| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |>>| operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() |>>| operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() |>>| operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() |>>| operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() |>>| operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() |>>| operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() |>>| operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() |>>| operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() |>>| operand2.asLong8());
break label1;
}
break label0;
case O_VECT_GE:
switch(kind)
{
case DOUBLE:
result = factory.createLong(operand1.asDouble() |>=| operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createLong2(operand1.asDouble2() |>=| operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createLong4(operand1.asDouble4() |>=| operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createLong8(operand1.asDouble8() |>=| operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createInt(operand1.asFloat() |>=| operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createInt2(operand1.asFloat2() |>=| operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createInt4(operand1.asFloat4() |>=| operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createInt8(operand1.asFloat8() |>=| operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() |>=| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |>=| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |>=| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |>=| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |>=| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |>=| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |>=| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |>=| operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() |>=| operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() |>=| operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() |>=| operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() |>=| operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() |>=| operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() |>=| operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() |>=| operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() |>=| operand2.asLong8());
break label1;
}
break label0;
case O_VECT_LT:
switch(kind)
{
case DOUBLE:
result = factory.createLong(operand1.asDouble() |<<| operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createLong2(operand1.asDouble2() |<<| operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createLong4(operand1.asDouble4() |<<| operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createLong8(operand1.asDouble8() |<<| operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createInt(operand1.asFloat() |<<| operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createInt2(operand1.asFloat2() |<<| operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createInt4(operand1.asFloat4() |<<| operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createInt8(operand1.asFloat8() |<<| operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() |<<| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |<<| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |<<| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |<<| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |<<| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |<<| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |<<| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |<<| operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() |<<| operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() |<<| operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() |<<| operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() |<<| operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() |<<| operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() |<<| operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() |<<| operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() |<<| operand2.asLong8());
break label1;
}
break label0;
case O_VECT_LE:
switch(kind)
{
case DOUBLE:
result = factory.createLong(operand1.asDouble() |<=| operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createLong2(operand1.asDouble2() |<=| operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createLong4(operand1.asDouble4() |<=| operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createLong8(operand1.asDouble8() |<=| operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createInt(operand1.asFloat() |<=| operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createInt2(operand1.asFloat2() |<=| operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createInt4(operand1.asFloat4() |<=| operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createInt8(operand1.asFloat8() |<=| operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() |<=| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |<=| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |<=| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |<=| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |<=| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |<=| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |<=| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |<=| operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() |<=| operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() |<=| operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() |<=| operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() |<=| operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() |<=| operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() |<=| operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() |<=| operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() |<=| operand2.asLong8());
break label1;
}
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
Type resultType;
switch(operation)
{
case O_SCAL_GT:
case O_SCAL_GE:
case O_SCAL_LT:
case O_SCAL_LE:
if(kind == REAL || kind == DOUBLE || kind == FLOAT || kind == INT || kind == LONG)
{
resultType = fldTypeBoolean;
break;
}
break label0;
case O_VECT_GT:
case O_VECT_GE:
case O_VECT_LT:
case O_VECT_LE:
if(kind >= DOUBLE && kind <= DOUBLE8)
{
resultType = getPrimitiveType(kind + (LONG - DOUBLE));
break;
}
if(kind >= FLOAT && kind <= FLOAT8)
{
resultType = getPrimitiveType(kind + (INT - FLOAT));
break;
}
if(kind >= BYTE && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
}
child1 = cast(child1, commonType);
child2 = cast(child2, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, operation, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation += R_DELTA, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(
(operation = source.getLexemeKind(position)) == O_SCAL_GT || operation == O_SCAL_GE || operation == O_SCAL_LT || operation == O_SCAL_LE ||
operation == O_VECT_GT || operation == O_VECT_GE || operation == O_VECT_LT || operation == O_VECT_LE ||
operation == INSTANCEOF
);
}
return position;
}
private int parseEquality(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
int operation = source.getLexemeKind(position = parseRelational(parent, source, position, isStaticOnly));
if(operation == O_SCAL_EQ || operation == O_SCAL_NE || operation == O_VECT_EQ || operation == O_VECT_NE)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
position = parseRelational(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
if((operation == O_SCAL_EQ || operation == O_SCAL_NE) && argument1Type instanceof ReferenceType)
{
if(!argument1Type.isCompatibleWith(argument2Type))
{
throw new TextSourceException(String.format(
package.getResourceString("incompatible-types"), new Object[] { argument1Type, argument2Type }
)) { source = source, position = before };
}
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Object operand1 = ((Constant) child1.operand1).asObject();
Object operand2 = ((Constant) child2.operand1).asObject();
child1.setData(child1.position, fldTypeBoolean, LOAD_CONST, (operation == O_SCAL_EQ ? operand1 == operand2 : operand1 != operand2) ? fldTrue : fldFalse);
code.removeNode(child2);
continue;
}
Node result = code.createAndAppendNode(parent).setData(before, fldTypeBoolean, operation + (REF_EQ - O_SCAL_EQ));
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
label1:
{
if(operation == O_VECT_EQ || operation == O_VECT_NE)
{
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
}
if(!(argument1Type instanceof PrimitiveType)) break label0;
Type commonType = operation >= O_VECT_OPERATOR ? argument1Type.getVectorCommonType(argument2Type) : argument1Type.getScalarCommonType(argument2Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
label1: switch(operation)
{
case O_SCAL_EQ:
switch(kind)
{
case BOOLEAN:
result = operand1.asBoolean() == operand2.asBoolean() ? fldTrue : fldFalse;
break label1;
case REAL:
result = operand1.asReal() == operand2.asReal() ? fldTrue : fldFalse;
break label1;
case DOUBLE:
result = operand1.asDouble() == operand2.asDouble() ? fldTrue : fldFalse;
break label1;
case DOUBLE2:
result = operand1.asDouble2() == operand2.asDouble2() ? fldTrue : fldFalse;
break label1;
case DOUBLE4:
result = operand1.asDouble4() == operand2.asDouble4() ? fldTrue : fldFalse;
break label1;
case DOUBLE8:
result = operand1.asDouble8() == operand2.asDouble8() ? fldTrue : fldFalse;
break label1;
case FLOAT:
result = operand1.asFloat() == operand2.asFloat() ? fldTrue : fldFalse;
break label1;
case FLOAT2:
result = operand1.asFloat2() == operand2.asFloat2() ? fldTrue : fldFalse;
break label1;
case FLOAT4:
result = operand1.asFloat4() == operand2.asFloat4() ? fldTrue : fldFalse;
break label1;
case FLOAT8:
result = operand1.asFloat8() == operand2.asFloat8() ? fldTrue : fldFalse;
break label1;
case INT:
result = operand1.asInt() == operand2.asInt() ? fldTrue : fldFalse;
break label1;
case INT2:
result = operand1.asInt2() == operand2.asInt2() ? fldTrue : fldFalse;
break label1;
case INT4:
result = operand1.asInt4() == operand2.asInt4() ? fldTrue : fldFalse;
break label1;
case INT8:
result = operand1.asInt8() == operand2.asInt8() ? fldTrue : fldFalse;
break label1;
case LONG:
result = operand1.asLong() == operand2.asLong() ? fldTrue : fldFalse;
break label1;
case LONG2:
result = operand1.asLong2() == operand2.asLong2() ? fldTrue : fldFalse;
break label1;
case LONG4:
result = operand1.asLong4() == operand2.asLong4() ? fldTrue : fldFalse;
break label1;
case LONG8:
result = operand1.asLong8() == operand2.asLong8() ? fldTrue : fldFalse;
break label1;
}
break label0;
case O_SCAL_NE:
switch(kind)
{
case BOOLEAN:
result = operand1.asBoolean() != operand2.asBoolean() ? fldTrue : fldFalse;
break label1;
case REAL:
result = operand1.asReal() != operand2.asReal() ? fldTrue : fldFalse;
break label1;
case DOUBLE:
result = operand1.asDouble() != operand2.asDouble() ? fldTrue : fldFalse;
break label1;
case DOUBLE2:
result = operand1.asDouble2() != operand2.asDouble2() ? fldTrue : fldFalse;
break label1;
case DOUBLE4:
result = operand1.asDouble4() != operand2.asDouble4() ? fldTrue : fldFalse;
break label1;
case DOUBLE8:
result = operand1.asDouble8() != operand2.asDouble8() ? fldTrue : fldFalse;
break label1;
case FLOAT:
result = operand1.asFloat() != operand2.asFloat() ? fldTrue : fldFalse;
break label1;
case FLOAT2:
result = operand1.asFloat2() != operand2.asFloat2() ? fldTrue : fldFalse;
break label1;
case FLOAT4:
result = operand1.asFloat4() != operand2.asFloat4() ? fldTrue : fldFalse;
break label1;
case FLOAT8:
result = operand1.asFloat8() != operand2.asFloat8() ? fldTrue : fldFalse;
break label1;
case INT:
result = operand1.asInt() != operand2.asInt() ? fldTrue : fldFalse;
break label1;
case INT2:
result = operand1.asInt2() != operand2.asInt2() ? fldTrue : fldFalse;
break label1;
case INT4:
result = operand1.asInt4() != operand2.asInt4() ? fldTrue : fldFalse;
break label1;
case INT8:
result = operand1.asInt8() != operand2.asInt8() ? fldTrue : fldFalse;
break label1;
case LONG:
result = operand1.asLong() != operand2.asLong() ? fldTrue : fldFalse;
break label1;
case LONG2:
result = operand1.asLong2() != operand2.asLong2() ? fldTrue : fldFalse;
break label1;
case LONG4:
result = operand1.asLong4() != operand2.asLong4() ? fldTrue : fldFalse;
break label1;
case LONG8:
result = operand1.asLong8() != operand2.asLong8() ? fldTrue : fldFalse;
break label1;
}
break label0;
case O_VECT_EQ:
switch(kind)
{
case DOUBLE:
result = factory.createLong(operand1.asDouble() |==| operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createLong2(operand1.asDouble2() |==| operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createLong4(operand1.asDouble4() |==| operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createLong8(operand1.asDouble8() |==| operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createInt(operand1.asFloat() |==| operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createInt2(operand1.asFloat2() |==| operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createInt4(operand1.asFloat4() |==| operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createInt8(operand1.asFloat8() |==| operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() |==| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |==| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |==| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |==| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |==| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |==| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |==| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |==| operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() |==| operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() |==| operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() |==| operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() |==| operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() |==| operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() |==| operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() |==| operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() |==| operand2.asLong8());
break label1;
}
break label0;
case O_VECT_NE:
switch(kind)
{
case DOUBLE:
result = factory.createLong(operand1.asDouble() |!=| operand2.asDouble());
break label1;
case DOUBLE2:
result = factory.createLong2(operand1.asDouble2() |!=| operand2.asDouble2());
break label1;
case DOUBLE4:
result = factory.createLong4(operand1.asDouble4() |!=| operand2.asDouble4());
break label1;
case DOUBLE8:
result = factory.createLong8(operand1.asDouble8() |!=| operand2.asDouble8());
break label1;
case FLOAT:
result = factory.createInt(operand1.asFloat() |!=| operand2.asFloat());
break label1;
case FLOAT2:
result = factory.createInt2(operand1.asFloat2() |!=| operand2.asFloat2());
break label1;
case FLOAT4:
result = factory.createInt4(operand1.asFloat4() |!=| operand2.asFloat4());
break label1;
case FLOAT8:
result = factory.createInt8(operand1.asFloat8() |!=| operand2.asFloat8());
break label1;
case BYTE:
result = factory.createByte(operand1.asByte() |!=| operand2.asByte());
break label1;
case BYTE2:
result = factory.createByte2(operand1.asByte2() |!=| operand2.asByte2());
break label1;
case BYTE4:
result = factory.createByte4(operand1.asByte4() |!=| operand2.asByte4());
break label1;
case BYTE8:
result = factory.createByte8(operand1.asByte8() |!=| operand2.asByte8());
break label1;
case SHORT:
result = factory.createShort(operand1.asShort() |!=| operand2.asShort());
break label1;
case SHORT2:
result = factory.createShort2(operand1.asShort2() |!=| operand2.asShort2());
break label1;
case SHORT4:
result = factory.createShort4(operand1.asShort4() |!=| operand2.asShort4());
break label1;
case SHORT8:
result = factory.createShort8(operand1.asShort8() |!=| operand2.asShort8());
break label1;
case INT:
result = factory.createInt(operand1.asInt() |!=| operand2.asInt());
break label1;
case INT2:
result = factory.createInt2(operand1.asInt2() |!=| operand2.asInt2());
break label1;
case INT4:
result = factory.createInt4(operand1.asInt4() |!=| operand2.asInt4());
break label1;
case INT8:
result = factory.createInt8(operand1.asInt8() |!=| operand2.asInt8());
break label1;
case LONG:
result = factory.createLong(operand1.asLong() |!=| operand2.asLong());
break label1;
case LONG2:
result = factory.createLong2(operand1.asLong2() |!=| operand2.asLong2());
break label1;
case LONG4:
result = factory.createLong4(operand1.asLong4() |!=| operand2.asLong4());
break label1;
case LONG8:
result = factory.createLong8(operand1.asLong8() |!=| operand2.asLong8());
break label1;
}
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
Type resultType;
switch(operation)
{
case O_SCAL_EQ:
case O_SCAL_NE:
if(kind == BOOLEAN || kind >= REAL && kind <= FLOAT8 || kind >= INT && kind <= LONG8)
{
resultType = fldTypeBoolean;
break;
}
break label0;
case O_VECT_EQ:
case O_VECT_NE:
if(kind >= DOUBLE && kind <= DOUBLE8)
{
resultType = getPrimitiveType(kind + (LONG - DOUBLE));
break;
}
if(kind >= FLOAT && kind <= FLOAT8)
{
resultType = getPrimitiveType(kind + (INT - FLOAT));
break;
}
if(kind >= BYTE && kind <= LONG8)
{
resultType = commonType;
break;
}
break label0;
}
child1 = cast(child1, commonType);
child2 = cast(child2, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, operation, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(operation += R_DELTA, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(operation) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(operation) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while((operation = source.getLexemeKind(position)) == O_SCAL_EQ || operation == O_SCAL_NE || operation == O_VECT_EQ || operation == O_VECT_NE);
}
return position;
}
private int parseBitAnd(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
if(source.getLexemeKind(position = parseEquality(parent, source, position, isStaticOnly)) == O_BIT_AND)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
position = parseEquality(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
label1:
{
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(O_BIT_AND, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(O_BIT_AND) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(O_BIT_AND) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
if(!(argument1Type instanceof PrimitiveType)) break label0;
Type commonType = argument1Type.getVectorCommonType(argument2Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
switch(kind)
{
case BOOLEAN:
result = operand1.asBoolean() & operand2.asBoolean() ? fldTrue : fldFalse;
break;
case BYTE:
result = factory.createByte(operand1.asByte() & operand2.asByte());
break;
case BYTE2:
result = factory.createByte2(operand1.asByte2() & operand2.asByte2());
break;
case BYTE4:
result = factory.createByte4(operand1.asByte4() & operand2.asByte4());
break;
case BYTE8:
result = factory.createByte8(operand1.asByte8() & operand2.asByte8());
break;
case SHORT:
result = factory.createShort(operand1.asShort() & operand2.asShort());
break;
case SHORT2:
result = factory.createShort2(operand1.asShort2() & operand2.asShort2());
break;
case SHORT4:
result = factory.createShort4(operand1.asShort4() & operand2.asShort4());
break;
case SHORT8:
result = factory.createShort8(operand1.asShort8() & operand2.asShort8());
break;
case INT:
result = factory.createInt(operand1.asInt() & operand2.asInt());
break;
case INT2:
result = factory.createInt2(operand1.asInt2() & operand2.asInt2());
break;
case INT4:
result = factory.createInt4(operand1.asInt4() & operand2.asInt4());
break;
case INT8:
result = factory.createInt8(operand1.asInt8() & operand2.asInt8());
break;
case LONG:
result = factory.createLong(operand1.asLong() & operand2.asLong());
break;
case LONG2:
result = factory.createLong2(operand1.asLong2() & operand2.asLong2());
break;
case LONG4:
result = factory.createLong4(operand1.asLong4() & operand2.asLong4());
break;
case LONG8:
result = factory.createLong8(operand1.asLong8() & operand2.asLong8());
break;
default:
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
if(kind == BOOLEAN || kind >= BYTE && kind <= LONG8)
{
Type resultType = commonType;
child1 = cast(child1, commonType);
child2 = cast(child2, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, O_BIT_AND, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
break label0;
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(R_BIT_AND, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(R_BIT_AND) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(R_BIT_AND) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(source.getLexemeKind(position) == O_BIT_AND);
}
return position;
}
private int parseBitXor(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
if(source.getLexemeKind(position = parseBitAnd(parent, source, position, isStaticOnly)) == O_BIT_XOR)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
position = parseBitAnd(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
label1:
{
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(O_BIT_XOR, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(O_BIT_XOR) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(O_BIT_XOR) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
if(!(argument1Type instanceof PrimitiveType)) break label0;
Type commonType = argument1Type.getVectorCommonType(argument2Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
switch(kind)
{
case BOOLEAN:
result = operand1.asBoolean() ^ operand2.asBoolean() ? fldTrue : fldFalse;
break;
case BYTE:
result = factory.createByte(operand1.asByte() ^ operand2.asByte());
break;
case BYTE2:
result = factory.createByte2(operand1.asByte2() ^ operand2.asByte2());
break;
case BYTE4:
result = factory.createByte4(operand1.asByte4() ^ operand2.asByte4());
break;
case BYTE8:
result = factory.createByte8(operand1.asByte8() ^ operand2.asByte8());
break;
case SHORT:
result = factory.createShort(operand1.asShort() ^ operand2.asShort());
break;
case SHORT2:
result = factory.createShort2(operand1.asShort2() ^ operand2.asShort2());
break;
case SHORT4:
result = factory.createShort4(operand1.asShort4() ^ operand2.asShort4());
break;
case SHORT8:
result = factory.createShort8(operand1.asShort8() ^ operand2.asShort8());
break;
case INT:
result = factory.createInt(operand1.asInt() ^ operand2.asInt());
break;
case INT2:
result = factory.createInt2(operand1.asInt2() ^ operand2.asInt2());
break;
case INT4:
result = factory.createInt4(operand1.asInt4() ^ operand2.asInt4());
break;
case INT8:
result = factory.createInt8(operand1.asInt8() ^ operand2.asInt8());
break;
case LONG:
result = factory.createLong(operand1.asLong() ^ operand2.asLong());
break;
case LONG2:
result = factory.createLong2(operand1.asLong2() ^ operand2.asLong2());
break;
case LONG4:
result = factory.createLong4(operand1.asLong4() ^ operand2.asLong4());
break;
case LONG8:
result = factory.createLong8(operand1.asLong8() ^ operand2.asLong8());
break;
default:
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
if(kind == BOOLEAN || kind >= BYTE && kind <= LONG8)
{
Type resultType = commonType;
child1 = cast(child1, commonType);
child2 = cast(child2, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, O_BIT_XOR, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
break label0;
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(R_BIT_XOR, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(R_BIT_XOR) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(R_BIT_XOR) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(source.getLexemeKind(position) == O_BIT_XOR);
}
return position;
}
private int parseBitOr(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
if(source.getLexemeKind(position = parseBitXor(parent, source, position, isStaticOnly)) == O_BIT_OR)
{
Code code = parent.parentCode;
ClassType enclosing = code.parentCallable.parentType;
ConstantFactory factory = fldConstantFactory;
Node child1 = parent[-1];
do
{
int before = position;
position = parseBitXor(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
label0:
{
label1:
{
if(argument1Type instanceof ClassType)
{
ClassType dereferenceClassType = (ClassType) argument1Type;
Type[] arguments = new Type[] { argument2Type };
Operator[] foundOperators = dereferenceClassType.findOperators(O_BIT_OR, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
if(argument2Type instanceof ClassType) break label1;
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(O_BIT_OR) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(O_BIT_OR) + foundOperator.arguments }
)) { source = source, position = before };
}
child2 = cast(child2, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
if(argument2Type instanceof ClassType) break label1;
if(!(argument1Type instanceof PrimitiveType)) break label0;
Type commonType = argument1Type.getVectorCommonType(argument2Type);
if(commonType == null) break label0;
int kind = commonType.kind;
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result;
Constant operand1 = (Constant) child1.operand1;
Constant operand2 = (Constant) child2.operand1;
switch(kind)
{
case BOOLEAN:
result = operand1.asBoolean() | operand2.asBoolean() ? fldTrue : fldFalse;
break;
case BYTE:
result = factory.createByte(operand1.asByte() | operand2.asByte());
break;
case BYTE2:
result = factory.createByte2(operand1.asByte2() | operand2.asByte2());
break;
case BYTE4:
result = factory.createByte4(operand1.asByte4() | operand2.asByte4());
break;
case BYTE8:
result = factory.createByte8(operand1.asByte8() | operand2.asByte8());
break;
case SHORT:
result = factory.createShort(operand1.asShort() | operand2.asShort());
break;
case SHORT2:
result = factory.createShort2(operand1.asShort2() | operand2.asShort2());
break;
case SHORT4:
result = factory.createShort4(operand1.asShort4() | operand2.asShort4());
break;
case SHORT8:
result = factory.createShort8(operand1.asShort8() | operand2.asShort8());
break;
case INT:
result = factory.createInt(operand1.asInt() | operand2.asInt());
break;
case INT2:
result = factory.createInt2(operand1.asInt2() | operand2.asInt2());
break;
case INT4:
result = factory.createInt4(operand1.asInt4() | operand2.asInt4());
break;
case INT8:
result = factory.createInt8(operand1.asInt8() | operand2.asInt8());
break;
case LONG:
result = factory.createLong(operand1.asLong() | operand2.asLong());
break;
case LONG2:
result = factory.createLong2(operand1.asLong2() | operand2.asLong2());
break;
case LONG4:
result = factory.createLong4(operand1.asLong4() | operand2.asLong4());
break;
case LONG8:
result = factory.createLong8(operand1.asLong8() | operand2.asLong8());
break;
default:
break label0;
}
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
if(kind == BOOLEAN || kind >= BYTE && kind <= LONG8)
{
Type resultType = commonType;
child1 = cast(child1, commonType);
child2 = cast(child2, commonType);
Node result = code.createAndAppendNode(parent).setData(before, resultType, O_BIT_OR, commonType);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
break label0;
}
ClassType dereferenceClassType = (ClassType) argument2Type;
Type[] arguments = new Type[] { argument1Type };
Operator[] foundOperators = dereferenceClassType.findOperators(R_BIT_OR, arguments, enclosing);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(R_BIT_OR) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
if(!foundOperator.isVisibleFrom(enclosing, dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosing.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(R_BIT_OR) + foundOperator.arguments }
)) { source = source, position = before };
}
child1 = cast(child1, foundOperator.arguments[0].type);
Node result = code.createAndAppendNode(parent).setData(before, foundOperator.type, invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
code.createAndAppendNode(result).setData(before, null, SWAP, argument1Type);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(source.getLexemeKind(position) == O_BIT_OR);
}
return position;
}
private int parseBoolAnd(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
if(source.getLexemeKind(position = parseBitOr(parent, source, position, isStaticOnly)) == BOOL_AND)
{
Code code = parent.parentCode;
Node child1 = parent[-1];
do
{
int before = position;
position = parseBitOr(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
if(argument1Type.isBoolean() && argument2Type.isBoolean())
{
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result = ((Constant) child1.operand1).asBoolean() & ((Constant) child2.operand1).asBoolean() ? fldTrue : fldFalse;
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
Node result = code.createAndAppendNode(parent).setData(before, argument1Type, BOOL_AND);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(source.getLexemeKind(position) == BOOL_AND);
}
return position;
}
private int parseBoolOr(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
if(source.getLexemeKind(position = parseBoolAnd(parent, source, position, isStaticOnly)) == BOOL_OR)
{
Code code = parent.parentCode;
Node child1 = parent[-1];
do
{
int before = position;
position = parseBoolAnd(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-1];
Type argument1Type = child1.type;
Type argument2Type = child2.type;
if(argument1Type.isBoolean() && argument2Type.isBoolean())
{
if(child1.instruction == LOAD_CONST && child2.instruction == LOAD_CONST)
{
Constant result = ((Constant) child1.operand1).asBoolean() | ((Constant) child2.operand1).asBoolean() ? fldTrue : fldFalse;
child1.setData(child1.position, result.type, LOAD_CONST, result);
code.removeNode(child2);
continue;
}
Node result = code.createAndAppendNode(parent).setData(before, argument1Type, BOOL_OR);
code.moveNode(child1, child1 = result, 0);
code.moveNode(child2, result, 1);
continue;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), argument1Type, argument2Type }
)) { source = source, position = before };
} while(source.getLexemeKind(position) == BOOL_OR);
}
return position;
}
private int parseConditional(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
if(source.getLexemeKind(position = parseBoolOr(parent, source, position, isStaticOnly)) == QUESTION)
{
int question = position;
Node child1 = parent[-1];
Type argument1Type = child1.type;
if(!argument1Type.isBoolean())
{
throw new TextSourceException(String.format(
package.getResourceString("expected.expression.type"), new Object[] { fldTypeBoolean, argument1Type }
)) { source = source, position = question };
}
if(child1.instruction == LOAD_CONST)
{
throw new TextSourceException(package.getResourceString("can-not-be.const-expression-before-question")) { source = source, position = question };
}
int colon = position = parseExpression(parent, source, position + 1, isStaticOnly);
if(source.getLexemeKind(position) != COLON)
{
throw new TextSourceException(package.getResourceString("expected.colon")) { source = source, position = position };
}
position = parseExpression(parent, source, position + 1, isStaticOnly);
Node child2 = parent[-2];
Node child3 = parent[-1];
requiresValue(child2);
requiresValue(child3);
Type argument2Type = child2.type;
Type argument3Type = child3.type;
Type commonType = argument2Type.getVectorCommonType(argument3Type);
if(commonType == null)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-define.common-type"), new Object[] { argument2Type, argument3Type }
)) { source = source, position = colon };
}
child2 = cast(child2, commonType);
child3 = cast(child3, commonType);
Code code = parent.parentCode;
Node result = code.createAndAppendNode(parent).setData(question, commonType, BOOL_COND);
code.moveNode(child1, result, 0);
code.moveNode(child2, result, 1);
code.moveNode(child3, result, 2);
}
return position;
}
private int parseExpression(Node parent, TextSource source, int position, boolean isStaticOnly) throws TextSourceException {
int operation = source.getLexemeKind(position = parseConditional(parent, source, position, isStaticOnly));
label0: switch(operation)
{
case EQUALS:
Node left = parent[-1];
int before = position;
int instruction = left.instruction;
switch(instruction)
{
case LOAD_LOCAL:
{
Local foundLocal = (Local) left.operand1;
if(foundLocal.isFinal())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.local-final.write"), new Object[] { foundLocal }
)) { source = source, position = before };
}
Type leftType = foundLocal.type;
position = parseExpression(left, source, position + 1, isStaticOnly);
Node right = left[-1];
requiresValue(right);
Type rightType = right.type;
if(!leftType.isConvertableFrom(rightType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { rightType, leftType }
)) { source = source, position = before };
}
cast(right, leftType);
left.setData(before, null, STORE_LOCAL, foundLocal);
break label0;
}
case LOAD_STATIC:
{
Field foundField = (Field) left.operand1;
Callable enclosingCallable = parent.parentCode.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
if(foundField.isFinal() && (!(enclosingCallable instanceof ClassInit) || foundField.parentType != enclosingClassType || foundField.value != null))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundField }
)) { source = source, position = before };
}
Type leftType = foundField.type;
position = parseExpression(left, source, position + 1, isStaticOnly);
Node right = left[-1];
requiresValue(right);
Type rightType = right.type;
if(!leftType.isConvertableFrom(rightType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { rightType, leftType }
)) { source = source, position = before };
}
cast(right, leftType);
left.setData(before, null, STORE_STATIC, foundField);
break label0;
}
case WRITE_SPECIAL:
case WRITE_PROPERTY:
if(left.length != 1) break;
/* падение через */
case READ_FIELD:
case READ_SPECIAL:
case READ_PROPERTY:
{
TypedMember foundFieldoid = (TypedMember) left.operand1;
if(foundFieldoid instanceof Property)
{
if(!((Property) foundFieldoid).hasWrite())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.property-read-only.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
} else
{
Node load = left[0];
Callable enclosingCallable = parent.parentCode.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
if(
foundFieldoid.isFinal() && (
!(enclosingCallable instanceof InstInit) || foundFieldoid.parentType != enclosingClassType ||
load.instruction != LOAD_LOCAL || load.operand1 != enclosingCallable.arguments.thisArgument
)
)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
}
Type leftType = foundFieldoid.type;
position = parseExpression(left, source, position + 1, isStaticOnly);
Node right = left[-1];
requiresValue(right);
Type rightType = right.type;
if(!leftType.isConvertableFrom(rightType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { rightType, leftType }
)) { source = source, position = before };
}
cast(right, leftType);
left.setData(before, null, instruction >= WRITE_OPERATOR ? instruction : instruction + A_DELTA, foundFieldoid);
break label0;
}
case READ_COMPONENT:
{
Type leftType = (Type) left.type;
position = parseExpression(left, source, position + 1, isStaticOnly);
Node right = left[-1];
requiresValue(right);
Type rightType = right.type;
if(!leftType.isConvertableFrom(rightType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { rightType, leftType }
)) { source = source, position = before };
}
cast(right, leftType);
left.setData(before, null, WRITE_COMPONENT, leftType);
break label0;
}
case INVOKE_VIRTUAL:
if(left.operand1 == null)
{
position = parseExpression(left, source, position + 1, isStaticOnly);
Node load = left[0];
Node index = left[1];
Node value = left[2];
requiresValue(value);
ClassType enclosingClassType = parent.parentCode.parentCallable.parentType;
ClassType dereferenceClassType = (ClassType) load.type;
Type[] arguments = new Type[] { index.type, value.type };
Operator[] foundOperators = dereferenceClassType.findOperators(WRITE_COMPONENT, arguments, enclosingClassType);
int foundLength = foundOperators == null ? 0 : foundOperators.length;
if(foundLength < 1)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.operator"), new Object[] { dereferenceClassType, VIEWNAME_OPERATOR + Operator.kindToSymbol(WRITE_COMPONENT) }
)) { source = source, position = before };
}
Operator foundOperator = foundOperators[0];
if(!foundOperator.isConvertableArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-applicable.operator"), new Object[] { foundOperator, ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
boolean isUseSuper = load.useSuper;
if(!foundOperator.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosingClassType.specialSimpleName, foundOperator }
)) { source = source, position = before };
}
if(foundLength > 1)
{
throw new TextSourceException(String.format(
package.getResourceString("ambiguous.operator"),
new Object[] { new StringBuilder(0x0400) + dereferenceClassType + ("." + VIEWNAME_OPERATOR) + Operator.kindToSymbol(WRITE_COMPONENT) + foundOperator.arguments }
)) { source = source, position = before };
}
if(isUseSuper && foundOperator.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.operator"), new Object[] { foundOperator }
)) { source = source, position = before };
}
with(foundOperator.arguments)
{
cast(index, operator [](0).type);
cast(value, operator [](1).type);
}
left.setData(before, null, isUseSuper ? INVOKE_SPECIAL : invokeInstructionFor(foundOperator, dereferenceClassType), foundOperator);
break label0;
}
}
throw new TextSourceException(String.format(
package.getResourceString("applicable.operator.increment-decrement"), new Object[] { source.getLexemeString(before) }
)) { source = source, position = before };
case A_BIT_AND:
case A_BIT_OR:
case A_BIT_XOR:
case A_SCAL_MUL:
case A_SCAL_DIV:
case A_SCAL_DIVU:
case A_SCAL_REM:
case A_SCAL_REMU:
case A_SCAL_ADD:
case A_SCAL_SUB:
case A_SCAL_SHR:
case A_SCAL_SHRU:
case A_SCAL_SHL:
case A_VECT_MUL:
case A_VECT_DIV:
case A_VECT_ADD:
case A_VECT_SUB:
case A_VECT_SHR:
case A_VECT_SHRU:
case A_VECT_SHL:
case A_VECT_GT:
case A_VECT_GE:
case A_VECT_LT:
case A_VECT_LE:
case A_VECT_EQ:
case A_VECT_NE:
case A_VECT_HMUL:
case A_VECT_HMULU:
case A_VECT_SADD:
case A_VECT_SADDU:
case A_VECT_SSUB:
case A_VECT_SSUBU:
Type leftType;
Node action;
Node right;
Node left = parent[-1];
Code code = parent.parentCode;
int before = position;
operation -= A_DELTA;
label1:
{
int instruction = left.instruction;
switch(instruction)
{
case LOAD_LOCAL:
{
Local foundLocal = (Local) left.operand1;
if(foundLocal.isFinal())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.local-final.write"), new Object[] { foundLocal }
)) { source = source, position = before };
}
leftType = foundLocal.type;
position = parseExpression(action = code.createAndAppendNode(left), source, position + 1, isStaticOnly);
requiresValue(right = action[-1]);
code.createAndPrependNode(action).setData(left.position, leftType, LOAD_LOCAL, foundLocal);
left.setData(before, null, STORE_LOCAL, foundLocal);
break label1;
}
case LOAD_STATIC:
{
Field foundField = (Field) left.operand1;
Callable enclosingCallable = parent.parentCode.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
if(foundField.isFinal() && (!(enclosingCallable instanceof ClassInit) || foundField.parentType != enclosingClassType || foundField.value != null))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundField }
)) { source = source, position = before };
}
leftType = foundField.type;
position = parseExpression(action = code.createAndAppendNode(left), source, position + 1, isStaticOnly);
requiresValue(right = action[-1]);
code.createAndPrependNode(action).setData(left.position, leftType, LOAD_STATIC, foundField);
left.setData(before, null, STORE_STATIC, foundField);
break label1;
}
case READ_FIELD:
case READ_SPECIAL:
case READ_PROPERTY:
{
TypedMember foundFieldoid = (TypedMember) left.operand1;
if(foundFieldoid instanceof Property)
{
if(!((Property) foundFieldoid).hasWrite())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.property-read-only.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
} else
{
Node load = left[0];
Callable enclosingCallable = parent.parentCode.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
if(
foundFieldoid.isFinal() && (
!(enclosingCallable instanceof InstInit) || foundFieldoid.parentType != enclosingClassType ||
load.instruction != LOAD_LOCAL || load.operand1 != enclosingCallable.arguments.thisArgument
)
)
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.access.field-final.write"), new Object[] { foundFieldoid }
)) { source = source, position = before };
}
}
leftType = foundFieldoid.type;
position = parseExpression(action = code.createAndAppendNode(left), source, position + 1, isStaticOnly);
requiresValue(right = action[-1]);
Node read = code.createAndPrependNode(action).setData(left.position, leftType, instruction, foundFieldoid);
code.createAndAppendNode(read).setData(-1, null, DUP1, fldTypeObject);
left.setData(before, null, instruction + A_DELTA, foundFieldoid);
break label1;
}
case READ_COMPONENT:
{
leftType = (Type) left.operand1;
position = parseExpression(action = code.createAndAppendNode(left), source, position + 1, isStaticOnly);
requiresValue(right = action[-1]);
Node read = code.createAndPrependNode(action).setData(left.position, leftType, READ_COMPONENT, leftType);
code.createAndAppendNode(read).setData(-1, null, DUP2, fldTypeInt);
left.setData(before, null, WRITE_COMPONENT, leftType);
break label1;
}
case INVOKE_SERVICE:
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
Operator foundReadOperator;
TableItem foundCallable = left.operand1;
if(foundCallable instanceof Operator && (foundReadOperator = (Operator) foundCallable).kind == READ_COMPONENT)
{
leftType = foundReadOperator.type;
Node load = left[0];
ClassType enclosingClassType = parent.parentCode.parentCallable.parentType;
ClassType dereferenceClassType = (ClassType) load.type;
Type[] arguments = new Type[] { foundReadOperator.arguments[0].type, leftType };
Operator[] foundOperators = dereferenceClassType.findOperators(WRITE_COMPONENT, arguments, enclosingClassType);
Operator foundWriteOperator = foundOperators == null || foundOperators.length != 1 ? null : foundOperators[0];
if(foundWriteOperator == null || !foundWriteOperator.isIdentityArguments(arguments))
{
throw new TextSourceException(String.format(
package.getResourceString("not-found.operator"), new Object[] { dereferenceClassType, Operator.kindToSymbol(WRITE_COMPONENT) + ArgumentArray.toString(arguments) }
)) { source = source, position = before };
}
boolean isUseSuper = load.useSuper;
if(!foundWriteOperator.isVisibleFrom(enclosingClassType, isUseSuper ? enclosingClassType : dereferenceClassType))
{
throw new TextSourceException(String.format(
package.getResourceString("invisible.operator"), new Object[] { enclosingClassType.specialSimpleName, foundWriteOperator }
)) { source = source, position = before };
}
if(isUseSuper && foundWriteOperator.isAbstract())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.direct-access-abstract.operator"), new Object[] { foundWriteOperator }
)) { source = source, position = before };
}
position = parseExpression(action = code.createAndAppendNode(left), source, position + 1, isStaticOnly);
requiresValue(right = action[-1]);
Node read = code.createAndPrependNode(action).setData(left.position, leftType, instruction, foundReadOperator);
code.createAndAppendNode(read).setData(-1, null, DUP2, arguments[0]);
left.setData(before, null, isUseSuper ? INVOKE_SPECIAL : invokeInstructionFor(foundWriteOperator, dereferenceClassType), foundWriteOperator);
break label1;
}
}
throw new TextSourceException(String.format(
package.getResourceString("applicable.operator.increment-decrement"), new Object[] { source.getLexemeString(before) }
)) { source = source, position = before };
}
Type rightType = right.type;
if(!(leftType instanceof PrimitiveType) || !leftType.isBoolean() && !leftType.isNumeric() || !(rightType instanceof PrimitiveType) || !rightType.isBoolean() && !rightType.isNumeric())
{
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), leftType, rightType }
)) { source = source, position = before };
}
boolean isChar = leftType.isChar();
Type typeInt = fldTypeInt;
Type mustType;
switch(operation)
{
case O_SCAL_SHR:
case O_SCAL_SHRU:
case O_SCAL_SHL:
case O_VECT_SHR:
case O_VECT_SHRU:
case O_VECT_SHL:
mustType = typeInt;
break;
default:
mustType = isChar ? typeInt : leftType;
}
if(!mustType.isConvertableFrom(rightType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { rightType, mustType }
)) { source = source, position = before };
}
cast(right, mustType);
int kind = leftType.kind;
Type resultType;
label1:
{
switch(operation)
{
case O_BIT_AND:
case O_BIT_OR:
case O_BIT_XOR:
if(kind == CHAR)
{
resultType = typeInt;
break label1;
}
if(kind == BOOLEAN || kind >= BYTE && kind <= LONG8)
{
resultType = leftType;
break label1;
}
break;
case O_SCAL_MUL:
case O_SCAL_ADD:
case O_SCAL_SUB:
if(kind == CHAR)
{
resultType = typeInt;
break label1;
}
if(kind >= BYTE && kind <= SHORT8)
{
resultType = getPrimitiveType(INT | kind & 3);
break label1;
}
if(kind >= REAL && kind <= FLOAT8 || kind >= INT && kind <= LONG8)
{
resultType = leftType;
break label1;
}
break;
case O_SCAL_DIV:
case O_SCAL_DIVU:
if(kind == CHAR || kind == BYTE || kind == SHORT)
{
resultType = typeInt;
break label1;
}
if(kind >= REAL && kind <= FLOAT8 || kind == INT || kind == LONG)
{
resultType = leftType;
break label1;
}
break;
case O_SCAL_REM:
case O_SCAL_REMU:
if(kind == CHAR || kind == BYTE || kind == SHORT)
{
resultType = typeInt;
break label1;
}
if(kind == REAL || kind == DOUBLE || kind == FLOAT || kind == INT || kind == LONG)
{
resultType = leftType;
break label1;
}
break;
case O_SCAL_SHR:
case O_SCAL_SHRU:
case O_SCAL_SHL:
if(kind == CHAR)
{
resultType = typeInt;
break label1;
}
if(kind >= BYTE && kind <= SHORT8)
{
resultType = getPrimitiveType(INT | kind & 3);
break label1;
}
if(kind >= INT && kind <= LONG8)
{
resultType = leftType;
break label1;
}
break;
case O_VECT_MUL:
case O_VECT_ADD:
case O_VECT_SUB:
if(kind == CHAR)
{
resultType = typeInt;
break label1;
}
if(kind >= DOUBLE && kind <= LONG8)
{
resultType = leftType;
break label1;
}
break;
case O_VECT_DIV:
if(kind >= DOUBLE && kind <= FLOAT8)
{
resultType = leftType;
break label1;
}
break;
case O_VECT_SHR:
case O_VECT_SHRU:
case O_VECT_SHL:
case O_VECT_GT:
case O_VECT_GE:
case O_VECT_LT:
case O_VECT_LE:
case O_VECT_EQ:
case O_VECT_NE:
if(kind == CHAR)
{
resultType = typeInt;
break label1;
}
if(kind >= BYTE && kind <= LONG8)
{
resultType = leftType;
break label1;
}
break;
case O_VECT_HMUL:
case O_VECT_HMULU:
case O_VECT_SADD:
case O_VECT_SADDU:
case O_VECT_SSUB:
case O_VECT_SSUBU:
if(kind >= BYTE && kind <= SHORT8)
{
resultType = leftType;
break label1;
}
break;
default:
break label1;
}
throw new TextSourceException(String.format(
package.getResourceString("not-defined.operator.2"), new Object[] { source.getLexemeString(before), leftType, rightType }
)) { source = source, position = before };
}
action.setData(before, resultType, operation, isChar ? typeInt : leftType);
cast(action, leftType);
}
return position;
}
private int parseDeclareLocal(Node parent, TextSource source, int position, boolean isLocalAllowed) throws TextSourceException {
label0:
{
if(isLocalAllowed)
{
int kind = source.getLexemeKind(position);
boolean isFinal = false;
if(kind == FINAL)
{
isFinal = true;
kind = source.getLexemeKind(++position);
}
boolean isName = kind == L_NAME;
if(kind >= VOID && kind < VOID + PRIMITIVES_LENGTH || isName)
{
ImmediateBuilderItemHolder localTypeHolder = getItemHolder();
int after = isName ? (
tryParseName(parent, source, position, source.getLexemeString(position), localTypeHolder)
) : (
tryParseTypeName(source, position, parent.parentCode.parentCallable.parentType, localTypeHolder)
);
Type localType = localTypeHolder.resultType;
if(localType != null && source.getLexemeKind(after) == L_NAME)
{
position = after;
if(localType.isVoid())
{
throw new TextSourceException(String.format(
package.getResourceString("type.not-suitable.local"), new Object[] { localType }
)) { source = source, position = position };
}
String localName = source.getLexemeString(position);
tryParseName(parent, source, position, localName, localTypeHolder);
if(localTypeHolder.resultItem instanceof Local)
{
throw new TextSourceException(String.format(
package.getResourceString("duplicate.name.local"), new Object[] { localName }
)) { source = source, position = position };
}
int before = position++;
Code code = parent.parentCode;
Node declare = code.createAndAppendNode(parent);
if(source.getLexemeKind(position) == EQUALS)
{
position = parseExpression(declare, source, position + 1, false);
Node value = declare[-1];
requiresValue(value);
Type valueType = value.type;
if(!localType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, localType }
)) { source = source, position = before + 1 };
}
cast(value, localType);
if(isFinal && value.instruction == LOAD_CONST)
{
Constant localValue = (Constant) value.operand1;
if(!localValue.isReference() || localValue.isReflective() || localValue.isNull())
{
declare.setData(before + 1, null, DECLARE_LOCAL, code.createLocal(true, localType, localName, localValue, before));
code.removeNode(value);
break label0;
}
}
declare.setData(before + 1, null, DECLARE_LOCAL, code.createLocal(isFinal, localType, localName, null, before));
break label0;
}
if(isFinal)
{
throw new TextSourceException(package.getResourceString("expected.equals")) { source = source, position = position };
}
if(localType instanceof ClassType)
{
code.createAndAppendNode(declare).setData(-1, localType, LOAD_CONST, fldNull.castTo(localType));
}
else if(localType.isNumeric())
{
code.createAndAppendNode(declare).setData(-1, localType, LOAD_CONST, fldConstantFactory.createByte(0).castTo(localType));
}
else
{
code.createAndAppendNode(declare).setData(-1, localType, LOAD_CONST, fldFalse);
}
declare.setData(-1, null, DECLARE_LOCAL, code.createLocal(false, localType, localName, null, before));
break label0;
}
}
if(isFinal)
{
throw new TextSourceException(package.getResourceString("expected.declaration.local")) { source = source, position = position };
}
}
position = parseExpression(parent, source, position, false);
Code code = parent.parentCode;
Node value = parent[-1];
switch(value.instruction)
{
case INC_POST_LOAD_LOCAL:
case INC_PRED_LOAD_LOCAL:
value.setData(value.position, null, INC_LOCAL, value.operand1);
break;
case DEC_POST_LOAD_LOCAL:
case DEC_PRED_LOAD_LOCAL:
value.setData(value.position, null, DEC_LOCAL, value.operand1);
break;
case INVOKE_STATIC:
if(!((Callable) value.operand1).type.isVoid()) value.weak = true;
value.type = null;
break;
case INVOKE_SERVICE:
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
Callable foundCallable = (Callable) value.operand1;
if(!(foundCallable instanceof Operator) || ((Operator) foundCallable).kind != WRITE_COMPONENT)
{
if(!foundCallable.type.isVoid()) value.weak = true;
value.type = null;
break;
}
/* падение через */
case WRITE_COMPONENT:
Node last = value[-1];
if(last.instruction == DUP1X2)
{
code.removeNode(last);
value.type = null;
break;
}
if(value.length == 4)
{
if(last.instruction == CAST_TO)
{
last = last[0];
}
int instruction = last.instruction;
if(instruction == O_SCAL_ADD || instruction == O_VECT_ADD)
{
Node dup = last[0];
if(dup.instruction == DUP1X2)
{
code.removeNode(dup);
code.moveNode(value[-2], last, 0);
value.type = null;
}
}
}
break;
case WRITE_FIELD:
case WRITE_SPECIAL:
case WRITE_PROPERTY:
Node last = value[-1];
if(last.instruction == DUP1X1)
{
code.removeNode(last);
value.type = null;
break;
}
if(value.length == 3)
{
if(last.instruction == CAST_TO)
{
last = last[0];
}
int instruction = last.instruction;
if(instruction == O_SCAL_ADD || instruction == O_VECT_ADD)
{
Node dup = last[0];
if(dup.instruction == DUP1X1)
{
code.removeNode(dup);
code.moveNode(value[-2], last, 0);
value.type = null;
}
}
}
break;
case STORE_LOCAL:
case STORE_STATIC:
Node last = value[-1];
if(last.instruction == DUP1)
{
code.removeNode(last);
value.type = null;
break;
}
if(value.length == 2)
{
if(last.instruction == CAST_TO)
{
last = last[0];
}
int instruction = last.instruction;
if(instruction == O_SCAL_ADD || instruction == O_VECT_ADD)
{
Node dup = last[0];
if(dup.instruction == DUP1)
{
code.removeNode(dup);
code.moveNode(value[-2], last, 0);
value.type = null;
}
}
}
break;
case NEW_INSTANCE:
Node dup = value[-1][0];
if(dup.instruction == DUP1)
{
code.removeNode(dup);
value.type = null;
}
break;
default:
throw new TextSourceException(package.getResourceString("expected.invocation-or-assignment")) { source = source, position = position };
}
}
return position;
}
private int parseDeclareWith(Node parent, TextSource source, int position, boolean isSynchronized) throws TextSourceException {
label0:
{
{
int kind = source.getLexemeKind(position);
boolean isFinal = false;
if(kind == FINAL)
{
isFinal = true;
kind = source.getLexemeKind(++position);
}
boolean isName = kind == L_NAME;
if(kind >= VOID && kind < VOID + PRIMITIVES_LENGTH || isName)
{
ImmediateBuilderItemHolder localTypeHolder = getItemHolder();
int after = isName ? (
tryParseName(parent, source, position, source.getLexemeString(position), localTypeHolder)
) : (
tryParseTypeName(source, position, parent.parentCode.parentCallable.parentType, localTypeHolder)
);
Type localType = localTypeHolder.resultType;
if(localType != null && source.getLexemeKind(after) == L_NAME)
{
position = after;
if(!(localType instanceof ClassType))
{
throw new TextSourceException(String.format(
package.getResourceString(isSynchronized ? "must-be.class-type.local.synchronized" : "must-be.class-type.local.with"), new Object[] { localType, fldTypeObject }
)) { source = source, position = position };
}
String localName = source.getLexemeString(position);
tryParseName(parent, source, position, localName, localTypeHolder);
if(localTypeHolder.resultItem instanceof Local)
{
throw new TextSourceException(String.format(
package.getResourceString("duplicate.name.local"), new Object[] { localName }
)) { source = source, position = position };
}
int before = position++;
if(source.getLexemeKind(position) != EQUALS)
{
throw new TextSourceException(package.getResourceString("expected.equals")) { source = source, position = position };
}
Code code = parent.parentCode;
Node declare = code.createAndAppendNode(parent);
position = parseExpression(declare, source, position + 1, false);
Node value = declare[-1];
requiresValue(value);
Type valueType = value.type;
if(!localType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, localType }
)) { source = source, position = before + 1 };
}
cast(value, localType);
if(value.instruction == LOAD_CONST)
{
Constant localValue = (Constant) value.operand1;
if(localValue.isReflective() || localValue.isNull())
{
declare.setData(before + 1, null, isSynchronized ? DECLARE_LOCAL : DECLARE_WITH, code.createLocal(true, localType, localName, localValue, before));
code.removeNode(value);
break label0;
}
}
declare.setData(before + 1, null, isSynchronized ? DECLARE_LOCAL : DECLARE_WITH, code.createLocal(true, localType, localName, null, before));
break label0;
}
}
if(isFinal)
{
throw new TextSourceException(package.getResourceString("expected.declaration.local")) { source = source, position = position };
}
}
Code code = parent.parentCode;
Node declare = code.createAndAppendNode(parent);
position = parseExpression(declare, source, position, false);
Node value = declare[-1];
requiresValue(value);
Type valueType = value.type;
if(!(valueType instanceof ClassType))
{
throw new TextSourceException(String.format(
package.getResourceString(isSynchronized ? "must-be.class-type.expression.synchronized" : "must-be.class-type.expression.with"), new Object[] { valueType, fldTypeObject }
)) { source = source, position = position };
}
if(value.instruction == LOAD_CONST)
{
Constant localValue = (Constant) value.operand1;
if(localValue.isReflective() || localValue.isNull())
{
if(isSynchronized)
{
declare.setData(-1, null, DECLARE_LOCAL, code.createMonitorLocal((ClassType) valueType, localValue));
} else
{
declare.setData(-1, null, DECLARE_WITH, code.createWithLocal((ClassType) valueType, localValue));
}
code.removeNode(value);
break label0;
}
}
if(isSynchronized)
{
declare.setData(-1, null, DECLARE_LOCAL, code.createMonitorLocal((ClassType) valueType, null));
} else
{
declare.setData(-1, null, DECLARE_WITH, code.createWithLocal((ClassType) valueType, null));
}
}
return position;
}
private int parseBlock(Node control, TextSource source, int position) throws TextSourceException {
label0: if(source.getLexemeKind(position) != CURLY_CLOSED) do
{
switch(source.getLexemeKind(position = parseControl(control, source, position)))
{
case L_END:
throw new TextSourceException(package.getResourceString("expected.closed-curly")) { source = source, position = position };
case CURLY_CLOSED:
break label0;
}
} while(true);
return position + 1;
}
private int parseBreak(Node control, TextSource source, int position) throws TextSourceException {
label0:
{
if(source.getLexemeKind(position) != L_NAME)
{
/* без метки */
for(Node node = control.parentNode; node != null; node = node.parentNode) switch(node.instruction)
{
case FINALLY_ENTER:
throw new TextSourceException(package.getResourceString("can-not-transfer.outside-finally")) { source = source, position = position };
case DO:
case FOR:
case WHILE:
case SWITCH:
control.setData(control.position, BREAK, node);
break label0;
}
throw new TextSourceException(package.getResourceString("can-not-use.break")) { source = source, position = position };
}
/* с меткой */
Object labelName = source.getLexemeString(position);
for(Node node = control.parentNode; node != null; node = node.parentNode) switch(node.instruction)
{
case FINALLY_ENTER:
throw new TextSourceException(package.getResourceString("can-not-transfer.outside-finally")) { source = source, position = position };
case LABEL:
if(labelName.equals(node.reference1))
{
control.setData(control.position, BREAK, node);
position++;
break label0;
}
}
throw new TextSourceException(String.format(
package.getResourceString("not-found.label"), new Object[] { labelName }
)) { source = source, position = position };
}
/* точка с запятой */
if(source.getLexemeKind(position) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
return position + 1;
}
private int parseContinue(Node control, TextSource source, int position) throws TextSourceException {
label0:
{
if(source.getLexemeKind(position) != L_NAME)
{
/* без метки */
for(Node node = control.parentNode; node != null; node = node.parentNode) switch(node.instruction)
{
case FINALLY_ENTER:
throw new TextSourceException(package.getResourceString("can-not-transfer.outside-finally")) { source = source, position = position };
case DO:
case FOR:
case WHILE:
control.setData(control.position, CONTINUE, node);
break label0;
}
throw new TextSourceException(package.getResourceString("can-not-use.continue")) { source = source, position = position };
}
/* с меткой */
Object labelName = source.getLexemeString(position);
for(Node node = control.parentNode; node != null; node = node.parentNode) switch(node.instruction)
{
case FINALLY_ENTER:
throw new TextSourceException(package.getResourceString("can-not-transfer.outside-finally")) { source = source, position = position };
case LABEL:
if(labelName.equals(node.reference1))
{
int instruction = (node = node[0]).instruction;
if(instruction != DO && instruction != FOR && instruction != WHILE)
{
throw new TextSourceException(package.getResourceString("can-not-use.continue")) { source = source, position = position };
}
control.setData(control.position, CONTINUE, node);
position++;
break label0;
}
}
throw new TextSourceException(String.format(
package.getResourceString("not-found.label"), new Object[] { labelName }
)) { source = source, position = position };
}
/* точка с запятой */
if(source.getLexemeKind(position) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
return position + 1;
}
private int parseDo(Node control, TextSource source, int position) throws TextSourceException {
/* тело цикла */
if(source.getLexemeKind(position = parseControl(control, source, position)) != WHILE)
{
throw new TextSourceException(package.getResourceString("expected.while")) { source = source, position = position };
}
/* условие повтора */
if(source.getLexemeKind(++position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
position = parseExpression(control, source, position + 1, false);
Node condition = control[-1];
requiresValue(condition);
Type conditionType = condition.type;
if(!conditionType.isBoolean())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-use.expression.repeat-condition"), new Object[] { conditionType, fldTypeBoolean }
)) { source = source, position = position };
}
if(source.getLexemeKind(position) != PARENTH_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
}
/* точка с запятой */
if(source.getLexemeKind(++position) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
return position + 1;
}
private int parseFor(Node control, TextSource source, int position) throws TextSourceException {
/* инициализация */
if(source.getLexemeKind(position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
label0: if(source.getLexemeKind(++position) != SEMICOLON) do
{
switch(source.getLexemeKind(position = parseDeclareLocal(control, source, position, true)))
{
default:
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
case SEMICOLON:
break label0;
case COMMA:
position++;
}
} while(true);
Code code = control.parentCode;
code.createAndAppendNode(control).setData(-1, JUMP);
/* условие повтора */
Node condition;
if(source.getLexemeKind(++position) == SEMICOLON)
{
condition = code.createAndAppendNode(control).setData(-1, fldTypeBoolean, LOAD_CONST, fldTrue);
} else
{
position = parseExpression(control, source, position, false);
requiresValue(condition = control[-1]);
Type conditionType = condition.type;
if(!conditionType.isBoolean())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-use.expression.repeat-condition"), new Object[] { conditionType, fldTypeBoolean }
)) { source = source, position = position };
}
if(source.getLexemeKind(position) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
}
/* шаг */
Node step = code.createAndAppendNode(control).setData(-1, BLOCK);
label0: if(source.getLexemeKind(++position) != PARENTH_CLOSED) do
{
switch(source.getLexemeKind(position = parseDeclareLocal(step, source, position, false)))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
case PARENTH_CLOSED:
break label0;
case COMMA:
position++;
}
} while(true);
/* тело цикла */
position = parseControl(control, source, position + 1);
/* перестановка узлов */
int index = control.length;
code.moveNode(step, index);
code.moveNode(condition, index);
return position;
}
private int parseIf(Node control, TextSource source, int position) throws TextSourceException {
/* условие ветвления */
if(source.getLexemeKind(position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
position = parseExpression(control, source, position + 1, false);
Node condition = control[-1];
requiresValue(condition);
Type conditionType = condition.type;
if(!conditionType.isBoolean())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-use.expression.branch-condition"), new Object[] { conditionType, fldTypeBoolean }
)) { source = source, position = position };
}
if(source.getLexemeKind(position) != PARENTH_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
}
/* ветка «тогда» */
if(source.getLexemeKind(position = parseControl(control, source, position + 1)) == ELSE)
{
/* ветка «иначе» */
control.parentCode.createAndAppendNode(control).setData(-1, JUMP).special = true;
position = parseControl(control, source, position + 1);
}
return position;
}
private int parseReturn(Node control, TextSource source, int position) throws TextSourceException {
Type targetType = control.parentCode.parentCallable.type;
if(!targetType.isVoid())
{
position = parseExpression(control, source, position, false);
Node value = control[-1];
requiresValue(value);
Type valueType = value.type;
if(!targetType.isConvertableFrom(valueType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { valueType, targetType }
)) { source = source, position = position };
}
cast(value, targetType);
}
for(Node node = control.parentNode; node != null; node = node.parentNode) if(node.instruction == FINALLY_ENTER)
{
throw new TextSourceException(package.getResourceString("can-not-transfer.outside-finally")) { source = source, position = position };
}
if(source.getLexemeKind(position) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
return position + 1;
}
private int parseSwitch(Node control, TextSource source, int position) throws TextSourceException {
/* выражение ветвления */
if(source.getLexemeKind(position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
Code code = control.parentCode;
Node branch = code.createAndAppendNode(control).setData(-1, BRANCH);
position = parseExpression(branch, source, position + 1, false);
Node target = branch[-1];
requiresValue(target);
Type targetType = target.type;
if(!targetType.isInt())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-use.expression.branch-switch"), new Object[] { targetType, fldTypeInt }
)) { source = source, position = position };
}
if(source.getLexemeKind(position) != PARENTH_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
}
/* тело ветвления */
if(source.getLexemeKind(++position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
label0: for(position++, Node label = null, int[] labels = new int[0x1f], boolean ldefault = false, int llength = 0; ; ) switch(source.getLexemeKind(position))
{
case CURLY_CLOSED:
if(!ldefault) code.createAndAppendNode(control).setData(position, DEFAULT);
break label0;
case CASE:
int before = position++;
position = parseExpression(control, source, position, false);
if((label = control[-1]).instruction != LOAD_CONST)
{
throw new TextSourceException(package.getResourceString("must-be.constant.case-label")) { source = source, position = position };
}
Type labelType = label.type;
if(!targetType.isConvertableFrom(labelType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.converted.type"), new Object[] { labelType, targetType }
)) { source = source, position = position };
}
int labelValue = ((Constant) label.operand1).asInt();
if(llength > 0 && Array.indexOf(labelValue, labels, 0, llength) >= 0)
{
throw new TextSourceException(String.format(
package.getResourceString("duplicate.label.case"), new Object[] { Int.toString(labelValue) }
)) { source = source, position = position };
}
if(source.getLexemeKind(position) != COLON)
{
throw new TextSourceException(package.getResourceString("expected.colon")) { source = source, position = position };
}
if(llength == labels.length) Array.copy(labels, 0, labels = new int[llength << 1 | 1], 0, llength);
label.setData(before, CASE, new Int(labelValue));
labels[llength++] = labelValue;
position++;
break;
case DEFAULT:
int before = position++;
if(ldefault)
{
throw new TextSourceException(package.getResourceString("duplicate.label.default")) { source = source, position = position };
}
if(source.getLexemeKind(position) != COLON)
{
throw new TextSourceException(package.getResourceString("expected.colon")) { source = source, position = position };
}
label = code.createAndAppendNode(control).setData(before, DEFAULT);
ldefault = true;
position++;
break;
default:
if(label == null)
{
throw new TextSourceException(package.getResourceString("expected.case-or-default")) { source = source, position = position };
}
position = parseControl(label, source, position);
}
return position + 1;
}
private int parseSynchronized(Node control, TextSource source, int position) throws TextSourceException {
boolean isSynchronizedWith = false;
if(source.getLexemeKind(position) == WITH)
{
isSynchronizedWith = true;
position++;
}
/* переменная синхронизации */
if(source.getLexemeKind(position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
position = parseDeclareWith(control, source, position + 1, !isSynchronizedWith);
Local monitor = (Local) control[-1].operand1;
ClassType typeObject = fldTypeObject;
Code code = control.parentCode;
Node enter = code.createAndAppendNode(control).setData(-1, MONITOR_ENTER);
Constant value = monitor.value;
boolean isConstant = monitor.isConstant();
if(isConstant)
{
code.createAndAppendNode(enter).setData(-1, typeObject, LOAD_CONST, value);
} else
{
code.createAndAppendNode(enter).setData(-1, typeObject, LOAD_LOCAL, monitor);
}
if(source.getLexemeKind(position) != PARENTH_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
}
/* тело синхронизации */
if(source.getLexemeKind(++position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
control = code.createAndAppendNode(control).setData(-1, TRY);
Node blockTry = code.createAndAppendNode(control).setData(-1, BEGIN);
position = parseBlock(blockTry, source, position + 1) - 1;
blockTry = code.createAndAppendNode(blockTry).setData(-1, END);
Node blockFinally = code.createAndAppendNode(control).setData(-1, FINALLY_ENTER);
Node leave = code.createAndAppendNode(blockFinally).setData(-1, MONITOR_LEAVE);
if(isConstant)
{
code.createAndAppendNode(leave).setData(-1, typeObject, LOAD_CONST, value);
} else
{
code.createAndAppendNode(leave).setData(-1, typeObject, LOAD_LOCAL, monitor);
}
code.createAndAppendNode(blockFinally).setData(-1, FINALLY_LEAVE).special = true;
code.createAndAppendNode(blockTry).setData(-1, INVOKE_FINALLY, blockFinally).special = true;
code.createAndAppendNode(blockTry).setData(-1, JUMP).special = true;
return position + 1;
}
private int parseThrow(Node control, TextSource source, int position) throws TextSourceException {
/* выражение */
position = parseExpression(control, source, position, false);
Node target = control[-1];
requiresValue(target);
Type targetType = target.type;
Type typeThrowable = fldTypeThrowable;
if(!typeThrowable.isConvertableFrom(targetType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.thrown"), new Object[] { targetType, typeThrowable }
)) { source = source, position = position };
}
/* точка с запятой */
if(source.getLexemeKind(position) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
control.setData(control.position, THROW, targetType);
return position + 1;
}
private int parseTry(Node control, TextSource source, int position) throws TextSourceException {
/* проверка на вложение в блок finally */
for(Node node = control.parentNode; node != null; node = node.parentNode) if(node.instruction == FINALLY_ENTER)
{
throw new TextSourceException(package.getResourceString("can-not-be.try-inside-finally")) { source = source, position = position - 1 };
}
/* тело блока */
if(source.getLexemeKind(position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
Code code = control.parentCode;
Node blockTry = code.createAndAppendNode(control).setData(position, BEGIN);
position = parseBlock(blockTry, source, position + 1);
(blockTry = code.createAndAppendNode(blockTry).setData(-1, END));
switch(source.getLexemeKind(position))
{
case CATCH:
Node blockCatch = null;
Node parent = control.parentNode;
ClassType typeThrowable = fldTypeThrowable;
ClassType enclosing = code.parentCallable.parentType;
ImmediateBuilderItemHolder localTypeHolder = getItemHolder();
do
{
/* тело блока catch */
int block = position;
if(blockCatch != null)
{
code.createAndAppendNode(blockCatch).setData(-1, JUMP).special = true;
}
if(source.getLexemeKind(++position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
if(source.getLexemeKind(++position) != L_NAME)
{
throw new TextSourceException(package.getResourceString("expected.name.exception.type")) { source = source, position = position };
}
position = parseTypeName(source, position, enclosing, localTypeHolder);
Type localType = localTypeHolder.resultType;
if(!typeThrowable.isConvertableFrom(localType))
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-be.thrown"), new Object[] { localType, typeThrowable }
)) { source = source, position = position };
}
if(source.getLexemeKind(position) != L_NAME)
{
throw new TextSourceException(package.getResourceString("expected.name.exception.local")) { source = source, position = position };
}
int before = position;
String localName = source.getLexemeString(position);
tryParseName(parent, source, position, localName, localTypeHolder);
if(localTypeHolder.resultItem instanceof Local)
{
throw new TextSourceException(String.format(
package.getResourceString("duplicate.name.local"), new Object[] { localName }
)) { source = source, position = position };
}
if(source.getLexemeKind(++position) != PARENTH_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
}
if(source.getLexemeKind(++position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
blockCatch = code.createAndAppendNode(control).setData(block, CATCH, localType);
code.createAndAppendNode(blockCatch).setData(-1, null, DECLARE_LOCAL, code.createLocal(true, localType, localName, null, before));
} while(source.getLexemeKind(position = parseBlock(blockCatch, source, position + 1)) == CATCH);
code.createAndAppendNode(blockTry).setData(-1, JUMP).special = true;
break;
case FINALLY:
/* тело блока finally */
if(source.getLexemeKind(++position) != CURLY_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-curly")) { source = source, position = position };
}
Node blockFinally = code.createAndAppendNode(control).setData(-1, FINALLY_ENTER);
position = parseBlock(blockFinally, source, position + 1);
code.createAndAppendNode(blockFinally).setData(-1, FINALLY_LEAVE).special = true;
code.createAndAppendNode(blockTry).setData(-1, INVOKE_FINALLY, blockFinally).special = true;
code.createAndAppendNode(blockTry).setData(-1, JUMP).special = true;
break;
default:
throw new TextSourceException(package.getResourceString("expected.catch-or-finally")) { source = source, position = position };
}
return position;
}
private int parseWhile(Node control, TextSource source, int position) throws TextSourceException {
/* условие повтора */
if(source.getLexemeKind(position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
position = parseExpression(control, source, position + 1, false);
Node condition = control[-1];
requiresValue(condition);
Type conditionType = condition.type;
if(!conditionType.isBoolean())
{
throw new TextSourceException(String.format(
package.getResourceString("can-not-use.expression.repeat-condition"), new Object[] { conditionType, fldTypeBoolean }
)) { source = source, position = position };
}
if(source.getLexemeKind(position) != PARENTH_CLOSED)
{
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
}
/* тело цикла */
position = parseControl(control, source, position + 1);
Code code = control.parentCode;
code.moveNode(condition, control.length);
code.createAndPrependNode(control).setData(-1, JUMP);
return position;
}
private int parseWith(Node control, TextSource source, int position) throws TextSourceException {
/* переменные ссылочного типа для быстрого доступа к членам их типов */
if(source.getLexemeKind(position) != PARENTH_OPENED)
{
throw new TextSourceException(package.getResourceString("expected.opened-parenth")) { source = source, position = position };
}
label0: for(position++; ; )
{
switch(source.getLexemeKind(position = parseDeclareWith(control, source, position, false)))
{
default:
throw new TextSourceException(package.getResourceString("expected.closed-parenth")) { source = source, position = position };
case PARENTH_CLOSED:
break label0;
case COMMA:
position++;
}
}
/* тело с быстрым доступом к членам типов переменных */
return parseControl(control, source, position + 1);
}
private int parseControl(Node parent, TextSource source, int position) throws TextSourceException {
Code code = parent.parentCode;
for(; source.getLexemeKind(position) == L_NAME && source.getLexemeKind(position + 1) == COLON; position += 2)
{
parent = code.createAndAppendNode(parent).setData(position, LABEL, source.getLexemeString(position));
}
switch(source.getLexemeKind(position))
{
case SEMICOLON:
code.createAndAppendNode(parent).setData(position++, BLOCK);
break;
case CURLY_OPENED:
position = parseBlock(code.createAndAppendNode(parent).setData(position++, BLOCK), source, position);
break;
case BREAK:
position = parseBreak(code.createAndAppendNode(parent).setData(position++, BREAK, null), source, position);
break;
case CONTINUE:
position = parseContinue(code.createAndAppendNode(parent).setData(position++, CONTINUE, null), source, position);
break;
case DO:
position = parseDo(code.createAndAppendNode(parent).setData(position++, DO), source, position);
break;
case FOR:
position = parseFor(code.createAndAppendNode(parent).setData(position++, FOR), source, position);
break;
case IF:
position = parseIf(code.createAndAppendNode(parent).setData(position++, IF), source, position);
break;
case RETURN:
position = parseReturn(code.createAndAppendNode(parent).setData(position++, RETURN), source, position);
break;
case SWITCH:
position = parseSwitch(code.createAndAppendNode(parent).setData(position++, SWITCH), source, position);
break;
case SYNCHRONIZED:
position = parseSynchronized(code.createAndAppendNode(parent).setData(position++, BLOCK), source, position);
break;
case THROW:
position = parseThrow(code.createAndAppendNode(parent).setData(position++, THROW, null), source, position);
break;
case TRY:
position = parseTry(code.createAndAppendNode(parent).setData(position++, TRY), source, position);
break;
case WHILE:
position = parseWhile(code.createAndAppendNode(parent).setData(position++, WHILE), source, position);
break;
case WITH:
position = parseWith(code.createAndAppendNode(parent).setData(position++, BLOCK), source, position);
break;
default:
if(source.getLexemeKind(position = parseDeclareLocal(parent, source, position, true)) != SEMICOLON)
{
throw new TextSourceException(package.getResourceString("expected.semicolon")) { source = source, position = position };
}
position++;
}
return position;
}
private int tryParseName(Node parent, TextSource source, int position, String name, ImmediateBuilderItemHolder parsed) {
Callable enclosingCallable = parent.parentCode.parentCallable;
ClassType enclosingClassType = enclosingCallable.parentType;
TableItem resultItem = null;
Local resultWith = null;
label0:
{
/* поиск среди локальных переменных */
do for(int index = parent.length; index-- > 0; )
{
Node child = parent[index];
switch(child.instruction)
{
case DECLARE_WITH:
Local local = (Local) child.operand1;
if((resultItem = ((ClassType) local.type).resolveName(name, enclosingClassType, true)) != null)
{
resultWith = local;
break label0;
}
/* падение через */
case DECLARE_LOCAL:
Local local = (Local) child.operand1;
if(name.equals(local.specialSimpleName))
{
resultItem = local;
break label0;
}
}
} while((parent = parent.parentNode) != null);
/* поиск среди аргументов метода */
{
Local local = enclosingCallable.getArgument(name);
if(local != null)
{
resultItem = local;
break label0;
}
}
/* поиск среди членов типа */
if((resultItem = enclosingClassType.resolveName(name, enclosingClassType, true)) != null)
{
resultWith = enclosingCallable.arguments.thisArgument;
break label0;
}
/* поиск среди типов и пакетов */
if(name.length <= 0 || name[0] != '<')
{
int after = tryParseTypeName(source, position, enclosingClassType, parsed);
return parsed.resultType != null ? after : tryParsePackageName(source, position, enclosingClassType, parsed);
}
}
parsed.resultWith = resultWith;
parsed.resultItem = resultItem;
return position + 1;
}
private int tryParsePackageName(TextSource source, int position, ClassType enclosing, PackageHolder parsed) {
if(source.getLexemeKind(position) != L_NAME)
{
parsed.resultPack = null;
return position;
}
Package result;
{
String name = source.getLexemeString(position++);
/* последние позиция и результат */
int lastPosition = position;
Package lastResult = result = getPackage(name);
/* распознавание канонического имени пакета */
StringBuilder specialCanonicalName = new StringBuilder(LIMIT_NAME_LENGTH) + name;
while(source.getLexemeKind(position) == PERIOD && source.getLexemeKind(position + 1) == L_NAME)
{
position++;
if((result = getPackage((specialCanonicalName + '.' + source.getLexemeString(position++)).toString())) != null)
{
lastPosition = position;
lastResult = result;
}
}
if(result == null)
{
position = lastPosition;
result = lastResult;
}
}
parsed.resultPack = result;
return position;
}
private int tryParseClassName(TextSource source, int position, ClassType enclosing, TypeHolder parsed) {
if(source.getLexemeKind(position) != L_NAME)
{
parsed.resultType = null;
return position;
}
ClassType result;
label0:
{
String name = source.getLexemeString(position++);
/* поиск среди типов в исходном коде */
if((result = source.getDeclaredType(name)) != null) break label0;
if((result = source.getImportedType(name)) != null) break label0;
/* поиск в родительском пакете */
if((result = (ClassType) source.owner.getChildType(name)) != null && result.isVisibleFrom(enclosing)) break label0;
/* поиск среди неявно импортированных типов */
ClassType[] types = source.findImplicitlyImportedTypes(name, enclosing);
int length = types.length;
if(length > 0 && (result = types[0]).isVisibleFrom(enclosing))
{
if(length > 1) result = null;
break label0;
}
/* поиск в языковом пакете */
if((result = (ClassType) getLanguagePackage().getChildType(name)) != null && result.isVisibleFrom(enclosing)) break label0;
/* распознавание канонического имени типа */
StringBuilder specialCanonicalName = new StringBuilder(LIMIT_NAME_LENGTH) + name;
while(source.getLexemeKind(position) == PERIOD)
{
if(source.getLexemeKind(++position) != L_NAME)
{
result = null;
break label0;
}
if((result = getClassType((specialCanonicalName + '.' + source.getLexemeString(position++)).toString())) != null) break label0;
}
result = null;
}
if(!parsed.helpersAllowed && result != null && result.isHelper()) result = null;
parsed.resultType = result;
return position;
}
private int tryParseTypeName(TextSource source, int position, ClassType enclosing, TypeHolder parsed) {
int kind = source.getLexemeKind(position);
if(kind == VOID)
{
parsed.resultType = getPrimitiveType(VOID);
return position + 1;
}
Type result;
if(kind > VOID && kind < VOID + PRIMITIVES_LENGTH && isPrimitiveKind(kind))
{
position++;
result = getPrimitiveType(kind);
} else
{
position = tryParseClassName(source, position, enclosing, parsed);
if((result = parsed.resultType) == null || result.isHelper())
{
parsed.resultType = result;
return position;
}
}
for(int dimCount = 0; dimCount < LIMIT_DIMENSIONS_COUNT && source.getLexemeKind(position) == BRACKET_OPENED && source.getLexemeKind(position + 1) == BRACKET_CLOSED; position += 2, dimCount++)
{
result = acquireArrayType(result);
}
parsed.resultType = result;
return position;
}
private Node appendIncrementCode(Node parent, PrimitiveType argumentType, boolean isUseIncrement) {
Node result;
Code code = parent.parentCode;
switch(argumentType.kind)
{
default:
Constant delta = fldConstantFactory.createByte(isUseIncrement ? 1 : -1).castTo(argumentType);
result = code.createAndAppendNode(parent).setData(-1, argumentType, O_VECT_ADD, argumentType);
code.createAndAppendNode(result).setData(-1, argumentType, LOAD_CONST, delta);
break;
case REAL:
Constant delta = fldConstantFactory.createReal(isUseIncrement ? 1.0 : -1.0);
result = code.createAndAppendNode(parent).setData(-1, argumentType, O_SCAL_ADD, argumentType);
code.createAndAppendNode(result).setData(-1, argumentType, LOAD_CONST, delta);
break;
case CHAR:
Type typeInt = fldTypeInt;
Constant delta = fldConstantFactory.createInt(isUseIncrement ? 1 : -1);
result = code.createAndAppendNode(parent).setData(-1, argumentType, CAST_TO, argumentType, typeInt);
result = code.createAndAppendNode(result).setData(-1, typeInt, O_SCAL_ADD, typeInt);
code.createAndAppendNode(result).setData(-1, typeInt, LOAD_CONST, delta);
}
return result;
}
private TableItem getAdditionalOperand(int operand, Hashtable locals, Object[] constants, int index) {
switch(operand)
{
default:
return null;
case OPERAND_CONSTANT:
Object element = constants[index];
return fldConstantFactory.createFrom(!(element instanceof RecompilableElement) ? element : ((RecompilableElement) element).getItem());
case OPERAND_LOCAL:
return (Local) locals.operator [](index <= 0 ? SPECNAME_THIS : (String) constants[index]);
case OPERAND_GLOBAL:
return ((FieldElement) constants[index]).getItem();
}
}
private ImmediateBuilderItemHolder getItemHolder() {
CompilerParallelWorker threadItemHolder = fldThreadItemHolder;
return threadItemHolder == null ? fldGlobalItemHolder : (ImmediateBuilderItemHolder) threadItemHolder.threadObject();
}
}
final class ImmediateBuilderForBinarySources(Object, CompilerRunnable)
{
private final ImmediateBuilder fldParent;
public (ImmediateBuilder parent) { fldParent = parent; }
public void run(Object target) throws BinarySourceException, IOException {
ClassType enclosing = (ClassType) target;
int length = enclosing.length;
for(ImmediateBuilder parent = fldParent, int index = 0; index < length; index++)
{
Member member = enclosing[index];
if(member instanceof Callable) parent.readCallableBody((Callable) member);
}
}
}
final class ImmediateBuilderForTextSources(Object, CompilerRunnable, CompilerThreadObjectCreator, AVTOOConstants)
{
private final ImmediateBuilder fldParent;
public (ImmediateBuilder parent) { fldParent = parent; }
public void run(Object target) throws TextSourceException {
ClassType enclosing = (ClassType) target;
int length = enclosing.length;
for(ImmediateBuilder parent = fldParent, int index = 0; index < length; index++)
{
Member member = enclosing[index];
if(member instanceof Callable) parent.parseCallableBody((Callable) member);
}
for(int index = 0; index < length; index++)
{
Member member = enclosing[index];
if(member instanceof InstInit) for(InstInit thisConstructor = (InstInit) member, int position = -1; ; )
{
Node constructor = thisConstructor.code.root[0];
if(constructor.instruction != INVOKE_SPECIAL) break;
Callable callable = (Callable) constructor.operand1;
if(!(callable instanceof InstInit) || callable.parentType != enclosing)
{
break;
}
if(position < 0)
{
position = constructor.position;
}
if(callable == member)
{
throw new TextSourceException(String.format(
package.getResourceString("constructor.recursive-invocation"), new Object[] { member }
)) { source = (TextSource) enclosing.source, position = position };
}
thisConstructor = (InstInit) callable;
}
}
}
public ImmediateBuilderItemHolder createThreadObject() { return new ImmediateBuilderItemHolder(); }
}
class ImmediateBuilderItemHolder(Object, OperatorHolder, TypeHolder, PackageHolder)
{
protected boolean fldHelpersAllowed;
protected int fldResultKind;
protected Type fldResultType;
protected Package fldResultPack;
protected Local fldResultWith;
protected TableItem fldResultItem;
public () { }
public int resultKind { read = fldResultKind, write = fldResultKind }
public boolean helpersAllowed { read = fldHelpersAllowed, write = fldHelpersAllowed }
public Type resultType { read = fldResultType, write = setResultType }
public Package resultPack { read = fldResultPack, write = setResultPack }
public Local resultWith { read = fldResultWith, write = fldResultWith }
public TableItem resultItem { read = fldResultItem, write = setResultItem }
protected void setResultType(Type newResultType) {
fldResultType = newResultType;
fldResultPack = null;
fldResultWith = null;
fldResultItem = newResultType;
}
protected void setResultPack(Package newResultPack) {
fldResultType = null;
fldResultPack = newResultPack;
fldResultWith = null;
fldResultItem = newResultPack;
}
protected void setResultItem(TableItem newResultItem) {
fldResultType = !(newResultItem instanceof Type) ? null : (Type) newResultItem;
fldResultPack = !(newResultItem instanceof Package) ? null : (Package) newResultItem;
fldResultItem = newResultItem;
}
}
final class ImmediateBuilderUnaryOperation(Object)
{
private final int fldPosition;
private final int fldOperation;
private final Type fldNewType;
public (int position, int operation) {
fldPosition = position;
fldOperation = operation;
}
public (int position, int operation, Type newType) {
fldPosition = position;
fldOperation = operation;
fldNewType = newType;
}
public int position { read = fldPosition }
public int operation { read = fldOperation }
public Type newType { read = fldNewType }
}