Java tutorial
/* * Copyright (c) 2009-2010 Ken Wenzel and Mathias Doenitz * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.parboiled.transform.process; import com.github.fge.grappa.transform.CodeBlock; import com.github.fge.grappa.transform.LoadingOpcode; import me.qmx.jitescript.util.CodegenUtils; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.VarInsnNode; import org.parboiled.common.Factory; import org.parboiled.transform.InstructionGraphNode; import org.parboiled.transform.InstructionGroup; import org.parboiled.transform.ParserClassNode; import org.parboiled.transform.RuleMethod; import javax.annotation.Nonnull; import java.util.Objects; import static org.objectweb.asm.Opcodes.DUP; import static org.objectweb.asm.Opcodes.PUTFIELD; /** * Inserts action group class instantiation code at the groups respective * placeholders. */ public final class RuleMethodRewriter implements RuleMethodProcessor { private RuleMethod method; private int actionNr = 0; private int varInitNr = 0; @Override public boolean appliesTo(@Nonnull final ParserClassNode classNode, @Nonnull final RuleMethod method) { Objects.requireNonNull(classNode, "classNode"); Objects.requireNonNull(method, "method"); return method.containsExplicitActions() || method.containsVars(); } @Override public void process(@Nonnull final ParserClassNode classNode, @Nonnull final RuleMethod method) throws Exception { this.method = Objects.requireNonNull(method, "method"); actionNr = 0; varInitNr = 0; for (final InstructionGroup group : method.getGroups()) { createNewGroupClassInstance(group); initializeFields(group); final InstructionGraphNode root = group.getRoot(); final AbstractInsnNode rootInsn = root.getInstruction(); if (root.isActionRoot()) method.instructions.remove(rootInsn); else // if (root.isVarInitRoot()) // TODO: replace with Supplier ((MethodInsnNode) rootInsn).desc = CodegenUtils.sig(void.class, Factory.class); } method.setBodyRewritten(); } private void createNewGroupClassInstance(final InstructionGroup group) { final String internalName = group.getGroupClassType().getInternalName(); final InstructionGraphNode root = group.getRoot(); final AbstractInsnNode rootInsn = root.getInstruction(); final InsnList insnList = method.instructions; final String constant = method.name + (root.isActionRoot() ? "_Action" + ++actionNr : "_VarInit" + ++varInitNr); final CodeBlock block = CodeBlock.newCodeBlock(); block.newobj(internalName).dup().ldc(constant).invokespecial(internalName, "<init>", CodegenUtils.sig(void.class, String.class)); if (root.isActionRoot() && method.hasSkipActionsInPredicatesAnnotation()) block.dup().invokevirtual(internalName, "setSkipInPredicates", CodegenUtils.sig(void.class)); insnList.insertBefore(rootInsn, block.getInstructionList()); } private void initializeFields(final InstructionGroup group) { final String internalName = group.getGroupClassType().getInternalName(); InsnList insnList; AbstractInsnNode rootInsn; int opcode; VarInsnNode varNode; FieldInsnNode fieldNode; for (final FieldNode field : group.getFields()) { insnList = method.instructions; rootInsn = group.getRoot().getInstruction(); // TODO: replace with method in CodeBlock? opcode = LoadingOpcode.forType((Type) field.value); varNode = new VarInsnNode(opcode, field.access); fieldNode = new FieldInsnNode(PUTFIELD, internalName, field.name, field.desc); insnList.insertBefore(rootInsn, new InsnNode(DUP)); // the FieldNodes access and value members have been reused for the // var index / Type respectively! insnList.insertBefore(rootInsn, varNode); insnList.insertBefore(rootInsn, fieldNode); } } }