<commit_before>package org.metaborg.meta.lang.dynsem.interpreter.nodes.natives;

import org.metaborg.meta.lang.dynsem.interpreter.nodes.DynSemNode;
import org.metaborg.meta.lang.dynsem.interpreter.nodes.rules.DispatchNode;
import org.metaborg.meta.lang.dynsem.interpreter.nodes.rules.DispatchNodeGen;
import org.metaborg.meta.lang.dynsem.interpreter.nodes.rules.RuleResult;
import org.metaborg.meta.lang.dynsem.interpreter.utils.InterpreterUtils;
import org.metaborg.meta.lang.dynsem.interpreter.utils.SourceUtils;
import org.spoofax.interpreter.core.Tools;
import org.spoofax.interpreter.terms.IStrategoList;
import org.spoofax.interpreter.terms.IStrategoTerm;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.source.SourceSection;

public class DispatchInteropNode extends DynSemNode {

	private final FrameSlot[] inputComponents;
	private final FrameSlot[] outputComponents;
	@Child private DispatchNode dispatchInvokeNode;

	public DispatchInteropNode(SourceSection source, FrameSlot[] inComponents, FrameSlot[] outComponents) {
		super(source);
		this.inputComponents = inComponents;
		this.outputComponents = outComponents;
		this.dispatchInvokeNode = DispatchNodeGen.create(getSourceSection(), "");
	}

	public Object executeInterop(VirtualFrame frame, VirtualFrame components, Object inputTerm) {
		RuleResult result = dispatchInvokeNode.execute(frame, inputTerm.getClass(),
				createArgumentsArray(components, inputTerm));
		
		updateComponentSnapshot(components, result.components);
		
		return result.result;
	}

	@ExplodeLoop
	private Object[] createArgumentsArray(VirtualFrame components, Object inputTerm) {
		final Object[] args = new Object[inputComponents.length + 1];
		CompilerAsserts.compilationConstant(args.length);
		args[0] = inputTerm;
		for (int i = 0; i < inputComponents.length; i++) {
			InterpreterUtils.setComponent(getContext(), args, i + 1, components.getValue(inputComponents[i]));
		}
		return args;
	}

	/* FIXME: @ExplodeLoop
	 * it turns out that resultComps.length is NOT compilation constant
	 * FIXME: why is that?! this would suggest that sometimes the rule is that invoked differs in the number of output components
	 */
	private void updateComponentSnapshot(VirtualFrame components, Object[] resultComps) {
		assert resultComps.length == outputComponents.length;
//		CompilerAsserts.compilationConstant(resultComps.length);
		for (int i = 0; i < resultComps.length; i++) {
			components.setObject(outputComponents[i], resultComps[i]);<commit_msg>Fix loop explosion bug in Dispatch Interop Node<commit_after>package org.metaborg.meta.lang.dynsem.interpreter.nodes.natives;

import org.metaborg.meta.lang.dynsem.interpreter.nodes.DynSemNode;
import org.metaborg.meta.lang.dynsem.interpreter.nodes.rules.DispatchNode;
import org.metaborg.meta.lang.dynsem.interpreter.nodes.rules.DispatchNodeGen;
import org.metaborg.meta.lang.dynsem.interpreter.nodes.rules.RuleResult;
import org.metaborg.meta.lang.dynsem.interpreter.utils.InterpreterUtils;
import org.metaborg.meta.lang.dynsem.interpreter.utils.SourceUtils;
import org.spoofax.interpreter.core.Tools;
import org.spoofax.interpreter.terms.IStrategoList;
import org.spoofax.interpreter.terms.IStrategoTerm;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.source.SourceSection;

public class DispatchInteropNode extends DynSemNode {

	private final FrameSlot[] inputComponents;
	private final FrameSlot[] outputComponents;
	@Child private DispatchNode dispatchInvokeNode;

	public DispatchInteropNode(SourceSection source, FrameSlot[] inComponents, FrameSlot[] outComponents) {
		super(source);
		this.inputComponents = inComponents;
		this.outputComponents = outComponents;
		this.dispatchInvokeNode = DispatchNodeGen.create(getSourceSection(), "");
	}

	public Object executeInterop(VirtualFrame frame, VirtualFrame components, Object inputTerm) {
		RuleResult result = dispatchInvokeNode.execute(frame, inputTerm.getClass(),
				createArgumentsArray(components, inputTerm));
		
		updateComponentSnapshot(components, result.components);
		
		return result.result;
	}

	@ExplodeLoop
	private Object[] createArgumentsArray(VirtualFrame components, Object inputTerm) {
		final Object[] args = new Object[inputComponents.length + 1];
		CompilerAsserts.compilationConstant(args.length);
		args[0] = inputTerm;
		for (int i = 0; i < inputComponents.length; i++) {
			InterpreterUtils.setComponent(getContext(), args, i + 1, components.getValue(inputComponents[i]));
		}
		return args;
	}

	@ExplodeLoop
	private void updateComponentSnapshot(VirtualFrame components, Object[] resultComps) {
		assert resultComps.length == outputComponents.length;
		CompilerAsserts.compilationConstant(outputComponents.length);
		for (int i = 0; i < outputComponents.length; i++) {
			components.setObject(outputComponents[i], resultComps[i]);
{'fraction_non_alphanumeric': 0.10305560827481496, 'fraction_numerical': 0.0018978933383943823, 'mean_word_length': 6.258953168044077, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5534103', 'n_tokens_mistral': 1638, 'n_tokens_neox': 1572, 'n_words': 299}