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

com.alibaba.fastjson2.internal.codegen.Block Maven / Gradle / Ivy

package com.alibaba.fastjson2.internal.codegen;

import com.alibaba.fastjson2.JSONException;

import java.util.ArrayList;
import java.util.List;

import static com.alibaba.fastjson2.internal.codegen.Opcodes.*;

public class Block {
    protected final List statements = new ArrayList<>();

    public void invoke(String method, Opcodes.Op... args) {
        statements.add(new StatementOp(Opcodes.invoke(method, args)));
    }

    public void invoke(Opcodes.Op owner, String method, Opcodes.Op... args) {
        statements.add(new StatementOp(Opcodes.invoke(owner, method, args)));
    }

    public void putField(String fieldName, Opcodes.Op value) {
        putField(THIS, fieldName, value);
    }

    public void putField(Opcodes.Op owner, String fieldName, Opcodes.Op value) {
        statements.add(new StatementOp(Opcodes.putField(owner, fieldName, value)));
    }

    public void ret(Opcodes.Op value) {
        statements.add(new StatementRet(value));
    }

    public void continueStmt() {
        statements.add(new StatementContinue(null));
    }

    public void continueStmt(String label) {
        statements.add(new StatementContinue(label));
    }

    public void breakStmt() {
        statements.add(new StatementBreak(null));
    }

    public void breakStmt(String label) {
        statements.add(new StatementBreak(label));
    }

    public IfStmt ifStmt(Opcodes.Op testValue) {
        IfStmt stmt = new IfStmt(testValue);
        statements.add(stmt);
        return stmt;
    }

    public IfStmt ifNull(Opcodes.Op testValue) {
        IfStmt stmt = new IfStmt(eq(testValue, ldc(null)));
        statements.add(stmt);
        return stmt;
    }

    public IfStmt ifNotNull(Opcodes.Op testValue) {
        IfStmt stmt = new IfStmt(ne(testValue, ldc(null)));
        statements.add(stmt);
        return stmt;
    }

    public void newLine() {
        statements.add(new Empty());
    }

    public void label(String label) {
        statements.add(new Label(label));
    }

    public ForStmt forStmt(Class initType, Opcodes.Op init, Opcodes.Op condition, Opcodes.Op increment) {
        ForStmt stmt = new ForStmt(initType, init, condition, increment);
        statements.add(stmt);
        return stmt;
    }

    public WhileStmt whileStmtStmt(Opcodes.Op condition) {
        WhileStmt stmt = new WhileStmt(condition);
        statements.add(stmt);
        return stmt;
    }

    public SwitchStmt switchStmt(Opcodes.Op op, int[] hashCodes) {
        SwitchStmt stmt = new SwitchStmt(op, hashCodes);
        statements.add(stmt);
        return stmt;
    }

    public Statement stmt(Opcodes.Op op) {
        StatementOp stmt = new StatementOp(op);
        statements.add(stmt);
        return stmt;
    }

    public Statement declare(Class type, Opcodes.OpName name) {
        DeclareStmt stmt = new DeclareStmt(ClassWriter.getTypeName(type), name, null);
        statements.add(stmt);
        return stmt;
    }

    public Statement declare(String type, Opcodes.OpName name) {
        DeclareStmt stmt = new DeclareStmt(type, name, null);
        statements.add(stmt);
        return stmt;
    }

    public Statement declare(Class type, Opcodes.OpName name, Opcodes.Op initValue) {
        DeclareStmt stmt = new DeclareStmt(ClassWriter.getTypeName(type), name, initValue);
        statements.add(stmt);
        return stmt;
    }

    public Statement declare(Class type, Opcodes.OpName name, Object initValue) {
        DeclareStmt stmt = new DeclareStmt(ClassWriter.getTypeName(type), name, initValue == null ? null : ldc(initValue));
        statements.add(stmt);
        return stmt;
    }

    public Statement declare(String type, Opcodes.OpName name, Op initValue) {
        DeclareStmt stmt = new DeclareStmt(type, name, initValue == null ? null : ldc(initValue));
        statements.add(stmt);
        return stmt;
    }

    public interface Statement {
        default void toString(MethodWriter mw, StringBuilder buf, int indent) {
            throw new JSONException("TODO " + getClass().getName());
        }
    }

    public static class Empty
            implements Statement {
        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
        }
    }

    public static class IfStmt
            extends Block
            implements Statement {
        final Opcodes.Op condition;
        Block elseStmt;

        public IfStmt(Opcodes.Op testValue) {
            this.condition = testValue;
        }

        public Block elseStmt() {
            if (elseStmt == null) {
                elseStmt = new Block();
            }
            return elseStmt;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);
            buf.append("if (");
            condition.toString(mw, buf, indent);
            buf.append(") {").append('\n');

            for (int i = 0; i < statements.size(); i++) {
                if (i != 0) {
                    buf.append('\n');
                }
                Statement stmt = statements.get(i);
                stmt.toString(mw, buf, indent + 1);
            }

            buf.append('\n');
            mw.ident(buf, indent);
            buf.append("}");

            if (elseStmt != null) {
                buf.append(" else {\n");
                for (int i = 0; i < elseStmt.statements.size(); i++) {
                    if (i != 0) {
                        buf.append('\n');
                    }
                    Statement stmt = elseStmt.statements.get(i);
                    stmt.toString(mw, buf, indent + 1);
                }
                buf.append('\n');
                mw.ident(buf, indent);
                buf.append("}");
            }
        }
    }

    public static class Label
            implements Statement {
        final String label;

        public Label(String label) {
            this.label = label;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);
            buf.append(label).append(':');
        }
    }

    public static class SwitchStmt
            implements Statement {
        final Opcodes.Op op;
        final int[] hashKeys;
        final Block[] lables;
        final Block dflt;

        public SwitchStmt(Opcodes.Op op, int[] hashKeys) {
            this.op = op;
            this.hashKeys = hashKeys;
            this.lables = new Block[hashKeys.length];
            for (int i = 0; i < lables.length; i++) {
                lables[i] = new Block();
            }
            this.dflt = new Block();
        }

        public int labels() {
            return lables.length;
        }

        public Block label(int index) {
            return lables[index];
        }

        public int labelKey(int index) {
            return hashKeys[index];
        }

        public Block dflt() {
            return dflt;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);
            buf.append("switch (");
            op.toString(mw, buf, indent);
            buf.append(") {\n");

            for (int i = 0; i < lables.length; i++) {
                indent++;

                mw.ident(buf, indent);

                indent++;

                List statements = lables[i].statements;
                boolean brace = statements.stream().anyMatch(e -> e instanceof DeclareStmt);

                buf.append("case ").append(hashKeys[i]);
                if (brace) {
                    buf.append(": {\n");
                } else {
                    buf.append(":\n");
                }

                for (int j = 0; j < statements.size(); j++) {
                    if (j != 0) {
                        buf.append('\n');
                    }
                    statements.get(j).toString(mw, buf, indent);
                }

                buf.append('\n');
                indent--;

                if (brace) {
                    mw.ident(buf, indent);
                    buf.append("}\n");
                }

                indent--;
            }

            indent++;
            mw.ident(buf, indent);

            List statements = dflt.statements;
            boolean brace = statements.stream().anyMatch(e -> e instanceof DeclareStmt);

            if (brace) {
                buf.append("default : {\n");
            } else {
                buf.append("default :\n");
            }

            indent++;
            for (int j = 0; j < statements.size(); j++) {
                if (j != 0) {
                    buf.append('\n');
                }
                statements.get(j).toString(mw, buf, indent);
            }

            if (!statements.isEmpty()) {
                buf.append('\n');
            }
            mw.ident(buf, indent);
            buf.append("break;\n");
            indent--;

            if (brace) {
                mw.ident(buf, indent);
                buf.append("}\n");
            }

            indent--;

            mw.ident(buf, indent);
            buf.append("}");
        }
    }

    public static class ForStmt
            extends Block
            implements Statement {
        final Class initType;
        final Opcodes.Op init;
        final Opcodes.Op condition;
        final Opcodes.Op increment;

        public ForStmt(Class initType, Opcodes.Op init, Opcodes.Op condition, Opcodes.Op increment) {
            this.initType = initType;
            this.init = init;
            this.condition = condition;
            this.increment = increment;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);
            buf.append("for (");
            if (initType != null) {
                buf.append(initType.getSimpleName()).append(' ');
            }
            if (init != null) {
                init.toString(mw, buf, indent);
            }
            buf.append(';');
            if (condition != null) {
                buf.append(' ');
                condition.toString(mw, buf, indent);
            }
            buf.append(';');
            if (increment != null) {
                buf.append(' ');
                increment.toString(mw, buf, indent);
            }
            buf.append(") {\n");

            for (int i = 0; i < statements.size(); i++) {
                if (i != 0) {
                    buf.append('\n');
                }
                Statement stmt = statements.get(i);
                stmt.toString(mw, buf, indent + 1);
            }

            buf.append('\n');
            mw.ident(buf, indent);
            buf.append("}");
        }
    }

    public static class WhileStmt
            extends Block
            implements Statement {
        final Opcodes.Op condition;
        public WhileStmt(Opcodes.Op condition) {
            this.condition = condition;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);
            buf.append("while (");
            condition.toString(mw, buf, indent);
            buf.append(") {\n");

            for (int i = 0; i < statements.size(); i++) {
                if (i != 0) {
                    buf.append('\n');
                }
                Statement stmt = statements.get(i);
                stmt.toString(mw, buf, indent + 1);
            }

            buf.append('\n');
            mw.ident(buf, indent);
            buf.append("}");
        }
    }

    public static class DeclareStmt
            implements Statement {
        public final String type;
        public final Opcodes.OpName name;
        public final Opcodes.Op initValue;

        public DeclareStmt(String type, Opcodes.OpName name, Opcodes.Op initValue) {
            this.type = type;
            this.name = name;
            this.initValue = initValue;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);
            buf.append(type).append(' ');
            buf.append(name.name);
            if (initValue != null) {
                if (type.length() >= 16) {
                    buf.append('\n');
                    mw.ident(buf, indent + 2);
                    buf.append("= ");
                } else {
                    buf.append(" = ");
                }
                initValue.toString(mw, buf, indent);
            }
            buf.append(';');
        }
    }

    public static class StatementOp
            implements Statement {
        public final Opcodes.Op op;

        StatementOp(Opcodes.Op op) {
            this.op = op;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);
            op.toString(mw, buf, indent);
            buf.append(';');
        }
    }

    public static class StatementRet
            implements Statement {
        public final Opcodes.Op op;

        public StatementRet(Opcodes.Op op) {
            this.op = op;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);

            buf.append("return");
            if (op != null) {
                buf.append(' ');
                op.toString(mw, buf, indent);
            }
            buf.append(';');
        }
    }

    public static class StatementContinue
            implements Statement {
        public final String label;

        public StatementContinue(String label) {
            this.label = label;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);

            buf.append("continue");
            if (label != null) {
                buf.append(' ');
                buf.append(label);
            }
            buf.append(';');
        }
    }

    public static class StatementBreak
            implements Statement {
        public final String label;

        public StatementBreak(String label) {
            this.label = label;
        }

        public void toString(MethodWriter mw, StringBuilder buf, int indent) {
            mw.ident(buf, indent);

            buf.append("break");
            if (label != null) {
                buf.append(' ');
                buf.append(label);
            }
            buf.append(';');
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy