Node.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 Node(CallableItem, DataHolder, Cloneable, Measureable, ObjectArray)
{
    private boolean fldWeak;
    private boolean fldUseSuper;
    private boolean fldEndPoint;
    private int fldSpecialState;
    private int fldDebugIndex;
    private int fldLabelIndex;
    private int fldInstruction;
    private int fldStackElements;
    private int fldJumpCasesLength;
    private int[] fldJumpCasesValues;
    private Node[] fldJumpCasesNodes;
    private Node[] fldChildsNodes;
    private Node fldJumpDefault;
    private Node fldParentNode;
    private Type fldType;
    private Object fldReference1;
    private Object fldReference2;
    private TableItem fldOperand1;
    private TableItem fldOperand2;
    private final Code fldParentCode;

    public (Code parentCode): super(parentCode == null ? null : parentCode.sequence) {
        fldDebugIndex = -1;
        fldLabelIndex = -1;
        fldInstruction = -1;
        fldStackElements = -1;
        fldParentCode = parentCode;
    }

    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" }));
        }
        if(fldJumpDefault == oldJumpNode)
        {
            fldJumpDefault = newJumpNode;
        }
        for(Node[] nodes = fldJumpCasesNodes, int length = fldJumpCasesLength, int index = 0; index < length && (index = Array.indexOf(oldJumpNode, nodes, index, length - index)) >= 0; )
        {
            nodes[index++] = newJumpNode;
        }
    }

    public void setJumpCase(int valueOfCase, Node jumpIsCase) {
        int length = fldJumpCasesLength;
        int[] values = fldJumpCasesValues;
        Node[] nodes = fldJumpCasesNodes;
        if(jumpIsCase == null)
        {
            if(length > 0)
            {
                int index = Array.indexOf(valueOfCase, values, 0, length);
                if(index >= 0)
                {
                    int next = index + 1;
                    int count = --length - index;
                    Array.copy(values, next, values, index, count);
                    Array.copy(nodes, next, nodes, index, count);
                    values[length] = 0;
                    nodes[length] = null;
                    fldJumpCasesLength = length;
                }
            }
            return;
        }
        if(length <= 0)
        {
            if(values == null) fldJumpCasesValues = values = new int[0x0f];
            if(nodes == null) fldJumpCasesNodes = nodes = new Node[0x0f];
            values[0] = valueOfCase;
            nodes[0] = jumpIsCase;
            fldEndPoint = false;
            fldJumpCasesLength = 1;
            return;
        }
        int index = Array.indexOf(valueOfCase, values, 0, length);
        if(index >= 0)
        {
            nodes[index] = jumpIsCase;
            return;
        }
        if(length == nodes.length)
        {
            if(length == Int.MAX_VALUE)
            {
                throw new BufferTooLargeError(avt.lang.package.getResourceString("!error.buffer-too-large"));
            }
            int capacity = length << 1 | 1;
            Array.copy(values, 0, fldJumpCasesValues = values = new int[capacity], 0, length);
            Array.copy(nodes, 0, fldJumpCasesNodes = nodes = new Node[capacity], 0, length);
        }
        values[length] = valueOfCase;
        nodes[length++] = jumpIsCase;
        fldJumpCasesLength = length;
    }

    public void clearJumpCases() {
        int length = fldJumpCasesLength;
        if(length > 0)
        {
            Array.fill(fldJumpCasesValues, 0, length, 0);
            Array.fill(fldJumpCasesNodes, 0, length, null);
            fldJumpCasesLength = 0;
        }
    }

    public Node setData(int position, int instruction) {
        setPosition(position);
        setType(null);
        setInstruction(instruction);
        setReference1(null);
        setReference2(null);
        setOperand1(null);
        setOperand2(null);
        return this;
    }

    public Node setData(int position, int instruction, Object reference1) {
        setPosition(position);
        setType(null);
        setInstruction(instruction);
        setReference1(reference1);
        setReference2(null);
        setOperand1(null);
        setOperand2(null);
        return this;
    }

    public Node setData(int position, int instruction, Object reference1, Object reference2) {
        setPosition(position);
        setType(null);
        setInstruction(instruction);
        setReference1(reference1);
        setReference2(reference2);
        setOperand1(null);
        setOperand2(null);
        return this;
    }

    public Node setData(int position, Type type, int instruction) {
        setPosition(position);
        setType(type);
        setInstruction(instruction);
        setReference1(null);
        setReference2(null);
        setOperand1(null);
        setOperand2(null);
        return this;
    }

    public Node setData(int position, Type type, int instruction, TableItem operand1) {
        setPosition(position);
        setType(type);
        setInstruction(instruction);
        setReference1(null);
        setReference2(null);
        setOperand1(operand1);
        setOperand2(null);
        return this;
    }

    public Node setData(int position, Type type, int instruction, TableItem operand1, TableItem operand2) {
        setPosition(position);
        setType(type);
        setInstruction(instruction);
        setReference1(null);
        setReference2(null);
        setOperand1(operand1);
        setOperand2(operand2);
        return this;
    }

    public final boolean hasJumpsTo(Node node) {
        if(node != null)
        {
            if(getJumpDefault() == node) return true;
            int length = fldJumpCasesLength;
            if(length > 0 && Array.indexOf(node, fldJumpCasesNodes, 0, length) >= 0) return true;
        }
        return false;
    }

    public final boolean isEmpty() {
        Measureable nodes = fldChildsNodes;
        return nodes == null || nodes.length <= 0;
    }

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

    public final boolean isParent(Node node) {
        if(node != null && node != this) for(Node current = fldParentNode; current != null; current = current.fldParentNode) if(current == node) return true;
        return false;
    }

    public final int minOrder() {
        Code code = fldParentCode;
        if(code == null) return -1;
        int result = -1;
        label0: for(Node node = this, Node parent = null, int index = -1, Node target = fldParentNode; ; )
        {
            int order = code.orderOf(node);
            if(order >= 0 && (result < 0 || order < result))
            {
                result = order;
            }
            if(node.length > 0)
            {
                node = (parent = node)[index = 0];
                continue;
            }
            if(parent == null)
            {
                break;
            }
            if(++index < parent.length)
            {
                node = parent[index];
                continue;
            }
            do
            {
                index = parent.index + 1;
                if((parent = parent.fldParentNode) == target)
                {
                    break label0;
                }
                if(index < parent.length)
                {
                    node = parent[index];
                    break;
                }
            } while(true);
        }
        return result;
    }

    public final int maxOrder() {
        Code code = fldParentCode;
        if(code == null) return -1;
        int result = -1;
        label0: for(Node node = this, Node parent = null, int index = -1, Node target = fldParentNode; ; )
        {
            int order = code.orderOf(node);
            if(order > result)
            {
                result = order;
            }
            if(node.length > 0)
            {
                node = (parent = node)[index = 0];
                continue;
            }
            if(parent == null)
            {
                break;
            }
            if(++index < parent.length)
            {
                node = parent[index];
                continue;
            }
            do
            {
                index = parent.index + 1;
                if((parent = parent.fldParentNode) == target)
                {
                    break label0;
                }
                if(index < parent.length)
                {
                    node = parent[index];
                    break;
                }
            } while(true);
        }
        return result;
    }

    public final int getJumpCasesLength() { return fldJumpCasesLength; }

    public final int getJumpCaseValueAt(int index) {
        int[] values = fldJumpCasesValues;
        if(values == null || index < 0 || index >= fldJumpCasesLength)
        {
            throw new ArrayIndexOutOfBoundsException(avt.lang.package.getResourceString("out-of-bounds.array-index"));
        }
        return values[index];
    }

    public final Node getJumpCaseNodeAt(int index) {
        Node[] nodes = fldJumpCasesNodes;
        if(nodes == null || index < 0 || index >= fldJumpCasesLength)
        {
            throw new ArrayIndexOutOfBoundsException(avt.lang.package.getResourceString("out-of-bounds.array-index"));
        }
        return nodes[index];
    }

    public final Node getJumpCase(int valueOfCase) {
        int length = fldJumpCasesLength;
        if(length <= 0) return null;
        int index = Array.indexOf(valueOfCase, fldJumpCasesValues, 0, length);
        return index < 0 ? null : fldJumpCasesNodes[index];
    }

    public Node jumpIsTrue { read = fldJumpDefault, write = setJumpDefault }

    public Node jumpIsFalse { index = 0, read = getJumpCase, write = setJumpCase }

    public final int length { read = getLength }

    public final boolean weak { read = fldWeak, write = setWeak }

    public final boolean special { index = 0, read = getSpecialState, write = setSpecialState }

    public final boolean endPoint { read = fldEndPoint, write = setEndPoint }

    public final boolean useSuper { read = fldUseSuper, write = fldUseSuper }

    public final boolean persistent { index = 1, read = getSpecialState, write = setSpecialState }

    public final int index { read = getIndex }

    public final int order { read = getOrder }

    public final int debugIndex { read = fldDebugIndex, write = fldDebugIndex }

    public final int labelIndex { read = fldLabelIndex, write = fldLabelIndex }

    public final int instruction { read = fldInstruction, write = setInstruction }

    public final int stackElements { read = fldStackElements, write = fldStackElements }

    public final Type type { read = fldType, write = setType }

    public final TableItem operand1 { read = fldOperand1, write = setOperand1 }

    public final TableItem operand2 { read = fldOperand2, write = setOperand2 }

    public final Object reference1 { read = fldReference1, write = setReference1 }

    public final Object reference2 { read = fldReference2, write = setReference2 }

    public final Node jumpDefault { read = getJumpDefault, write = setJumpDefault }

    public final Node parentNode { read = fldParentNode }

    public final Code parentCode { read = fldParentCode }

    public final Node operator [](int index) {
        Node[] nodes = fldChildsNodes;
        if(nodes == null)
        {
            throw new ArrayIndexOutOfBoundsException(avt.lang.package.getResourceString("out-of-bounds.array-index"));
        }
        return nodes[index >= 0 ? index : nodes.length + index];
    }

    protected void setType(Type newType) { fldType = newType; }

    protected void setWeak(boolean newWeak) { fldWeak = newWeak; }

    protected void setInstruction(int newInstruction) { fldInstruction = newInstruction; }

    protected void setReference1(Object newReference1) { fldReference1 = newReference1; }

    protected void setReference2(Object newReference2) { fldReference2 = newReference2; }

    protected void setOperand1(TableItem newOperand1) { fldOperand1 = newOperand1; }

    protected void setOperand2(TableItem newOperand2) { fldOperand2 = newOperand2; }

    protected void setJumpDefault(Node newJumpDefault) {
        fldEndPoint = false;
        fldJumpDefault = newJumpDefault;
    }

    package final void moveChild(int oldIndex, int newIndex) {
        Node[] nodes = fldChildsNodes;
        int length = nodes == null ? 0 : nodes.length;
        if(oldIndex < 0 || oldIndex >= length || newIndex < 0 || newIndex > length)
        {
            throw new IndexOutOfBoundsException(package.getResourceString("out-of-bounds.child-node-index"));
        }
        if(newIndex > oldIndex)
        {
            newIndex--;
        }
        if(newIndex != oldIndex)
        {
            Node node = nodes[oldIndex];
            if(oldIndex > newIndex)
            {
                Array.copy(nodes, newIndex, nodes, newIndex + 1, oldIndex - newIndex);
            } else
            {
                Array.copy(nodes, oldIndex + 1, nodes, oldIndex, newIndex - oldIndex);
            }
            nodes[newIndex] = node;
        }
    }

    package final void insertChild(int index, Node child) {
        if(child == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "child" }));
        }
        Node[] nodes = fldChildsNodes;
        if(nodes == null)
        {
            (fldChildsNodes = nodes = new Node[0x0f]).length = 1;
            nodes[0] = child;
        } else
        {
            int length = nodes.length;
            if(index < 0)
            {
                index = 0;
            }
            if(index > length)
            {
                index = length;
            }
            if(length == nodes.capacity)
            {
                if(length == Int.MAX_VALUE)
                {
                    throw new BufferTooLargeError(avt.lang.package.getResourceString("!error.buffer-too-large"));
                }
                Array.copy(nodes, 0, fldChildsNodes = nodes = new Node[length << 1 | 1], 0, length);
            }
            nodes.length = length + 1;
            Array.copy(nodes, index, nodes, index + 1, length - index);
            nodes[index] = child;
        }
        child.fldParentNode = this;
    }

    package final void deleteChild(int index) {
        Node[] nodes = fldChildsNodes;
        int length = nodes == null ? 0 : nodes.length;
        if(index < 0 || index >= length)
        {
            throw new IndexOutOfBoundsException(package.getResourceString("out-of-bounds.child-node-index"));
        }
        nodes[index].fldParentNode = null;
        Array.copy(nodes, index + 1, nodes, index, --length - index);
        nodes[length] = null;
        nodes.length = length;
    }

    package final void deleteChilds() {
        Node[] nodes = fldChildsNodes;
        int length = nodes == null ? 0 : nodes.length;
        if(length > 0)
        {
            for(int index = length; index-- > 0; ) nodes[index].fldParentNode = null;
            Array.fill(nodes, 0, length, null);
            nodes.length = 0;
        }
    }

    private void setEndPoint(boolean newEndPoint) { if(!newEndPoint || fldJumpCasesLength <= 0 && fldJumpDefault == null) fldEndPoint = newEndPoint; }

    private void setSpecialState(int index, boolean newSpecialState) {
        int state = fldSpecialState & ~(1 << index) | (!newSpecialState ? 0 : 1 << index);
        fldSpecialState = state != 0b10 ? state : 0b11 * index;
    }

    private boolean getSpecialState(int index) { return (fldSpecialState & (1 << index)) != 0; }

    private int getLength() {
        Node[] nodes = fldChildsNodes;
        return nodes == null ? 0 : nodes.length;
    }

    private int getIndex() {
        Node parent = fldParentNode;
        Node[] nodes = parent == null ? null : parent.fldChildsNodes;
        int length = nodes == null ? 0 : nodes.length;
        return length <= 0 ? -1 : Array.indexOf(this, nodes, 0, length);
    }

    private int getOrder() {
        Code code = fldParentCode;
        return code == null ? -1 : code.orderOf(this);
    }

    private Node getJumpDefault() {
        Node result = fldJumpDefault;
        if(result != null) return result;
        if(fldEndPoint) return null;
        Code code = fldParentCode;
        int order = code == null ? 0 : code.orderOf(this) + 1;
        return order <= 0 || order >= code.length ? null : code[order];
    }
}