package me.august.lumen.compile.parser.ast; import me.august.lumen.common.ModifierSet; import me.august.lumen.compile.analyze.ASTVisitor; import me.august.lumen.compile.analyze.VisitorConsumer; import me.august.lumen.compile.codegen.BuildContext; import me.august.lumen.compile.codegen.ClassCodeGen; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ClassNode implements ClassCodeGen, VisitorConsumer { private ModifierSet modifiers; private String name; private Typed superClass; private String[] interfaces; private List<FieldNode> fields = new ArrayList<>(); private List<MethodNode> methods = new ArrayList<>(); public ClassNode(String name, Typed superClass, String[] interfaces, ModifierSet modifiers) { this.name = name; this.superClass = superClass; this.interfaces = interfaces; this.modifiers = modifiers; } @Override public void generate(ClassVisitor visitor, BuildContext context) { visitor.visit( context.classVersion(), modifiers.getValue(), name, null, superClass.getResolvedType().getInternalName(), interfaces ); generateDefaultConstructor(visitor); for (FieldNode field : fields) field.generate(visitor, context); for (MethodNode method : methods) method.generate(visitor, context); } private void generateDefaultConstructor(ClassVisitor visitor) { MethodVisitor method = visitor.visitMethod( Opcodes.ACC_PUBLIC, "<init>", "()V", null, null ); // load `this` method.visitVarInsn(Opcodes.ALOAD, 0); method.visitMethodInsn( Opcodes.INVOKESPECIAL, superClass.getResolvedType().getInternalName(), "<init>", "()V", false ); method.visitInsn(Opcodes.RETURN); method.visitMaxs(1, 1); method.visitEnd(); } @Override public void accept(ASTVisitor visitor) { visitor.visitClass(this); fields.forEach(visitor::visitField); for (MethodNode method : methods) { method.accept(visitor); } visitor.visitClassEnd(this); } @Override public String toString() { return "ClassNode{" + "modifiers=" + modifiers + ", name='" + name + '\'' + ", superClass='" + superClass + '\'' + ", interfaces=" + Arrays.toString(interfaces) + ", fields=" + fields + ", methods=" + methods + '}'; } public List<FieldNode> getFields() { return fields; } public List<MethodNode> getMethods() { return methods; } public ModifierSet getModifiers() { return modifiers; } public String getName() { return name; } public Typed getSuperClass() { return superClass; } public String[] getInterfaces() { return interfaces; } public void setSuperClass(Typed superClass) { this.superClass = superClass; } }