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