/*
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package ru.malik.elaborarer.avtoo.lang;
import avt.lang.array.*;
public final class Constant(TableItem, Numeric, Cloneable, Measureable, ObjectArray, TypedItem, AVTOOConstants)
{
private static final int NUMERIC = REAL;
private static final int REFERENCE = REF;
private final int fldClassKind;
private final int fldTypeKind;
private final boolean fldBoolean;
private final char fldChar;
private final long8 fldIntegral;
private final double8 fldFloating;
private final real fldReal;
private final Object fldObject;
private final Type fldType;
package (PrimitiveType type, boolean value): this() {
fldClassKind = Class.BOOLEAN;
fldTypeKind = BOOLEAN;
fldBoolean = value;
fldType = type;
}
package (PrimitiveType type, char value): this() {
fldClassKind = Class.CHAR;
fldTypeKind = NUMERIC;
fldChar = value;
fldIntegral = value;
fldFloating = value;
fldReal = value;
fldType = type;
}
package (PrimitiveType type, long8 value): this() {
switch(type.kind)
{
case BYTE:
fldClassKind = Class.BYTE;
break;
case BYTE2:
fldClassKind = Class.BYTE2;
break;
case BYTE4:
fldClassKind = Class.BYTE4;
break;
case BYTE8:
fldClassKind = Class.BYTE8;
break;
case SHORT:
fldClassKind = Class.SHORT;
break;
case SHORT2:
fldClassKind = Class.SHORT2;
break;
case SHORT4:
fldClassKind = Class.SHORT4;
break;
case SHORT8:
fldClassKind = Class.SHORT8;
break;
case INT:
fldClassKind = Class.INT;
break;
case INT2:
fldClassKind = Class.INT2;
break;
case INT4:
fldClassKind = Class.INT4;
break;
case INT8:
fldClassKind = Class.INT8;
break;
case LONG:
fldClassKind = Class.LONG;
break;
case LONG2:
fldClassKind = Class.LONG2;
break;
case LONG4:
fldClassKind = Class.LONG4;
break;
case LONG8:
fldClassKind = Class.LONG8;
}
fldTypeKind = NUMERIC;
fldChar = (char) (int) (long) value;
fldIntegral = value;
fldFloating = (double8) value;
fldReal = (long) value;
fldType = type;
}
package (PrimitiveType type, double8 value): this() {
switch(type.kind)
{
case FLOAT:
fldClassKind = Class.FLOAT;
break;
case FLOAT2:
fldClassKind = Class.FLOAT2;
break;
case FLOAT4:
fldClassKind = Class.FLOAT4;
break;
case FLOAT8:
fldClassKind = Class.FLOAT8;
break;
case DOUBLE:
fldClassKind = Class.DOUBLE;
break;
case DOUBLE2:
fldClassKind = Class.DOUBLE2;
break;
case DOUBLE4:
fldClassKind = Class.DOUBLE4;
break;
case DOUBLE8:
fldClassKind = Class.DOUBLE8;
}
fldTypeKind = NUMERIC;
fldChar = (char) (int) (double) value;
fldIntegral = (long8) value;
fldFloating = value;
fldReal = (double) value;
fldType = type;
}
package (PrimitiveType type, real value): this() {
fldClassKind = Class.REAL;
fldTypeKind = NUMERIC;
fldChar = (char) (int) value;
fldIntegral = (long) value;
fldFloating = (double) value;
fldReal = value;
fldType = type;
}
package (ReferenceType type, Object value): this() {
fldClassKind = 0;
fldTypeKind = REFERENCE;
fldObject = value;
fldType = type;
}
private (Constant anot): this() {
fldClassKind = anot.fldClassKind;
fldTypeKind = anot.fldTypeKind;
fldBoolean = anot.fldBoolean;
fldChar = anot.fldChar;
fldIntegral = anot.fldIntegral;
fldFloating = anot.fldFloating;
fldReal = anot.fldReal;
fldObject = anot.fldObject;
fldType = anot.fldType;
}
private (): super(null, null, null, -1, -1) { }
public String toString() {
int kind = fldClassKind;
switch(kind)
{
case Class.BOOLEAN:
return fldBoolean ? "true" : "false";
case Class.CHAR:
return new String(new char[] { '\'', fldChar, '\'' });
case Class.BYTE:
return Byte.toString((byte) (long) fldIntegral);
case Class.SHORT:
return Short.toString((short) (long) fldIntegral) + "S";
case Class.INT:
return Int.toString((int) (long) fldIntegral) + "I";
case Class.LONG:
return Long.toString((long) fldIntegral) + "L";
case Class.FLOAT:
return Float.toString((float) (double) fldFloating) + "F";
case Class.DOUBLE:
return Double.toString((double) fldFloating) + "D";
case Class.REAL:
return Real.toString(fldReal);
case Class.BYTE2:
case Class.BYTE4:
case Class.BYTE8:
byte8 value = (byte8) fldIntegral;
int length = 1 << (kind &= 0x03);
Object[] data = new Object[length];
for(int index = length; index-- > 0; ) data[index] = new Byte(value[index]);
return String.format(kind == 1 ? "new byte2 { %0%, %1% }" : kind == 2 ? "new byte4 { %0%, %1%, %2%, %3% }" : "new byte8 { %0%, %1%, %2%, %3%, %4%, %5%, %6%, %7% }", data);
case Class.SHORT2:
case Class.SHORT4:
case Class.SHORT8:
short8 value = (short8) fldIntegral;
int length = 1 << (kind &= 0x03);
Object[] data = new Object[length];
for(int index = length; index-- > 0; ) data[index] = new Short(value[index]);
return String.format(kind == 1 ? "new short2 { %0%, %1% }" : kind == 2 ? "new short4 { %0%, %1%, %2%, %3% }" : "new short8 { %0%, %1%, %2%, %3%, %4%, %5%, %6%, %7% }", data);
case Class.INT2:
case Class.INT4:
case Class.INT8:
int8 value = (int8) fldIntegral;
int length = 1 << (kind &= 0x03);
Object[] data = new Object[length];
for(int index = length; index-- > 0; ) data[index] = new Int(value[index]);
return String.format(kind == 1 ? "new int2 { %0%, %1% }" : kind == 2 ? "new int4 { %0%, %1%, %2%, %3% }" : "new int8 { %0%, %1%, %2%, %3%, %4%, %5%, %6%, %7% }", data);
case Class.LONG2:
case Class.LONG4:
case Class.LONG8:
long8 value = fldIntegral;
int length = 1 << (kind &= 0x03);
Object[] data = new Object[length];
for(int index = length; index-- > 0; ) data[index] = new Long(value[index]);
return String.format(kind == 1 ? "new long2 { %0%, %1% }" : kind == 2 ? "new long4 { %0%, %1%, %2%, %3% }" : "new long8 { %0%, %1%, %2%, %3%, %4%, %5%, %6%, %7% }", data);
case Class.FLOAT2:
case Class.FLOAT4:
case Class.FLOAT8:
float8 value = (float8) fldFloating;
int length = 1 << (kind &= 0x03);
Object[] data = new Object[length];
for(int index = length; index-- > 0; ) data[index] = new Float(value[index]);
return String.format(kind == 1 ? "new float2 { %0%, %1% }" : kind == 2 ? "new float4 { %0%, %1%, %2%, %3% }" : "new float8 { %0%, %1%, %2%, %3%, %4%, %5%, %6%, %7% }", data);
case Class.DOUBLE2:
case Class.DOUBLE4:
case Class.DOUBLE8:
double8 value = fldFloating;
int length = 1 << (kind &= 0x03);
Object[] data = new Object[length];
for(int index = length; index-- > 0; ) data[index] = new Double(value[index]);
return String.format(kind == 1 ? "new double2 { %0%, %1% }" : kind == 2 ? "new double4 { %0%, %1%, %2%, %3% }" : "new double8 { %0%, %1%, %2%, %3%, %4%, %5%, %6%, %7% }", data);
default:
Object value = fldObject;
return
value == null ? "null" :
value instanceof String ? (new StringBuilder() + '\"' + value + '\"').toString() :
value instanceof Package ? ((Type) value).specialCanonicalName + ".package" :
value instanceof Type ? ((Type) value).specialCanonicalName + ".class" :
value.toString()
;
}
}
public boolean isNaN() {
switch(fldClassKind)
{
case Class.FLOAT:
case Class.DOUBLE:
return Double.isNaN((double) fldFloating);
case Class.FLOAT2:
case Class.DOUBLE2:
return Double2.isNaN((double2) fldFloating);
case Class.FLOAT4:
case Class.DOUBLE4:
return Double4.isNaN((double4) fldFloating);
case Class.FLOAT8:
case Class.DOUBLE8:
return Double8.isNaN(fldFloating);
default:
return false;
}
}
public boolean isInfinite() {
switch(fldClassKind)
{
case Class.FLOAT:
case Class.DOUBLE:
return Double.isInfinite((double) fldFloating);
case Class.FLOAT2:
case Class.DOUBLE2:
return Double2.isInfinite((double2) fldFloating);
case Class.FLOAT4:
case Class.DOUBLE4:
return Double4.isInfinite((double4) fldFloating);
case Class.FLOAT8:
case Class.DOUBLE8:
return Double8.isInfinite(fldFloating);
default:
return false;
}
}
public char asChar() {
checkTypeKind(NUMERIC);
return fldChar;
}
public byte8 asByte8() {
checkTypeKind(NUMERIC);
return (byte8) fldIntegral;
}
public short8 asShort8() {
checkTypeKind(NUMERIC);
return (short8) fldIntegral;
}
public int8 asInt8() {
checkTypeKind(NUMERIC);
return (int8) fldIntegral;
}
public long8 asLong8() {
checkTypeKind(NUMERIC);
return fldIntegral;
}
public float8 asFloat8() {
checkTypeKind(NUMERIC);
return (float8) fldFloating;
}
public double8 asDouble8() {
checkTypeKind(NUMERIC);
return fldFloating;
}
public real asReal() {
checkTypeKind(NUMERIC);
return fldReal;
}
public Constant clone() { return new Constant(this); }
public boolean isNull() { return fldTypeKind == REFERENCE && fldObject == null; }
public boolean isClass() { return fldTypeKind == REFERENCE && fldObject instanceof Type; }
public boolean isString() { return fldTypeKind == REFERENCE && fldObject instanceof String; }
public boolean isPackage() { return fldTypeKind == REFERENCE && fldObject instanceof Package; }
public boolean isBoolean() { return fldTypeKind == BOOLEAN; }
public boolean isNumeric() { return fldTypeKind == NUMERIC; }
public boolean isReference() { return fldTypeKind == REFERENCE; }
public boolean isReflective() { return fldTypeKind == REFERENCE && fldObject instanceof RequiredReflectItem; }
public boolean isDefaultValue() {
switch(fldTypeKind)
{
case BOOLEAN:
return !fldBoolean;
case NUMERIC:
int kind = fldClassKind;
return
kind == Class.CHAR ? fldChar == '\0' :
kind >= Class.BYTE && kind <= Class.LONG8 ? fldIntegral == 0 :
kind >= Class.FLOAT && kind <= Class.FLOAT8 || kind >= Class.DOUBLE && kind <= Class.DOUBLE8 ? Double8.toLong8Bits(fldFloating) == 0 :
Real.toLong2Bits(fldReal) == 0
;
default:
return fldObject == null;
}
}
public boolean asBoolean() {
checkTypeKind(BOOLEAN);
return fldBoolean;
}
public Object asObject() {
checkTypeKind(REFERENCE);
return fldObject;
}
public Constant castTo(Type type) {
if(type == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "type" }));
}
if(type instanceof PrimitiveType)
{
PrimitiveType prim = (PrimitiveType) type;
int kind = prim.kind;
if(kind == BOOLEAN)
{
checkTypeKind(BOOLEAN);
}
else if(kind > BOOLEAN)
{
checkTypeKind(NUMERIC);
}
if(type == fldType)
{
return this;
}
switch(kind)
{
case BOOLEAN:
return new Constant(prim, fldBoolean);
case CHAR:
return new Constant(prim, fldChar);
case BYTE:
return new Constant(prim, (long8) (byte) fldIntegral);
case BYTE2:
return new Constant(prim, (long8) (byte2) fldIntegral);
case BYTE4:
return new Constant(prim, (long8) (byte4) fldIntegral);
case BYTE8:
return new Constant(prim, (long8) (byte8) fldIntegral);
case SHORT:
return new Constant(prim, (long8) (short) fldIntegral);
case SHORT2:
return new Constant(prim, (long8) (short2) fldIntegral);
case SHORT4:
return new Constant(prim, (long8) (short4) fldIntegral);
case SHORT8:
return new Constant(prim, (long8) (short8) fldIntegral);
case INT:
return new Constant(prim, (long8) (int) fldIntegral);
case INT2:
return new Constant(prim, (long8) (int2) fldIntegral);
case INT4:
return new Constant(prim, (long8) (int4) fldIntegral);
case INT8:
return new Constant(prim, (long8) (int8) fldIntegral);
case LONG:
return new Constant(prim, (long8) (long) fldIntegral);
case LONG2:
return new Constant(prim, (long8) (long2) fldIntegral);
case LONG4:
return new Constant(prim, (long8) (long4) fldIntegral);
case LONG8:
return new Constant(prim, fldIntegral);
case FLOAT:
return new Constant(prim, (double8) (float) fldFloating);
case FLOAT2:
return new Constant(prim, (double8) (float2) fldFloating);
case FLOAT4:
return new Constant(prim, (double8) (float4) fldFloating);
case FLOAT8:
return new Constant(prim, (double8) (float8) fldFloating);
case DOUBLE:
return new Constant(prim, (double8) (double) fldFloating);
case DOUBLE2:
return new Constant(prim, (double8) (double2) fldFloating);
case DOUBLE4:
return new Constant(prim, (double8) (double4) fldFloating);
case DOUBLE8:
return new Constant(prim, fldFloating);
case REAL:
return new Constant(prim, fldReal);
}
}
else if(type instanceof ClassType)
{
checkTypeKind(REFERENCE);
if(type == fldType) return this;
if(type.isAssignableFrom(fldType)) return new Constant((ClassType) type, fldObject);
}
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "type" }));
}
public int kind { read = fldClassKind }
public Type type { read = fldType }
protected String composeRecompilableName() { return null; }
protected String composeFasmSimpleName() { return null; }
private void checkTypeKind(int kind) {
if(fldTypeKind != kind)
{
throw new IllegalConstantTypeException(package.getResourceString("illegal-type.constant"));
}
}
}