/*
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Стандартной общественной лицензии 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; break;
}
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; break;
}
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:
{
int value = fldChar;
return new String(
value >= 0x0021 && value <= 0x007f ? new char[] {
'\'',
(char) value,
'\''
} : new char[] {
'\'', '\\', 'u',
Char.toChar((value >> 0x0c) & 0x0f),
Char.toChar((value >> 0x08) & 0x0f),
Char.toChar((value >> 0x04) & 0x0f),
Char.toChar(value & 0x0f),
'\''
}
);
}
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 Type ? ((RequiredReflectItem) value).specialCanonicalName + ".class" :
value instanceof Package ? ((RequiredReflectItem) value).specialCanonicalName + ".package" :
value instanceof String ? (new StringBuilder()).append('\"').append(value).append('\"').toString() :
value.toString()
;
}
}
}
public boolean isNaN() {
switch(fldClassKind)
{
default : return false;
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);
}
}
public boolean isInfinite() {
switch(fldClassKind)
{
default : return false;
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);
}
}
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"));
}
}
}