All Downloads are FREE. Search and download functionalities are using the official Maven repository.

objectos.code.internal.InternalApi Maven / Gradle / Ivy

There is a newer version: 0.8.2
Show newest version
/*
 * Copyright (C) 2014-2023 Objectos Software LTDA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package objectos.code.internal;

import objectos.code.JavaTemplate;
import objectos.code.JavaTemplate._Ext;
import objectos.code.JavaTemplate._Include;
import objectos.code.JavaTemplate._Item;
import objectos.code.tmpl.TypeName;
import objectos.lang.Check;
import objectos.util.IntArrays;
import objectos.util.ObjectArrays;

public class InternalApi {

  static final int NULL = Integer.MIN_VALUE;

  private static final int LOCAL = -1;
  private static final int EXT = -2;
  private static final int LAMBDA = -3;
  private static final int LTAIL = -4;

  public final AutoImports autoImports = new AutoImports();

  int[] codeArray = new int[128];

  int codeIndex;

  Object[] objectArray = new Object[64];

  int objectIndex;

  int[] protoArray = new int[256];

  int protoIndex;

  int[] stackArray = new int[10];

  int stackIndex;

  public final void arrayTypeName(Class type) {
    int dimCount = 1;

    var componentType = type.getComponentType();

    for (;;) {
      var next = componentType.getComponentType();

      if (next == null) {
        break;
      }

      dimCount++;

      componentType = next;
    }

    classType(componentType);

    for (int i = 0; i < dimCount; i++) {
      itemAdd(ByteProto.ARRAY_DIMENSION, ByteProto.NOOP);
    }

    arrayTypeName(dimCount);
  }

  public final _Item arrayTypeName(int dimCount) {
    elemCnt(ByteProto.ARRAY_TYPE, 1 + dimCount);

    elemItem(_Item.INSTANCE);

    for (int i = 0; i < dimCount; i++) {
      elemItem(_Item.INSTANCE);
    }

    return elemRet();
  }

  public final void arrayTypeName(TypeName type, int count) {
    // cast is safe: TypeName is sealed
    var ext = (External) type;

    ext.execute(this);

    for (int i = 0; i < count; i++) {
      itemAdd(ByteProto.ARRAY_DIMENSION, ByteProto.NOOP);
    }

    elemCnt(ByteProto.ARRAY_TYPE, 1 + count);

    elemItem(_Ext.INSTANCE);

    for (int i = 0; i < count; i++) {
      elemItem(_Item.INSTANCE);
    }

    elemRet();
  }

  public final _Item classType(Class type) {
    var last = objectIndex;

    while (true) {
      var simpleName = type.getSimpleName(); // implicit null-check

      object(simpleName);

      var outer = type.getEnclosingClass();

      if (outer == null) {
        break;
      } else {
        type = outer;
      }
    }

    var first = objectIndex - 1;

    var names = objectIndex - last;

    var packageName = type.getPackageName();

    localStart();

    protoAdd(ByteProto.CLASS_TYPE, object(packageName), names);

    for (var index = first; index >= last; index--) {
      var simpleName = objectArray[index];

      protoAdd(object(simpleName));
    }

    return _Item.INSTANCE;
  }

  public final _Item elem(int proto) {
    int count = 0;
    elemCnt(proto, count);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1) {
    int count = 0;
    count += elemPre(e1);
    elemCnt(proto, count);
    elemItem(e1);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3, Object e4) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    count += elemPre(e4);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    elemItem(e4);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3, Object e4,
      Object e5) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    count += elemPre(e4);
    count += elemPre(e5);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    elemItem(e4);
    elemItem(e5);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3, Object e4,
      Object e5, Object e6) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    count += elemPre(e4);
    count += elemPre(e5);
    count += elemPre(e6);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    elemItem(e4);
    elemItem(e5);
    elemItem(e6);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3, Object e4,
      Object e5, Object e6, Object e7) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    count += elemPre(e4);
    count += elemPre(e5);
    count += elemPre(e6);
    count += elemPre(e7);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    elemItem(e4);
    elemItem(e5);
    elemItem(e6);
    elemItem(e7);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3, Object e4,
      Object e5, Object e6, Object e7, Object e8) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    count += elemPre(e4);
    count += elemPre(e5);
    count += elemPre(e6);
    count += elemPre(e7);
    count += elemPre(e8);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    elemItem(e4);
    elemItem(e5);
    elemItem(e6);
    elemItem(e7);
    elemItem(e8);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3, Object e4,
      Object e5, Object e6, Object e7, Object e8, Object e9) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    count += elemPre(e4);
    count += elemPre(e5);
    count += elemPre(e6);
    count += elemPre(e7);
    count += elemPre(e8);
    count += elemPre(e9);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    elemItem(e4);
    elemItem(e5);
    elemItem(e6);
    elemItem(e7);
    elemItem(e8);
    elemItem(e9);
    return elemRet();
  }

  public final _Item elem(int proto, Object e1, Object e2, Object e3, Object e4,
      Object e5, Object e6, Object e7, Object e8, Object e9, Object e10) {
    int count = 0;
    count += elemPre(e1);
    count += elemPre(e2);
    count += elemPre(e3);
    count += elemPre(e4);
    count += elemPre(e5);
    count += elemPre(e6);
    count += elemPre(e7);
    count += elemPre(e8);
    count += elemPre(e9);
    count += elemPre(e10);
    elemCnt(proto, count);
    elemItem(e1);
    elemItem(e2);
    elemItem(e3);
    elemItem(e4);
    elemItem(e5);
    elemItem(e6);
    elemItem(e7);
    elemItem(e8);
    elemItem(e9);
    elemItem(e10);
    return elemRet();
  }

  public final _Item elemMany(int proto, Object first, Object second, Object[] elements) {
    int count = 0;

    count += elemPre(first);
    count += elemPre(second);

    for (int i = 0; i < elements.length; i++) {
      var element = elements[i];
      Check.notNull(element, "elements[", i, "] == null");
      count += elemPre(element);
    }

    elemCnt(proto, count);

    elemItem(first);
    elemItem(second);

    for (int i = 0; i < elements.length; i++) {
      var element = elements[i];
      elemItem(element);
    }

    return elemRet();
  }

  public final _Item elemMany(int proto, Object first, Object[] elements) {
    int count = 0;

    count += elemPre(first);

    for (int i = 0; i < elements.length; i++) {
      var element = elements[i];
      Check.notNull(element, "elements[", i, "] == null");
      count += elemPre(element);
    }

    elemCnt(proto, count);

    elemItem(first);

    for (int i = 0; i < elements.length; i++) {
      var element = elements[i];
      elemItem(element);
    }

    return elemRet();
  }

  public final _Item elemMany(int proto, Object[] elements) {
    int count = 0;

    for (int i = 0; i < elements.length; i++) {
      var element = elements[i];
      Check.notNull(element, "elements[", i, "] == null");
      count += elemPre(element);
    }

    elemCnt(proto, count);

    for (int i = 0; i < elements.length; i++) {
      var element = elements[i];
      elemItem(element);
    }

    return elemRet();
  }

  public final void externalToLocal() {
    codeArray[codeIndex - 2] = LOCAL;
  }

  public final void extStart() {
    levelAdd(EXT, protoIndex);
  }

  public final void identifierext(String value) {
    levelAdd(EXT, protoIndex);
    protoAdd(ByteProto.IDENTIFIER, object(value));
  }

  public final _Item itemAdd(int v0, int v1) {
    localStart();
    protoAdd(v0, v1);
    return _Item.INSTANCE;
  }

  public final _Item itemAdd(int v0, int v1, int v2, int v3) {
    localStart();
    protoAdd(v0, v1, v2, v3);
    return _Item.INSTANCE;
  }

  public final _Item itemAdd(int v0, int v1, int v2, int v3, int v4) {
    localStart();
    protoAdd(v0, v1, v2, v3, v4);
    return _Item.INSTANCE;
  }

  public final _Item itemEnd() {
    return _Item.INSTANCE;
  }

  public final void lambdaend() {
    int headIndex = stackPop();

    levelAdd(LTAIL, headIndex);

    codeArray[headIndex + 1] = codeIndex;
  }

  public final void lambdastart() {
    // push lambda head
    stackPush(codeIndex);

    levelAdd(LAMBDA, NULL);
  }

  public final void localStart() {
    levelAdd(LOCAL, protoIndex);
  }

  public final void localToExternal() {
    codeArray[codeIndex - 2] = EXT;
  }

  public final int object(Object value) {
    objectArray = ObjectArrays.growIfNecessary(objectArray, objectIndex);

    var result = objectIndex;

    objectArray[objectIndex++] = value;

    return result;
  }

  public final void protoAdd(int v0) {
    protoArray = IntArrays.growIfNecessary(protoArray, protoIndex + 0);
    protoArray[protoIndex++] = v0;
  }

  public final void protoAdd(int v0, int v1) {
    protoArray = IntArrays.growIfNecessary(protoArray, protoIndex + 1);
    protoArray[protoIndex++] = v0;
    protoArray[protoIndex++] = v1;
  }

  protected final void accept(InternalJavaTemplate template) {
    autoImports.clear();

    stackIndex = -1;

    codeIndex = objectIndex = protoIndex = 0;

    template.execute(this);

    int self = protoIndex;

    for (int i = 0; i < codeIndex;) {
      int kind = codeArray[i++];

      if (kind == LOCAL) {
        int protoIndex = codeArray[i++];

        int proto = protoGet(protoIndex++);

        protoAdd(proto, protoIndex);
      } else {
        throw new UnsupportedOperationException(
          "Implement me :: code=" + kind
        );
      }
    }

    protoAdd(ByteProto.END_ELEMENT);

    stackArray[0] = protoIndex;

    protoIndex = self;
  }

  final _Item itemAdd(int v0) {
    localStart();
    protoAdd(v0);
    return _Item.INSTANCE;
  }

  final _Item itemAdd(int v0, int v1, int v2) {
    localStart();
    protoAdd(v0, v1, v2);
    return _Item.INSTANCE;
  }

  final void protoAdd(int v0, int v1, int v2) {
    protoArray = IntArrays.growIfNecessary(protoArray, protoIndex + 2);
    protoArray[protoIndex++] = v0;
    protoArray[protoIndex++] = v1;
    protoArray[protoIndex++] = v2;
  }

  final int stackPop() { return stackArray[stackIndex--]; }

  final void stackPush(int v0) {
    stackArray = IntArrays.growIfNecessary(stackArray, stackIndex + 1);
    stackArray[++stackIndex] = v0;
  }

  private void elemCnt(int value, int itemCount) {
    int seenCount = 0;

    int index = codeIndex;

    while (seenCount < itemCount) {
      index -= 2;

      int item = codeArray[index];

      if (item == LOCAL || item == EXT) {
        seenCount++;
      } else if (item == LTAIL) {
        int headIndex = codeArray[index + 1];

        index = headIndex;

        seenCount++;
      } else {
        throw new UnsupportedOperationException("Implement me :: item=" + item);
      }
    }

    int levelStart = index,
        localIndex = levelStart,
        extIndex = levelStart,
        includeIndex = levelStart;

    stackPush(
      /*4*/protoIndex,
      /*3*/levelStart,
      /*2*/includeIndex,
      /*1*/extIndex,
      /*0*/localIndex
    );

    protoAdd(value);
  }

  private void elemCntx0lambda(int index) {
    // index is at tail index
    // start is first instruction after LAMBDA
    int start = index + 1;

    // index is at tail index
    // max is at lambda tail
    int max = codeArray[index] - 2;

    for (int i = start; i < max;) {
      int code = codeArray[i];

      if (code == LOCAL) {
        i++;

        int levelValue = codeArray[i++];

        int proto = protoGet(levelValue++);

        protoAdd(proto, levelValue);
      } else if (code == LAMBDA) {
        elemCntx0lambda(i);

        i = codeArray[i + 1];
      } else {
        throw new UnsupportedOperationException(
          "Implement me :: code=" + code);
      }
    }
  }

  private void elemItem(Object obj) {
    int offset;
    int kind;

    if (obj instanceof JavaTemplate._Item item) {
      offset = 0;

      kind = LOCAL;
    } else if (
      obj == _Ext.INSTANCE || obj instanceof External || obj instanceof String) {
      offset = 1;

      kind = EXT;
    } else if (obj == _Include.INSTANCE) {
      offset = 2;

      kind = LAMBDA;
    } else {
      throw new UnsupportedOperationException(
        "Implement me :: obj=" + obj);
    }

    int index = stackPeek(offset);

    index = levelSearch(index, kind);

    if (kind != LAMBDA) {
      int levelValue = levelGet(index);

      int proto = protoGet(levelValue++);

      protoAdd(proto, levelValue);
    } else {
      elemCntx0lambda(index);
    }

    stackset(offset, index);
  }

  private int elemPre(Object obj) {
    int count = 1;

    if (obj instanceof External ext) {
      ext.execute(this);
    } else if (obj instanceof String s) {
      identifierext(s);
    }

    return count;
  }

  private _Item elemRet() {
    /*localIndex = */stackPop();
    /*extIndex = */stackPop();
    /*includeIndex = */stackPop();

    int levelStart = stackPop(),
        self = stackPop();

    codeIndex = levelStart;

    protoAdd(ByteProto.END_ELEMENT);

    levelAdd(LOCAL, self);

    return _Item.INSTANCE;
  }

  private void levelAdd(int v0, int v1) {
    codeArray = IntArrays.growIfNecessary(codeArray, codeIndex + 1);
    codeArray[codeIndex++] = v0;
    codeArray[codeIndex++] = v1;
  }

  private int levelGet(int index) { return codeArray[index]; }

  private int levelSearch(int index, int condition) {
    for (int i = index; i < codeIndex;) {
      int value = codeArray[i++];

      if (value == LAMBDA && condition != LAMBDA) {
        i = codeArray[i];
      } else if (value == condition) {
        // assuming array was properly assembled
        // there will always be a i+1 index
        return i;
      }
    }

    throw new UnsupportedOperationException(
      "Implement me :: could not find code (index=%d; condition=%d)"
          .formatted(index, condition)
    );
  }

  private void protoAdd(int v0, int v1, int v2, int v3) {
    protoArray = IntArrays.growIfNecessary(protoArray, protoIndex + 3);
    protoArray[protoIndex++] = v0;
    protoArray[protoIndex++] = v1;
    protoArray[protoIndex++] = v2;
    protoArray[protoIndex++] = v3;
  }

  private void protoAdd(int v0, int v1, int v2, int v3, int v4) {
    protoArray = IntArrays.growIfNecessary(protoArray, protoIndex + 4);
    protoArray[protoIndex++] = v0;
    protoArray[protoIndex++] = v1;
    protoArray[protoIndex++] = v2;
    protoArray[protoIndex++] = v3;
    protoArray[protoIndex++] = v4;
  }

  private int protoGet(int index) { return protoArray[index]; }

  private int stackPeek(int offset) { return stackArray[stackIndex - offset]; }

  private void stackPush(int v0, int v1, int v2, int v3, int v4) {
    stackArray = IntArrays.growIfNecessary(stackArray, stackIndex + 5);
    stackArray[++stackIndex] = v0;
    stackArray[++stackIndex] = v1;
    stackArray[++stackIndex] = v2;
    stackArray[++stackIndex] = v3;
    stackArray[++stackIndex] = v4;
  }

  private void stackset(int offset, int value) { stackArray[stackIndex - offset] = value; }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy