Constant.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Компилятор языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    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"));
        }
    }
}