package som.interpreter;

import som.interpreter.nodes.ContextualNode;
import som.interpreter.nodes.ExpressionNode;
import som.interpreter.nodes.SOMNode;

import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.nodes.NodeVisitor;


public final class Inliner implements NodeVisitor {

  public static ExpressionNode doInline(
      final ExpressionNode body,
      final LexicalContext inlinedContext) {
    ExpressionNode inlinedBody = NodeUtil.cloneNode(body);
    inlinedBody.accept(new Inliner(inlinedContext));
    return inlinedBody;
  }

  private final LexicalContext inlinedContext;

  private Inliner(final LexicalContext inlinedContext) {
    this.inlinedContext = inlinedContext;
  }

  public LexicalContext getLexicalContext() {
    return inlinedContext;
  }

  @Override
  public boolean visit(final Node node) {
    prepareBodyNode(node);
    assert !(node instanceof Method);
    return true;
  }

  public FrameSlot getLocalFrameSlot(final Object slotId) {
    return inlinedContext.getFrameDescriptor().findFrameSlot(slotId);
  }

  public FrameSlot getFrameSlot(final ContextualNode node, final Object slotId) {
    return getFrameSlot(slotId, node.getContextLevel());
  }

  public FrameSlot getFrameSlot(final Object slotId, int level) {
    LexicalContext ctx = inlinedContext;
    while (level > 0) {
      ctx = ctx.getOuterContext();
      level--;
    }
    return ctx.getFrameDescriptor().findFrameSlot(slotId);
  }

  private void prepareBodyNode(final Node node) {
    if (node instanceof SOMNode) {
      ((SOMNode) node).replaceWithIndependentCopyForInlining(this);
    }
  }
}

@@ -387,16 +387,321 @@
 itor %7B%0A%0A
+  private static class DummyParent extends SOMNode %7B%0A    public DummyParent() %7B super(null); %7D%0A    @Child  private SOMNode child;%0A%0A    @Override%0A    public ExpressionNode getFirstMethodBodyNode() %7B return null; %7D%0A    public void adopt(final SOMNode child) %7B%0A        this.child = insert(child);%0A    %7D%0A  %7D%0A%0A
   public
@@ -870,16 +870,103 @@
 (body);%0A
+%0A    DummyParent dummyParent = new DummyParent();%0A    dummyParent.adopt(inlinedBody);%0A%0A
     inli

Add temporary dummy parent to enable replacement