Code.avt

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

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

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

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

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

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

package ru.malik.elaborarer.avtoo.lang;

import avt.lang.array.*;
import platform.independent.streamformat.*;

public class Code(CallableItem, DataHolder, Cloneable, Measureable, ObjectArray)
{
    private static LexemeSequence getLexemeSequence(TableItem item) {
        if(item == null) return null;
        Object src = item.source;
        return !(src instanceof LexemeSequence) ? null : (LexemeSequence) src;
    }

    private int fldWithLocalIndex;
    private int fldMonitorLocalIndex;
    private Node[] fldInstructionsNodes;
    private Node fldRoot;
    private final NodeArray fldNodesArray;
    private final LocalArray fldLocalsArray;
    private final CodeLineIndexArray fldDebugLineIndicesArray;
    private final Callable fldParentCallable;
    private final Programme fldParentProgramme;

    public (Callable parentCallable): super(getLexemeSequence(parentCallable)) {
        (fldInstructionsNodes = new Node[0x0f]).length = 0;
        fldNodesArray = new NodeArray();
        fldLocalsArray = new LocalArray();
        fldDebugLineIndicesArray = new CodeLineIndexArray();
        fldParentCallable = parentCallable;
        fldParentProgramme = parentCallable == null ? null : parentCallable.parentProgramme;
    }

    public void replaceJumpNode(Node oldJumpNode, Node newJumpNode) {
        if(oldJumpNode == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "oldJumpNode" }));
        }
        if(newJumpNode == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "newJumpNode" }));
        }
        for(Node[] nodes = fldInstructionsNodes, int index = nodes.length; index-- > 0; ) nodes[index].replaceJumpNode(oldJumpNode, newJumpNode);
    }

    public void assignOrder(Node node, int order) {
        if(node == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "node" }));
        }
        if(fldNodesArray.indexOf(node) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.not-owned-by-code"));
        }
        Node[] nodes = fldInstructionsNodes;
        int length = nodes.length;
        int index = length <= 0 ? -1 : Array.indexOf(node, nodes, 0, length);
        if(order < 0)
        {
            order = 0;
        }
        if(order > length)
        {
            order = length;
        }
        if(index < 0)
        {
            if(length == nodes.capacity)
            {
                if(length == Int.MAX_VALUE)
                {
                    throw new BufferTooLargeError(avt.lang.package.getResourceString("!error.buffer-too-large"));
                }
                Array.copy(nodes, 0, fldInstructionsNodes = nodes = new Node[length << 1 | 1], 0, length);
            }
            nodes.length = length + 1;
            Array.copy(nodes, order, nodes, order + 1, length - order);
        }
        else if(order <= index)
        {
            Array.copy(nodes, order, nodes, order + 1, index - order);
        }
        else
        {
            Array.copy(nodes, index + 1, nodes, index, --order - index);
        }
        nodes[order] = node;
    }

    public void clearOrder(Node node) {
        if(node == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "node" }));
        }
        if(fldNodesArray.indexOf(node) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.not-owned-by-code"));
        }
        Node[] nodes = fldInstructionsNodes;
        int length = nodes.length;
        int index = length <= 0 ? -1 : Array.indexOf(node, nodes, 0, length);
        if(index >= 0)
        {
            Array.copy(nodes, index + 1, nodes, index, --length - index);
            nodes[length] = null;
            nodes.length = length;
        }
    }

    public void removeChilds(Node node) {
        if(node == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "node" }));
        }
        NodeArray nodes = fldNodesArray;
        if(nodes.indexOf(node) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.not-owned-by-code"));
        }
        NodeArray.removeChildsFrom(fldInstructionsNodes, node);
        nodes.removeChilds(node);
        node.deleteChilds();
    }

    public void removeNode(Node node) {
        if(node == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "node" }));
        }
        NodeArray nodes = fldNodesArray;
        if(nodes.indexOf(node) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.not-owned-by-code"));
        }
        Node owning = node.parentNode;
        if(owning == null)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.is-root-node"));
        }
        if(node.isEmpty())
        {
            NodeArray.removeItemFrom(fldInstructionsNodes, node);
            nodes.remove(node);
        } else
        {
            NodeArray.removeNodeFrom(fldInstructionsNodes, node);
            nodes.removeNode(node);
        }
        owning.deleteChild(node.index);
    }

    public void moveNode(Node node, int index) {
        if(node == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "node" }));
        }
        if(fldNodesArray.indexOf(node) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.not-owned-by-code"));
        }
        Node owning = node.parentNode;
        if(owning == null)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.is-root-node"));
        }
        owning.moveChild(node.index, index);
    }

    public void moveNode(Node node, Node parent, int index) {
        if(node == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "node" }));
        }
        NodeArray nodes = fldNodesArray;
        if(nodes.indexOf(node) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.not-owned-by-code"));
        }
        Node owning = node.parentNode;
        if(owning == null)
        {
            throw new IllegalArgumentException(package.getResourceString("specified-node.is-root-node"));
        }
        if(parent == null)
        {
            parent = owning;
        }
        if(nodes.indexOf(parent) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("parent-node.not-owned-by-code"));
        }
        if(parent == node || parent.isParent(node))
        {
            throw new IllegalArgumentException(package.getResourceString("parent-node.illegal"));
        }
        if(owning == parent)
        {
            owning.moveChild(node.index, index);
            return;
        }
        owning.deleteChild(node.index);
        parent.insertChild(index, node);
    }

    public int createDebugIndex(int lineIndex) { return fldDebugLineIndicesArray.append(lineIndex); }

    public Local createWithLocal(ClassType type, Constant value) { return createLocal(true, type, "with." + Int.toString(fldWithLocalIndex++), value, -1); }

    public Local createMonitorLocal(ClassType type, Constant value) { return createLocal(true, type, "monitor." + Int.toString(fldMonitorLocalIndex++), value, -1); }

    public Local createLocal(boolean isFinal, Type type, String specialSimpleName, Constant value, int declarationPosition) {
        if(type == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "type" }));
        }
        if(type.isVoid() || type.isNull())
        {
            throw new IllegalArgumentException(package.getResourceString("type.not-suitable.variable"));
        }
        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"));
        }
        Programme programme = fldParentProgramme;
        LexemeSequence sequence = sequence;
        Source source = !(sequence instanceof Source) ? null : (Source) sequence;
        Local result = programme == null ? null : programme.newLocal(isFinal, type, specialSimpleName, value, source, declarationPosition);
        if(result == null) result = new Local(isFinal, type, specialSimpleName, value, source, declarationPosition);
        fldLocalsArray.append(result);
        return result;
    }

    public Node createAndInsertNode(Node parent, int index) {
        NodeArray nodes = fldNodesArray;
        if(parent == null)
        {
            parent = fldRoot;
        }
        else if(nodes.indexOf(parent) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("parent-node.not-owned-by-code"));
        }
        Node result = createNode();
        parent.insertChild(index, result);
        nodes.append(result);
        return result;
    }

    public Node createAndPrependNode(Node parent) {
        NodeArray nodes = fldNodesArray;
        if(parent == null)
        {
            parent = fldRoot;
        }
        else if(nodes.indexOf(parent) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("parent-node.not-owned-by-code"));
        }
        Node result = createNode();
        parent.insertChild(0, result);
        nodes.append(result);
        return result;
    }

    public Node createAndAppendNode(Node parent) {
        NodeArray nodes = fldNodesArray;
        if(parent == null)
        {
            parent = fldRoot;
        }
        else if(nodes.indexOf(parent) < 0)
        {
            throw new IllegalArgumentException(package.getResourceString("parent-node.not-owned-by-code"));
        }
        Node result = createNode();
        parent.insertChild(Int.MAX_VALUE, result);
        nodes.append(result);
        return result;
    }

    public final boolean hasJumpsTo(Node node) {
        if(node != null) for(Node[] nodes = fldInstructionsNodes, int index = nodes.length; index-- > 0; )
        {
            Node current = nodes[index];
            if(current != node && current.hasJumpsTo(node)) return true;
        }
        return false;
    }

    public final boolean isEmpty() { return fldInstructionsNodes.length <= 0; }

    public final Node[] clone() {
        Node[] result = fldInstructionsNodes;
        int length = result.length;
        Array.copy(result, 0, result = new Node[length], 0, length);
        return result;
    }

    public final int length { read = fldInstructionsNodes.length }

    public final Node root { read = fldRoot }

    public final NodeArray nodes { read = fldNodesArray }

    public final LocalArray locals { read = fldLocalsArray }

    public final IntArray debugLineIndices { read = fldDebugLineIndicesArray }

    public final Callable parentCallable { read = fldParentCallable }

    public final Programme parentProgramme { read = fldParentProgramme }

    public final Node operator [](int index) {
        if(index >= 0) return fldInstructionsNodes[index];
        Node[] nodes = fldInstructionsNodes;
        return nodes[nodes.length + index];
    }

    protected void afterConstruction() { fldNodesArray.append(fldRoot = createNode()); }

    package final int orderOf(Node node) { return node == null ? -1 : Array.indexOf(node, fldInstructionsNodes, 0, 0); }

    private Node createNode() {
        Programme programme = fldParentProgramme;
        Node result = programme == null ? null : programme.newNode(this);
        return result != null ? result : new Node(this);
    }
}

final class CodeLineIndexArray(Object, Cloneable, Measureable, IntArray)
{
    private int[] fldArray;

    () { (fldArray = new int[0x0f]).length = 0; }

    public int[] clone() {
        int[] result = fldArray;
        int length = result.length;
        Array.copy(result, 0, result = new int[length], 0, length);
        return result;
    }

    public int length { read = fldArray.length }

    public int operator [](int index) { return fldArray[index]; }

    int append(int item) {
        int[] array = fldArray;
        int length = array.length;
        if(length == array.capacity)
        {
            if(length == Int.MAX_VALUE)
            {
                throw new BufferTooLargeError(avt.lang.package.getResourceString("!error.buffer-too-large"));
            }
            Array.copy(array, 0, fldArray = array = new int[length << 1 | 1], 0, length);
        }
        array.length = length + 1;
        array[length] = item;
        return length;
    }
}