Constant.avt

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

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

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