TextSource.avt

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

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

    Copyright © 2021, 2024 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package ru.malik.elaborarer.avtoo.lang;

import avt.io.*;
import avt.io.charset.*;
import avt.io.extension.*;
import avt.lang.array.*;
import avt.util.*;
import platform.independent.filesystem.*;
import platform.independent.streamformat.*;

public class TextSource(LexemeSequence, CharsetInputAdapter, InputAdapter, Source, Cloneable, Measureable, MutableObjectArray, ObjectArray, AVTOOConstants)
{
    private byte[] fldInputStream;
    private CharDecoder fldDecoder;
    private StringArray fldLines;
    private String fldText;
    private Package fldOwner;
    private final RequiredReflectItemArray fldImportedArray;
    private final ClassTypeArray fldDeclaredArray;
    private final Hashtable fldImportedTable;
    private final Hashtable fldDeclaredTable;
    private final String fldFileName;
    private final String fldOutputPath;
    private final String fldRelativePath;
    private final Library fldParentLibrary;
    private final Programme fldParentProgramme;

    public (Library parentLibrary, String relativePath) {
        if(relativePath == null) relativePath = "";
        int solidusPosition = relativePath.indexOf('/');
        if(solidusPosition < 0) solidusPosition = 0;
        fldImportedArray = new RequiredReflectItemArray();
        fldDeclaredArray = new ClassTypeArray();
        fldImportedTable = new Hashtable();
        fldDeclaredTable = new Hashtable();
        fldFileName = AVTOOService.getObjectName(relativePath);
        fldOutputPath = relativePath.substring(solidusPosition);
        fldRelativePath = relativePath;
        fldParentLibrary = parentLibrary;
        fldParentProgramme = parentLibrary == null ? null : parentLibrary.parentProgramme;
    }

    public void loadFromDataStream(DataInputStream stream, CharDecoder decoder) throws IOException { loadFromInputStream(stream == null ? null : stream.reader, decoder); }

    public void loadFromDataStream(DataInputStream stream, String charsetName) throws IOException { loadFromInputStream(stream == null ? null : stream.reader, Charset.get(charsetName).newDecoder()); }

    public void loadFromInputStream(ByteReader stream, CharDecoder decoder) throws IOException {
        if(stream == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "stream" }));
        }
        LimitedSizeExtension sizeable = (LimitedSizeExtension) stream.getExtension(LimitedSizeExtension.class);
        if(sizeable == null)
        {
            throw new InvalidStreamException(String.format(
                platform.independent.streamformat.package.getResourceString("invalid-stream.input.unsupported-extension"), new Object[] { LimitedSizeExtension.class.simpleName }
            ));
        }
        long size = sizeable.available();
        if(size < 0 || size > Int.MAX_VALUE)
        {
            throw new InvalidStreamException(platform.independent.streamformat.package.getResourceString("invalid-stream.input.size-too-large"));
        }
        int length = (int) size;
        byte[] data = new byte[length];
        int readed = stream.read(data, 0, length);
        data.length = readed >= 0 && readed <= length ? readed : 0;
        fldInputStream = data;
        fldDecoder = decoder;
    }

    public void loadFromInputStream(ByteReader stream, String charsetName) throws IOException { loadFromInputStream(stream, Charset.get(charsetName).newDecoder()); }

    public void loadFromDataStream(DataInputStream stream) throws IOException { loadFromInputStream(stream == null ? null : stream.reader, (CharDecoder) null); }

    public void loadFromInputStream(ByteReader stream) throws IOException { loadFromInputStream(stream, (CharDecoder) null); }

    public void loadFromFileStream() throws IOException {
        Library parentLibrary = fldParentLibrary;
        FileSystem fileSystem;
        String sourcePath;
        if(parentLibrary == null)
        {
            fileSystem = Platform.instance.localFileSystem;
            sourcePath = "/" + fldRelativePath;
        } else
        {
            fileSystem = parentLibrary.fileSystem;
            sourcePath = parentLibrary.directoryPath + fldRelativePath;
        }
        ByteReader stream = fileSystem.openFileForRead(sourcePath);
        try
        {
            loadFromInputStream(stream, (CharDecoder) null);
        } finally
        {
            stream.close();
        }
    }

    public void parseInputStream() throws TextSourceException {
        /* преобразование массива байт в массив символов */
        byte[] source = fldInputStream;
        if(source == null)
        {
            throw new IllegalSourceStateException(package.getResourceString("source.not-loaded"));
        }
        int position = 0;
        int available = source.length;
        CharDecoder decoder = fldDecoder;
        fldInputStream = null;
        fldDecoder = null;
        if(decoder == null)
        {
            /* UTF-кодировка */
            int bom = available >= 3 ? (source[2] & 0xff) << 0o20 | (source[1] & 0xff) << 0o10 | (source[0] & 0xff) : available == 2 ? (source[1] & 0xff) << 0o10 | (source[0] & 0xff) : 0;
            try
            {
                if(bom == 0xbfbbef)
                {
                    position = 3;
                    decoder = Charset.get("UTF-8").newDecoder();
                }
                else if((bom &= 0xffff) == 0xfeff)
                {
                    position = 2;
                    decoder = Charset.get("UTF-16 LE").newDecoder();
                }
                else if(bom == 0xfffe)
                {
                    position = 2;
                    decoder = Charset.get("UTF-16 BE").newDecoder();
                }
                else
                {
                    decoder = Charset.get("UTF-8").newDecoder();
                }
            }
            catch(UnsupportedCharsetNameException exception)
            {
                throw new TextSourceException(exception.message, exception) { source = this };
            }
        }
        /* любая кодировка */
        try
        {
            decoder.errorAction = ErrorAction.ignore;
            char[] text = decoder.decode(source, position, available - position);
            fldLines = new StringArray((fldText = new String(text)).split());
        }
        catch(CharacterDecodingException exception)
        {
            throw new TextSourceException(exception.message, exception) { source = this };
        }
    }

    public boolean isSameSource(Source anot) {
        if(!(anot instanceof TextSource)) return false;
        TextSource src = (TextSource) anot;
        return src.fldOwner == fldOwner && src.fldFileName.equals(fldFileName);
    }

    public boolean contains(ClassType type) {
        if(type == null)
        {
            return false;
        }
        if(Array.indexOf(type, fldDeclaredArray.array, 0, 0) >= 0)
        {
            return true;
        }
        for(Programme programme = fldParentProgramme, RequiredReflectItem[] imported = fldImportedArray.array, int length = imported.length, int index = length; index >= -1; index--)
        {
            RequiredReflectItem item = index >= length ? fldOwner : index < 0 ? programme == null ? null : programme.getLanguagePackage() : imported[index];
            if(item != null && (type == item || type.parentPackage == item)) return true;
        }
        return false;
    }

    public void appendImported(RequiredReflectItem item) {
        if(item == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "item" }));
        }
        fldImportedArray.append(item);
        if(item instanceof ClassType) fldImportedTable[item.specialSimpleName] = item;
    }

    public final boolean isImported(Package pack) { return fldImportedArray.indexOf(pack) >= 0; }

    public final ClassType[] findImplicitlyImportedTypes(String specialSimpleName, ClassType enclosingClass) {
        if(specialSimpleName == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "specialSimpleName" }));
        }
        if(specialSimpleName.isEmpty())
        {
            throw new IllegalArgumentException(package.getResourceString("illegal-argument.empty.item-name"));
        }
        if(enclosingClass == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "enclosingClass" }));
        }
        if(enclosingClass.parentProgramme != parentProgramme)
        {
            throw new IllegalArgumentException(package.getResourceString("type.not-same-programme.source"));
        }
        ClassType[] result = new ClassType[2];
        int rlength = 0;
        ProgrammeItem[] imported = fldImportedArray.array;
        int ilength = imported.length;
        label0:
        {
            /* поиск видимых типов */
            for(int iindex = ilength; iindex-- > 0; )
            {
                ProgrammeItem item = imported[iindex];
                if(item instanceof Package && (item = item.getChildItem(specialSimpleName)) instanceof ClassType && ((ReflectItem) item).isVisibleFrom(enclosingClass))
                {
                    result[rlength++] = (ClassType) item;
                    if(rlength == 2) break label0;
                }
            }
            /* поиск типа без учёта видимости */
            if(rlength == 0) for(int iindex = ilength; iindex-- > 0; )
            {
                ProgrammeItem item = imported[iindex];
                if(item instanceof Package && (item = item.getChildItem(specialSimpleName)) instanceof ClassType)
                {
                    result[rlength++] = (ClassType) item;
                    break label0;
                }
            }
        }
        result.length = rlength;
        return result;
    }

    public final ClassType getImportedType(String specialSimpleName) { return (ClassType) fldImportedTable[specialSimpleName != null ? specialSimpleName : ""]; }

    public final ClassType getDeclaredType(String specialSimpleName) { return (ClassType) fldDeclaredTable[specialSimpleName != null ? specialSimpleName : ""]; }

    public final StringArray contents { read = fldLines }

    public final ClassTypeArray declared { read = fldDeclaredArray }

    public final String relativePath { read = fldRelativePath }

    public final Library parentLibrary { read = fldParentLibrary }

    public final Programme parentProgramme { read = fldParentProgramme }

    public final Package owner { read = fldOwner, write = setOwner }

    public final String text { read = fldText }

    public final StringArray lines { read = fldLines }

    public final RequiredReflectItemArray imported { read = fldImportedArray }

    public final String outputPath { read = fldOutputPath }

    protected void appendDeclared(ClassType declared) {
        if(declared == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "declared" }));
        }
        fldDeclaredArray.append(declared);
        fldDeclaredTable[declared.specialSimpleName] = declared;
    }

    protected void setOwner(Package newOwner) { fldOwner = newOwner; }
}