/*
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package ru.malik.elaborarer.avtoo.lang;
import avt.io.*;
import avt.util.*;
import platform.independent.filesystem.*;
import platform.independent.streamformat.*;
public abstract class Programme(Object, AVTOOConstants)
{
private static int comparisonOrder(Type type) { return type instanceof ArrayType ? 3 : type instanceof ClassType ? 2 : type instanceof PrimitiveType ? 1 : 0; }
private boolean fldConstantFactoryIsUnlocked;
private Package fldLanguagePackage;
private Package fldSystemPackage;
private final int fldPointerSize;
private final PrimitiveType[] fldPrimitives;
private final ClassTypeArray fldClassesArray;
private final ArrayTypeArray fldArraysArray;
private final TypeArray fldTypesArray;
private final PackageArray fldPackagesArray;
private final LibraryArray fldLibrariesArray;
private final NullType fldNullType;
private final Hashtable fldTypesTable;
private final Hashtable fldPackagesTable;
private final Hashtable fldLibrariesTable;
private final ConstantFactory fldConstantFactory;
protected (int pointerSize) {
fldPointerSize = pointerSize == BITS32 ? BITS32 : BITS64;
fldPrimitives = new PrimitiveType[PRIMITIVES_LENGTH];
fldClassesArray = new ClassTypeArray();
fldArraysArray = new ArrayTypeArray();
fldTypesArray = new TypeArray();
fldPackagesArray = new PackageArray();
fldLibrariesArray = new LibraryArray();
fldNullType = new NullType();
fldTypesTable = new Hashtable();
fldPackagesTable = new Hashtable();
fldLibrariesTable = new Hashtable();
fldConstantFactory = new ConstantFactory();
}
public abstract void compile() throws IOException, CompilerException;
public Library createLibrary(FileSystem fileSystem, String directoryPath, boolean application) {
Library result = newLibrary(fileSystem, directoryPath, application);
if(result == null) result = new Library(this, fileSystem, directoryPath, application);
appendLibrary(result);
return result;
}
public final boolean isConstantFactoryUnlocked() { return fldConstantFactoryIsUnlocked; }
public final ConstantFactory getConstantFactory() {
if(!fldConstantFactoryIsUnlocked)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.can-not-create.constants"));
}
return fldConstantFactory;
}
public final Library getLibrary(FileSystem fileSystem, String directoryPath) { return (Library) fldLibrariesTable[new ProgrammeLibraryKey(fileSystem, directoryPath)]; }
public final Package getPackage(String specialCanonicalName) { return (Package) fldPackagesTable[specialCanonicalName != null ? specialCanonicalName : ""]; }
public final Package getPackage(String specialCanonicalName, boolean ignoreCase) {
if(specialCanonicalName == null)
{
specialCanonicalName = "";
}
if(!ignoreCase)
{
return (Package) fldPackagesTable[specialCanonicalName];
}
for(Package[] packages = fldPackagesArray.array, int index = packages.length; index-- > 0; )
{
Package pack = packages[index];
if(specialCanonicalName.equalsIgnoreCase(pack.specialCanonicalName)) return pack;
}
return null;
}
public final Package getSystemPackage() { return fldSystemPackage; }
public final Package getLanguagePackage() { return fldLanguagePackage; }
public final Type getType(String specialCanonicalName) {
return TYPENAME_NULL.equals(specialCanonicalName) ? fldNullType : (Type) fldTypesTable[specialCanonicalName != null ? specialCanonicalName : ""];
}
public final NullType getNullType() { return fldNullType; }
public final PrimitiveType getPrimitiveType(int kind) { return kind < VOID || kind >= VOID + PRIMITIVES_LENGTH ? null : fldPrimitives[kind - VOID]; }
public final ClassType getClassType(String specialCanonicalName) {
Object type = fldTypesTable[specialCanonicalName != null ? specialCanonicalName : ""];
return !(type instanceof ClassType) ? null : (ClassType) type;
}
public final ArrayType getArrayType(Type componentType) {
if(componentType == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "componentType" }));
}
if(componentType.isVoid() || componentType.isNull())
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.illegal"));
}
if(componentType.parentProgramme != this)
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.not-same-programme"));
}
if((!(componentType instanceof ArrayType) ? 0 : ((ArrayType) componentType).dimensionsCount) > LIMIT_DIMENSIONS_COUNT - 1)
{
throw new IllegalArrayDimensionsCountException(package.getResourceString("array.dimensions-count"));
}
Object type = fldTypesTable[componentType.specialCanonicalName + "[]"];
return !(type instanceof ArrayType) ? null : (ArrayType) type;
}
public final ArrayType getArrayType(Type componentType, int dimensionsCount) {
if(componentType == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "componentType" }));
}
if(componentType.isVoid() || componentType.isNull())
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.illegal"));
}
if(componentType.parentProgramme != this)
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.not-same-programme"));
}
if(dimensionsCount < 1 || dimensionsCount > (!(componentType instanceof ArrayType) ? LIMIT_DIMENSIONS_COUNT : LIMIT_DIMENSIONS_COUNT - ((ArrayType) componentType).dimensionsCount))
{
throw new IllegalArrayDimensionsCountException(package.getResourceString("array.dimensions-count"));
}
StringBuilder specialCanonicalName = new StringBuilder(450) + componentType.specialCanonicalName;
do specialCanonicalName + "[]"; while(--dimensionsCount > 0);
Object type = fldTypesTable[specialCanonicalName.toString()];
return !(type instanceof ArrayType) ? null : (ArrayType) type;
}
public final ArrayType acquireArrayType(Type componentType) {
if(componentType == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "componentType" }));
}
if(componentType.isVoid() || componentType.isNull())
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.illegal"));
}
if(componentType.parentProgramme != this)
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.not-same-programme"));
}
if((!(componentType instanceof ArrayType) ? 0 : ((ArrayType) componentType).dimensionsCount) > LIMIT_DIMENSIONS_COUNT - 1)
{
throw new IllegalArrayDimensionsCountException(package.getResourceString("array.dimensions-count"));
}
Type result = null;
synchronized(fldPrimitives)
{
if((result = (Type) fldTypesTable[componentType.specialCanonicalName + "[]"]) == null) result = createArrayType(componentType);
}
if(!(result instanceof ArrayType))
{
throw new IllegalProgrammeStateException(String.format(package.getResourceString("type.not-a-array"), new Object[] { result.specialCanonicalName }));
}
return (ArrayType) result;
}
public final ArrayType acquireArrayType(Type componentType, int dimensionsCount) {
if(componentType == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "componentType" }));
}
if(componentType.isVoid() || componentType.isNull())
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.illegal"));
}
if(componentType.parentProgramme != this)
{
throw new IllegalArgumentException(package.getResourceString("array.components-type.not-same-programme"));
}
if(dimensionsCount < 1 || dimensionsCount > (!(componentType instanceof ArrayType) ? LIMIT_DIMENSIONS_COUNT : LIMIT_DIMENSIONS_COUNT - ((ArrayType) componentType).dimensionsCount))
{
throw new IllegalArrayDimensionsCountException(package.getResourceString("array.dimensions-count"));
}
Type result = null;
synchronized(fldPrimitives)
{
Hashtable table = fldTypesTable;
StringBuilder specialCanonicalName = new StringBuilder(450) + componentType.specialCanonicalName;
do
{
if((result = (Type) table[(specialCanonicalName + "[]").toString()]) == null) result = createArrayType(componentType);
componentType = result;
} while(--dimensionsCount > 0);
}
if(!(result instanceof ArrayType))
{
throw new IllegalProgrammeStateException(String.format(package.getResourceString("type.not-a-array"), new Object[] { result.specialCanonicalName }));
}
return (ArrayType) result;
}
public final int pointerSize { read = fldPointerSize }
public final LibraryArray libraries { read = fldLibrariesArray }
public final PackageArray packages { read = fldPackagesArray }
public final TypeArray types { read = fldTypesArray }
public final ArrayTypeArray arrays { read = fldArraysArray }
public final ClassTypeArray classes { read = fldClassesArray }
protected abstract void prefetchSupertypesForPrimitiveArray(ArrayType array);
protected abstract void prefetchSupertypesForObjectArray(ArrayType array);
protected abstract void prefetchSupertypesForReferenceArray(ArrayType array);
protected abstract void createMembersForPrimitiveArray(ArrayType array);
protected abstract void createMembersForObjectArray(ArrayType array);
protected void appendLibrary(Library item) {
if(item == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "item" }));
}
if(item.parentProgramme != this)
{
throw new IllegalArgumentException(package.getResourceString("adding-library.not-owned-by-programme"));
}
LibraryArray list = fldLibrariesArray;
if(list.indexOf(item) >= 0)
{
throw new IllegalProgrammeStateException(package.getResourceString("adding-library.already-added"));
}
list.append(item);
fldLibrariesTable.operator []=(new ProgrammeLibraryKey(item), item);
}
protected void appendPackage(Package item) {
if(item == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "item" }));
}
if(item.parentProgramme != this)
{
throw new IllegalArgumentException(package.getResourceString("adding-package.not-owned-by-programme"));
}
PackageArray list = fldPackagesArray;
if(list.indexOf(item) >= 0)
{
throw new IllegalProgrammeStateException(package.getResourceString("adding-package.already-added"));
}
DataHolder key = item.specialCanonicalName;
list.append(item);
fldPackagesTable[key] = item;
if(key.isEmpty()) fldSystemPackage = item;
if(key.equals(PACKNAME_LANG)) fldLanguagePackage = item;
}
protected void appendType(Type item) {
if(item == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "item" }));
}
if(item.parentProgramme != this)
{
throw new IllegalArgumentException(package.getResourceString("adding-type.not-owned-by-programme"));
}
TypeArray list = fldTypesArray;
if(list.indexOf(item) >= 0)
{
throw new IllegalProgrammeStateException(package.getResourceString("adding-type.already.added"));
}
list.append(item);
fldTypesTable[item.specialCanonicalName] = item;
if(item instanceof ArrayType)
{
fldArraysArray.append((ArrayType) item);
return;
}
if(item instanceof ClassType)
{
fldClassesArray.append((ClassType) item);
return;
}
if(item instanceof PrimitiveType)
{
PrimitiveType primitive = (PrimitiveType) item;
fldPrimitives[primitive.kind - VOID] = primitive;
}
}
protected int compareTypes(Type type0, Type type1) {
/* type0 - type1 */
/* type0 > type1 ? 1 */
/* type0 < type1 ? -1 */
int order0 = comparisonOrder(type0);
int order1 = comparisonOrder(type1);
if(order0 != order1)
{
return order0 - order1;
}
switch(order0)
{
case 1:
return type0.kind - type1.kind;
case 2:
boolean isHelper0 = type0.isHelper();
boolean isHelper1 = type1.isHelper();
return
type0 == type1 || isHelper0 && isHelper1 ? Comparable.EQUALS :
isHelper0 ? 1 :
isHelper1 ? -1 :
type0.isAssignableFrom(type1) ? -1 :
type1.isAssignableFrom(type0) ? 1 :
Comparable.INDEFINITE
;
case 3:
ArrayType array0 = (ArrayType) type0;
ArrayType array1 = (ArrayType) type1;
if(array0.isSuperclass(array1)) return 1;
if(array1.isSuperclass(array0)) return -1;
Type component0 = array0.componentType;
Type component1 = array1.componentType;
order0 = comparisonOrder(component0);
order1 = comparisonOrder(component1);
return
order0 != order1 ? order0 - order1 :
order0 == 1 ? component0.kind - component1.kind :
array0.dimensionsCount - array1.dimensionsCount
;
}
return Comparable.INDEFINITE;
}
protected String[] essentialTypesNames() {
return new String[] {
PACKNAME_LANG + "." + TYPENAME_CLASS,
PACKNAME_LANG + "." + TYPENAME_OBJECT,
PACKNAME_LANG + "." + TYPENAME_STRING,
PACKNAME_LANG + "." + TYPENAME_STRUCT,
PACKNAME_LANG + "." + TYPENAME_PACKAGE,
PACKNAME_LANG + "." + TYPENAME_THROWABLE
};
}
protected Local createLocal(boolean isFinal, Type type, String specialSimpleName, Constant value, Source source, int declarationPosition) {
Local result = newLocal(isFinal, type, specialSimpleName, value, source, declarationPosition);
if(result == null) result = new Local(isFinal, type, specialSimpleName, value, source, declarationPosition);
return result;
}
protected Library newLibrary(FileSystem fileSystem, String directoryPath, boolean application) { return null; }
protected Source newSource(Library parentLibrary, String relativePath, String type) { return null; }
protected Package newPackage(Library parentLibrary, int visibility, String specialCanonicalName, Source source, int declarationPosition, int documentationPosition) { return null; }
protected ClassType newClassType(Package parentPackage, int attributes, String specialSimpleName, Source source, int declarationPosition, int documentationPosition, String outputPath) {
return null;
}
protected ArrayType newArrayType(Type componentType) { return null; }
protected Union newNestedUnion(AllocatableFactory parentItem, int declarationPosition, int documentationPosition) { return null; }
protected Struct newNestedStruct(AllocatableFactory parentItem, int declarationPosition, int documentationPosition) { return null; }
protected Field newStructField(AllocatableFactory parentItem, Type type, int capacity, String specialSimpleName, int declarationPosition, int documentationPosition) { return null; }
protected Field newStructField(ClassType parentType, int structOffset, Type type, int capacity, String specialSimpleName, int declarationPosition, int documentationPosition) { return null; }
protected Field newClassField(ClassType parentType, int attributes, Type type, String specialSimpleName, int declarationPosition, int documentationPosition) { return null; }
protected ClassInit newStaticBlock(ClassType parentType, int attributes, int declarationPosition, int documentationPosition) { return null; }
protected InstInit newConstructor(ClassType parentType, int attributes, Local[] arguments, int declarationPosition, int documentationPosition) { return null; }
protected Method newMethod(ClassType parentType, int attributes, Type type, String specialSimpleName, Local[] arguments, int declarationPosition, int documentationPosition) { return null; }
protected Operator newOperator(ClassType parentType, int attributes, Type type, int kind, Local[] arguments, int declarationPosition, int documentationPosition) { return null; }
protected Property newProperty(ClassType parentType, int attributes, Type type, String specialSimpleName, int declarationPosition, int documentationPosition) { return null; }
protected Local newLocal(boolean isFinal, Type type, String specialSimpleName, Constant value, Source source, int declarationPosition) { return null; }
protected Code newCode(Callable parentCallable) { return null; }
protected Node newNode(Code parentCode) { return null; }
protected final void sortTypes() {
Type[] types = fldTypesArray.array;
int length = types.length;
int limit = length - 1;
for(int tpi = 0; tpi < limit; tpi++) for(Type type0 = types[tpi], int tpj = tpi + 1; tpj < length; tpj++)
{
Type type1 = types[tpj];
if(compareTypes(type0, type1) > 0)
{
types[tpj] = type0;
types[tpj = tpi] = type0 = type1;
}
}
}
protected final void initSubtypes() {
initSubtypes(fldClassesArray.array);
initSubtypes(fldArraysArray.array);
}
protected final void createArrayTypes() {
ArrayTypeArray list = fldArraysArray;
if(list.length > 0)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.already-created.main-arrays-types"));
}
Package packageSystem = fldSystemPackage;
if(packageSystem == null)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.not-created.system-package"));
}
Package packageLanguage = fldLanguagePackage;
if(packageLanguage == null)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.not-created.language-package"));
}
ClassType classObject = getClassType(PACKNAME_LANG + "." + TYPENAME_OBJECT);
if(classObject == null)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.not-created.object-type"));
}
PrimitiveType[] primitives = fldPrimitives;
for(int kind = BOOLEAN; kind < VOID + PRIMITIVES_LENGTH; kind++) if(isPrimitiveKind(kind) && primitives[kind - VOID] == null)
{
throw new IllegalProgrammeStateException(String.format(
package.getResourceString("programme.not-created.primitive-type"), new Object[] { PrimitiveType.kindToSpecialSimpleName(kind) }
));
}
/* разблокировка возможности создания констант */
if(getClassType(PACKNAME_LANG + "." + TYPENAME_STRING) == null)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.not-created.string-type"));
}
if(getClassType(PACKNAME_LANG + "." + TYPENAME_CLASS) == null)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.not-created.class-type"));
}
if(getClassType(PACKNAME_LANG + "." + TYPENAME_PACKAGE) == null)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.not-created.package-type"));
}
fldConstantFactory.loadDataFrom(this);
fldConstantFactoryIsUnlocked = true;
/* создание массивов */
for(int kind = BOOLEAN; kind < VOID + PRIMITIVES_LENGTH; kind++) if(isPrimitiveKind(kind))
{
PrimitiveType primitive = primitives[kind - VOID];
ArrayType array = newArrayType(primitive);
if(array == null) array = new ArrayType(primitive);
packageSystem.appendChildItem(array);
appendType(array);
array.makeCompilable();
}
{
ArrayType array = newArrayType(classObject);
if(array == null) array = new ArrayType(classObject);
packageLanguage.appendChildItem(array);
appendType(array);
array.makeCompilable();
}
/* определение супертипов массивов */
for(ArrayType[] arrays = list.array, int length = arrays.length, int index = 0; index < length; index++)
{
ArrayType array = arrays[index];
if(array.componentType.getClass() == PrimitiveType.class)
{
prefetchSupertypesForPrimitiveArray(array);
continue;
}
prefetchSupertypesForObjectArray(array);
}
}
protected final void createPrimitiveTypes() {
Package systemPackage = fldSystemPackage;
if(systemPackage == null)
{
throw new IllegalProgrammeStateException(package.getResourceString("programme.not-created.system-package"));
}
PrimitiveType[] primitives = fldPrimitives;
for(int kind = VOID; kind < VOID + PRIMITIVES_LENGTH; kind++) if(isPrimitiveKind(kind) && primitives[kind - VOID] != null)
{
throw new IllegalProgrammeStateException(String.format(
package.getResourceString("programme.already-created.primitive-type"), new Object[] { PrimitiveType.kindToSpecialSimpleName(kind) }
));
}
/* создание примитивов */
for(int kind = VOID; kind < VOID + PRIMITIVES_LENGTH; kind++) if(isPrimitiveKind(kind))
{
PrimitiveType primitive = new PrimitiveType(systemPackage, kind);
systemPackage.appendChildItem(primitive);
appendType(primitive);
}
}
protected final void createMembersForArrayTypes() {
for(ClassType objectType = getClassType(PACKNAME_LANG + "." + TYPENAME_OBJECT), ArrayType[] arrays = fldArraysArray.array, int length = arrays.length, int index = 0; index < length; index++)
{
ArrayType array = arrays[index];
Type component = array.componentType;
if(component.getClass() == PrimitiveType.class)
{
createMembersForPrimitiveArray(array);
continue;
}
if(component == objectType)
{
createMembersForObjectArray(array);
continue;
}
break;
}
}
protected final void checkEssentialTypesPresence() throws CompilerException {
for(String[] names = essentialTypesNames(), int length = names == null ? 0 : names.length, int index = 0; index < length; index++)
{
String name = names[index];
if(getType(name) == null)
{
throw new CompilerException(String.format(package.getResourceString("essential-type.not-found"), new Object[] { name }));
}
}
}
private void initSubtypes(ClassType[] classes) {
for(int length = classes.length, int index = 0; index < length; index++) classes[index].initSubtypes();
}
private ArrayType createArrayType(Type componentType) {
ArrayType result = newArrayType(componentType);
if(result == null) result = new ArrayType(componentType);
componentType.parentPackage.appendChildItem(result);
appendType(result);
prefetchSupertypesForReferenceArray(result);
result.appendImpliedSuperservices();
return result;
}
}
final class ProgrammeLibraryKey(Object)
{
private final int fldHashCode;
private final long fldHashCodeAsLong;
private final long2 fldHashCodeAsLong2;
private final long4 fldHashCodeAsLong4;
private final String fldDirectoryPath;
private final FileSystem fldFileSystem;
public (Library library): this(library.fileSystem, library.directoryPath) { }
public (FileSystem fileSystem, String directoryPath) {
if(fileSystem == null) fileSystem = Platform.instance.localFileSystem;
if(directoryPath == null || directoryPath.isEmpty()) directoryPath = "/";
long2 fileSystemHash = fileSystem.hashCodeAsLong2();
long2 directoryPathHash = directoryPath.hashCodeAsLong2();
fldHashCode = fileSystem.hashCode() ^ directoryPath.hashCode();
fldHashCodeAsLong = fileSystem.hashCodeAsLong() ^ directoryPath.hashCodeAsLong();
fldHashCodeAsLong2 = fileSystemHash ^ directoryPathHash;
fldHashCodeAsLong4 = fileSystemHash + directoryPathHash * Math.J;
fldDirectoryPath = directoryPath;
fldFileSystem = fileSystem;
}
public boolean equals(Object anot) {
if(anot == this) return true;
if(!(anot instanceof ProgrammeLibraryKey)) return false;
ProgrammeLibraryKey lkey = (ProgrammeLibraryKey) anot;
return lkey.fldFileSystem == fldFileSystem && lkey.fldDirectoryPath.equals(fldDirectoryPath);
}
public int hashCode() { return fldHashCode; }
public long hashCodeAsLong() { return fldHashCodeAsLong; }
public long2 hashCodeAsLong2() { return fldHashCodeAsLong2; }
public long4 hashCodeAsLong4() { return fldHashCodeAsLong4; }
}