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