/*
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
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; }
}