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

io.termd.core.term.OpCode Maven / Gradle / Ivy

Go to download

An open source terminal daemon library providing terminal handling in Java, back ported to Alibaba by core engine team to support running on JDK 6+.

The newest version!
/*
 * Copyright 2015 Julien Viet
 *
 * 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 io.termd.core.term;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Julien Viet
 */
public abstract class OpCode {

  public String toString() {
    StringBuilder sb = new StringBuilder();
    toString(sb);
    return sb.toString();
  }

  public void eval(EvalContext context) {
    throw new UnsupportedOperationException(getClass().getSimpleName() + " operation not implemented");
  }

  protected abstract void toString(StringBuilder sb);

  public static class PushParam extends OpCode {

    private final int index;

    public PushParam(int index) {
      if (index < 1 || index > 9) {
        throw new IllegalArgumentException("Parameter index must be between 1 and 9");
      }
      this.index = index;
    }

    public int getIndex() {
      return index;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof PushParam) {
        PushParam that = (PushParam) obj;
        return index == that.index;
      }
      return false;
    }

    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%p").append(index);
    }

    @Override
    public void eval(EvalContext context) {
      int ptr = index - 1;
      if (ptr >= context.getParametersLength()) {
        throw new IllegalArgumentException("Not enough parameters");
      }
      context.push(context.getParameter(ptr));
    }
  }

  // Synthetic opcode for string literal
  public static class Literal extends OpCode {
    final String value;
    public Literal(String value) {
      this.value = value;
    }
    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof Literal) {
        Literal that = (Literal) obj;
        return value.equals(that.value);
      }
      return false;
    }
    @Override
    protected void toString(StringBuilder sb) {
      sb.append(value);
    }

    @Override
    public void eval(EvalContext context) {
      context.writeString(value);
    }
  }

  // %'A' or %{65}
  public static class PushConstant extends OpCode {

    private final int value;
    private final boolean literal;

    public PushConstant(int value, boolean literal) {
      this.value = value;
      this.literal = literal;
    }

    public int getValue() {
      return value;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof OpCode.PushConstant) {
        OpCode.PushConstant that = (PushConstant) obj;
        return value == that.value && literal == that.literal;
      }
      return false;
    }

    @Override
    protected void toString(StringBuilder sb) {
      if (literal) {
        sb.append("%{").append(value).append("}");
      } else {
        sb.append("%'").append((char)value).append("'");
      }
    }

    @Override
    public void eval(EvalContext context) {
      StringBuilder sb = new StringBuilder();
      if (literal) {
        sb.append(value);
      } else {
        sb.appendCodePoint(value);
      }
      context.push(sb.toString());
    }
  }

  // %%
  public static class Percent extends OpCode {
    public static final Percent INSTANCE = new Percent();
    private Percent() {
    }

    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%%");
    }
  }

  // %l
  public static class PushStrLen extends OpCode {
    public static final PushStrLen INSTANCE = new PushStrLen();
    private PushStrLen() {
    }
    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%l");
    }
  }

  // %%
  public static class Add1ToParams extends OpCode {
    public static final Add1ToParams INSTANCE = new Add1ToParams();
    private Add1ToParams() {
    }
    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%i");
    }

    @Override
    public void eval(EvalContext context) {
      if (context.getParametersLength() < 2) {
        throw new IllegalArgumentException("Missing parameters");
      }
      for (int i = 0;i < 2; i++) {
        context.setParameter(i, Integer.toString((Integer.parseInt(context.getParameter(i)) + 1)));
      }
    }
  }

  // %c
  // %s
  public static class PrintChar extends OpCode {
    public static final PrintChar INSTANCE = new PrintChar();
    private PrintChar() {
    }
    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%c");
    }
    @Override
    public void eval(EvalContext context) {
      String s = context.pop();
      int codePoint = Integer.parseInt(s);
      context.writeCodePoint(codePoint);
    }
  }

  public static class SetPopVar extends OpCode {
    private final char value;
    public SetPopVar(char value) {
      this.value = value;
    }
    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof SetPopVar) {
        SetPopVar that = (SetPopVar) obj;
        return value == that.value;
      }
      return false;
    }
    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%P").append(value);
    }
  }

  public static class GetPushVar extends OpCode {
    private final char value;
    public GetPushVar(char value) {
      this.value = value;
    }
    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof GetPushVar) {
        GetPushVar that = (GetPushVar) obj;
        return value == that.value;
      }
      return false;
    }
    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%g").append(value);
    }
  }

  public static class Bit extends OpCode {

    public static final Bit OR = new Bit('|');
    public static final Bit AND = new Bit('&');
    public static final Bit XOR = new Bit('^');
    public static final Bit NEG = new Bit('~');

    private final char value;

    private Bit(char value) {
      this.value = value;
    }

    @Override
    protected void toString(StringBuilder sb) {
      sb.append('%').append(value);
    }
  }

  public static class Logical extends OpCode {

    public static final Logical EQ = new Logical('=') {
      @Override
      public void eval(EvalContext context) {
        int op1 = Integer.parseInt(context.pop());
        int op2 = Integer.parseInt(context.pop());
        context.push(op1 == op2 ? "1" : "0");
      }
    };
    public static final Logical GT = new Logical('>');
    public static final Logical LT = new Logical('<');
    public static final Logical AND = new Logical('A');
    public static final Logical OR = new Logical('O');
    public static final Logical NEG = new Logical('!');

    final char value;

    private Logical(char value) {
      this.value = value;
    }

    @Override
    protected void toString(StringBuilder sb) {
      sb.append('%').append(value);
    }
  }

  public static class Arithmetic extends OpCode {

    public static final Arithmetic PLUS = new Arithmetic('+') {
      @Override
      public void eval(EvalContext context) {
        int op1 = Integer.parseInt(context.pop());
        int op2 = Integer.parseInt(context.pop());
        context.push(Integer.toString(op1 + op2));
      }
    };
    public static final Arithmetic MINUS = new Arithmetic('-');
    public static final Arithmetic MUL = new Arithmetic('*');
    public static final Arithmetic DIV = new Arithmetic('/');
    public static final Arithmetic MOD = new Arithmetic('m');

    final char value;

    private Arithmetic(char value) {
      this.value = value;
    }

    @Override
    protected void toString(StringBuilder sb) {
      sb.append('%').append(value);
    }
  }

  public static class Printf extends OpCode {

    private static final Pattern p = Pattern.compile("%:?([-+# ])?([0-9]+)?(?:\\.([0-9]+))?([doxXs])?");

    public static Printf parse(String s) {
      Matcher m = p.matcher(s);
      if (!m.matches()) {
        throw new IllegalArgumentException("Invalid printf pattern " + s);
      }
      String flag = m.group(1);
      String width = m.group(2);
      String precision = m.group(3);
      String specifier = m.group(4);
      return new Printf(flag != null ? flag.charAt(0) : null, width, precision, specifier != null ? specifier.charAt(0) : null);
    }

    private final Character flag;
    private final String width;
    private final String precision;
    private final Character specifier;

    public Printf(Character flag, String width, String precision, Character specifier) {
      this.flag = flag;
      this.width = width;
      this.precision = precision;
      this.specifier = specifier;
    }

    public Character getFlag() {
      return flag;
    }

    public String getWidth() {
      return width;
    }

    public String getPrecision() {
      return precision;
    }

    public Character getSpecifier() {
      return specifier;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof OpCode.Printf) {
        OpCode.Printf that = (Printf) obj;
        return
            (flag == null ? that.flag == null : flag.equals(that.flag)) &&
            (width == null ? that.width == null : width.equals(that.width)) &&
            (precision == null ? that.precision == null : precision.equals(that.precision)) &&
            (specifier == null ? that.specifier == null : specifier.equals(that.specifier));
      }
      return false;
    }

    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%:");
      if (flag != null) {
        sb.append(flag);
      }
      if (width != null) {
        sb.append(width);
      }
      if (precision != null) {
        sb.append(".").append(precision);
      }
      if (specifier != null) {
        sb.append(specifier);
      }
    }

    @Override
    public void eval(EvalContext context) {
      if (flag != null || width != null || precision != null) {
        super.eval(context);
      }
      if (specifier != null) {
        switch (specifier) {
          case 'd': {
            int value = Integer.parseInt(context.pop());
            context.writeNumber(value);
            break;
          }
          case 's': {
            String s = context.pop();
            context.writeString(s);
            break;
          }
          default:
            super.eval(context);
        }
      }
    }
  }

  public static class If extends OpCode implements ElsePart {

    final List expr;
    final Then thenPart;

    public If(List expr, Then thenPart) {
      this.expr = expr;
      this.thenPart = thenPart;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof If) {
        If that = (If) obj;
        return expr.equals(that.expr) && thenPart.equals(that.thenPart);
      }
      return false;
    }

    @Override
    protected void toString(StringBuilder sb) {
      sb.append("%?");
      for (OpCode op : expr) {
        op.toString(sb);
      }
      thenPart.toString(sb);
      sb.append("%;");
    }

    @Override
    public void eval(EvalContext context) {
      for (OpCode opCode : expr) {
        opCode.eval(context);
      }
      thenPart.eval(context);
    }
  }

  public static class Else extends OpCode implements ElsePart {

    final List expr;

    public Else(List expr) {
      this.expr = expr;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof Else) {
        Else that = (Else) obj;
        return expr.equals(that.expr);
      }
      return false;
    }

    protected void toString(StringBuilder sb) {
      sb.append("%e");
      for (OpCode op : expr) {
        op.toString(sb);
      }
    }

    @Override
    public void eval(EvalContext context) {
      for (OpCode opCode : expr) {
        opCode.eval(context);
      }
    }
  }

  public static class Then extends OpCode {

    final List expr;
    final ElsePart elsePart;

    public Then(List expr, ElsePart elsePart) {
      this.expr = expr;
      this.elsePart = elsePart;
    }

    public Then(List expr) {
      this.expr = expr;
      this.elsePart = null;
    }

    @Override
    public boolean equals(Object obj) {
      if (obj == this) {
        return true;
      }
      if (obj instanceof Then) {
        Then that = (Then) obj;
        return expr.equals(that.expr) && (elsePart == null ? that.elsePart == null : elsePart.equals(that.elsePart));
      }
      return false;
    }

    protected void toString(StringBuilder sb) {
      sb.append("%t");
      for (OpCode op : expr) {
        op.toString(sb);
      }
      if (elsePart instanceof Else) {
        ((Else) elsePart).toString(sb);
      } else if (elsePart instanceof If) {
        ((If) elsePart).toString(sb);
      }
    }

    @Override
    public void eval(EvalContext context) {
      int cond = Integer.parseInt(context.pop());
      if (cond != 0) {
        for (OpCode opCode : expr) {
          opCode.eval(context);
        }
      } else {
        if (elsePart instanceof If) {
          ((If) elsePart).eval(context);
        } else if (elsePart instanceof Else) {
          ((Else) elsePart).eval(context);
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy