<commit_before>package org.strategoxt.imp.runtime.stratego;

import static java.lang.Math.max;
import static org.spoofax.jsglr.client.imploder.ImploderAttachment.hasImploderOrigin;
import static org.spoofax.terms.Term.isTermList;
import static org.spoofax.terms.Term.tryGetConstructor;
import static org.spoofax.terms.attachments.OriginAttachment.tryGetOrigin;
import static org.spoofax.terms.attachments.ParentAttachment.getParent;

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

import org.spoofax.interpreter.terms.IStrategoAppl;
import org.spoofax.interpreter.terms.IStrategoConstructor;
import org.spoofax.interpreter.terms.IStrategoList;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.jsglr.client.imploder.ImploderAttachment;
import org.spoofax.jsglr.client.imploder.TermTreeFactory;
import org.spoofax.terms.TermFactory;
import org.spoofax.terms.TermVisitor;
import org.spoofax.terms.attachments.ParentAttachment;
import org.strategoxt.imp.generator.generator;
import org.strategoxt.imp.generator.position_of_term_1_0;
import org.strategoxt.imp.generator.term_at_position_0_1;
import org.strategoxt.imp.runtime.Environment;
import org.spoofax.terms.StrategoSubList;
import org.strategoxt.imp.runtime.services.ContentProposer;
import org.strategoxt.imp.runtime.services.ContentProposerSemantic;
import org.strategoxt.lang.Context;
import org.strategoxt.lang.Strategy;
import org.strategoxt.stratego_aterm.explode_aterm_0_0;
import org.strategoxt.stratego_aterm.implode_aterm_0_0;
import org.strategoxt.stratego_lib.assert_1_0;
import org.strategoxt.stratego_lib.oncetd_1_0;

/**
 * Maintains aterm paths, lists of nodes on the path to the root from a given AST node.
 * 
 * @author <NAME> <lennart add lclnet.nl>
 */
public class StrategoTermPath {

	private StrategoTermPath() {
		// Constructed by a static constructor
	}
	
	public static IStrategoList createPath(IStrategoTerm node) {
		List<Integer> pathInts=createPathList(node);
		return toStrategoPath(pathInts);
	}

	public static IStrategoList toStrategoPath(List<Integer> pathInts) {
		LinkedList<IStrategoTerm> results = new LinkedList<IStrategoTerm>();
		for (int i = 0; i < pathInts.size(); i++) {
			results.add(Environment.getTermFactory().makeInt(pathInts.get(i)));
		}
		return Environment.getTermFactory().makeList(results);
	}
	
	public static List<Integer> createPathList(IStrategoTerm node) {
		if (node instanceof StrategoSubList)
			node = ((StrategoSubList) node).getCompleteList();
		LinkedList<Integer> results = new LinkedList<Integer>();
		
		while (getParent(node) != null) {
			IStrategoTerm parent = getParent(node);
			int index = indexOfIdentical(parent, node);
			results.addFirst(Integer.valueOf(index));
			node = getParent(node);
		}
		return results;
	}
	
	/**
	 * Creates a term path given the AST Node of a parsed IStrategoTerm file.
	 * The resulting path relates to the actual AST, ignoring the 'appl' etc constructors
	 * of the IStrategoTerm syntax.
	 */
	public static IStrategoList createPathFromParsedIStrategoTerm(final IStrategoTerm node, Context context) {
		IStrategoTerm top = ParentAttachment.getRoot(node);
		final IStrategoTerm marker = context.getFactory().makeString(ContentProposerSemantic.COMPLETION_TOKEN);
		top = oncetd_1_0.instance.invoke(context, top, new Strategy() {
			@Override
			public IStrategoTerm invoke(Context context, IStrategoTerm current) {
				if (hasImploderOrigin(current) && tryGetOrigin(current) == node) {
					return explode_aterm_0_0.instance.invoke(context, marker);
				} else {
					return null;
				}
			}
		});
		top = implode_aterm_0_0.instance.invoke(context, top);
		return (IStrategoList) position_of_term_1_0.instance.invoke(context, top, new Strategy() {
			@Override
			public IStrategoTerm invoke(Context context, IStrategoTerm current) {
				return marker.equals(current) ? current : null;
			}
		});
	}
	
	/**
	 * Determine the path to a term in 'ast' with origin 'origin'.
	 */
	public static IStrategoList getTermPathWithOrigin(Context context, IStrategoTerm ast, IStrategoTerm origin) {
		if (ast == null)
			return null;
		if (isTermList(origin)) {
			// Lists have no origin information, try to find the node by its first child.
			if (origin.getSubtermCount() > 0) {
				IStrategoList subtermPath = getTermPathWithOrigin(context, ast, origin.getSubterm(0));
				if (subtermPath != null){
					// Arrays.copyOf is Java 1.6
					//IStrategoTerm[] originPath = Arrays.copyOf(subtermPath.getAllSubterms(), subtermPath.getSubtermCount()-1);
					IStrategoTerm[] allSubterms = subtermPath.getAllSubterms();
					IStrategoTerm[] originPath = new IStrategoTerm[subtermPath.getSubtermCount()-1];
					System.arraycopy(allSubterms, 0, originPath, 0, originPath.length);
					TermFactory factory = new TermFactory();
					return factory.makeList(originPath);
				}
			}
			return null;
		}
		
		final IStrategoTerm originChild = origin.getSubtermCount() == 0
				? null
				: (IStrategoTerm) origin.getSubterm(0);
		
		class TestOrigin extends Strategy {
			IStrategoTerm origin1;
			IStrategoTerm nextBest;
			
			@Override
			public IStrategoTerm invoke(Context context, IStrategoTerm current) {
				if (hasImploderOrigin(current)) {
					IStrategoTerm currentOrigin = tryGetOrigin(current);
					if (currentOrigin == origin1) return current;
					IStrategoTerm currentImploderOrigin = ImploderAttachment.getImploderOrigin(currentOrigin);
					IStrategoTerm imploderOrigin1 = ImploderAttachment.getImploderOrigin(origin1);
					if (	
							currentImploderOrigin != null &&
							imploderOrigin1 != null &&
							ImploderAttachment.getLeftToken(currentImploderOrigin).getStartOffset() == ImploderAttachment.getLeftToken(imploderOrigin1).getStartOffset() &&
							ImploderAttachment.getRightToken(currentImploderOrigin).getEndOffset() == ImploderAttachment.getRightToken(imploderOrigin1).getEndOffset()
					){
						if(currentOrigin.equals(origin1))
							return current; 
						if(current.getTermType() == origin1.getTermType()){
							if(current.getTermType() == IStrategoTerm.APPL){
								IStrategoAppl currentAppl = (IStrategoAppl)current;
								IStrategoAppl origin1Appl = (IStrategoAppl)origin1;
								if(currentAppl.getName().equals(origin1Appl.getName()) && currentAppl.getSubtermCount() == origin1Appl.getSubtermCount())
									return current;
							}
							nextBest = current;							
						}
					}
					// sets a term as 'nextBest' if one of the subterms of its origin-term is the originChild
					if (nextBest == null && originChild != null) {
						for (int i = 0, max = currentOrigin.getSubtermCount(); i < max; i++)
							if (currentOrigin.getSubterm(i) == originChild)
								nextBest = currentOrigin;
					}
				}
				else { // sets a term as 'nextBest' in case no origin term exists, but one of its subterms is origin-related to the originChild
					if (current == origin1) return current;
					if (nextBest == null && originChild != null) {
						for (int i = 0, max = current.getSubtermCount(); i < max; i++)
							if (tryGetOrigin(current.getSubterm(i)) == originChild)
								nextBest = current;
					}					
				}
				return null;
			}
		}
		TestOrigin testOrigin = new TestOrigin();
		testOrigin.origin1 = origin;		
		generator.init(context);
		IStrategoTerm perfectMatch = position_of_term_1_0.instance.invoke(context, ast, testOrigin);
		if (perfectMatch != null) {
			return (IStrategoList) perfectMatch;
		} else if (testOrigin.nextBest != null) {
			Environment.logWarning("Could not determine term corresponding to " + origin.toString() + " in resulting AST; using next best match " + testOrigin.nextBest);
			testOrigin.origin1 = testOrigin.nextBest;
			return (IStrategoList) position_of_term_1_0.instance.invoke(context, ast, testOrigin);
		} else {
			Environment.logWarning("Could not determine term corresponding to " + origin.toString() + " in resulting AST");
			return null;
		}
	}

	public static IStrategoTerm getTermAtPath(Context context, IStrategoTerm term, IStrategoList path) {
		return term_at_position_0_1.instance.invoke(context, term, path);
	}

	private static int indexOfIdentical(IStrategoTerm parent, IStrategoTerm node) {
		int index = 0;
		for (int size = parent.getSubtermCount(); index < size; index++) {
			if (parent.getSubterm(index) == node) break;
		}<commit_msg>Suppress "Could not determine term corresponding to..." warnings. They uncessarily clutter the error log (IMHO).<commit_after>package org.strategoxt.imp.runtime.stratego;

import static java.lang.Math.max;
import static org.spoofax.jsglr.client.imploder.ImploderAttachment.hasImploderOrigin;
import static org.spoofax.terms.Term.isTermList;
import static org.spoofax.terms.Term.tryGetConstructor;
import static org.spoofax.terms.attachments.OriginAttachment.tryGetOrigin;
import static org.spoofax.terms.attachments.ParentAttachment.getParent;

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

import org.spoofax.interpreter.terms.IStrategoAppl;
import org.spoofax.interpreter.terms.IStrategoConstructor;
import org.spoofax.interpreter.terms.IStrategoList;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.jsglr.client.imploder.ImploderAttachment;
import org.spoofax.jsglr.client.imploder.TermTreeFactory;
import org.spoofax.terms.StrategoSubList;
import org.spoofax.terms.TermFactory;
import org.spoofax.terms.TermVisitor;
import org.spoofax.terms.attachments.ParentAttachment;
import org.strategoxt.imp.generator.generator;
import org.strategoxt.imp.generator.position_of_term_1_0;
import org.strategoxt.imp.generator.term_at_position_0_1;
import org.strategoxt.imp.runtime.Environment;
import org.strategoxt.imp.runtime.services.ContentProposerSemantic;
import org.strategoxt.lang.Context;
import org.strategoxt.lang.Strategy;
import org.strategoxt.stratego_aterm.explode_aterm_0_0;
import org.strategoxt.stratego_aterm.implode_aterm_0_0;
import org.strategoxt.stratego_lib.oncetd_1_0;

/**
 * Maintains aterm paths, lists of nodes on the path to the root from a given AST node.
 * 
 * @author <NAME> <lennart add lclnet.nl>
 */
public class StrategoTermPath {

	private StrategoTermPath() {
		// Constructed by a static constructor
	}
	
	public static IStrategoList createPath(IStrategoTerm node) {
		List<Integer> pathInts=createPathList(node);
		return toStrategoPath(pathInts);
	}

	public static IStrategoList toStrategoPath(List<Integer> pathInts) {
		LinkedList<IStrategoTerm> results = new LinkedList<IStrategoTerm>();
		for (int i = 0; i < pathInts.size(); i++) {
			results.add(Environment.getTermFactory().makeInt(pathInts.get(i)));
		}
		return Environment.getTermFactory().makeList(results);
	}
	
	public static List<Integer> createPathList(IStrategoTerm node) {
		if (node instanceof StrategoSubList)
			node = ((StrategoSubList) node).getCompleteList();
		LinkedList<Integer> results = new LinkedList<Integer>();
		
		while (getParent(node) != null) {
			IStrategoTerm parent = getParent(node);
			int index = indexOfIdentical(parent, node);
			results.addFirst(Integer.valueOf(index));
			node = getParent(node);
		}
		return results;
	}
	
	/**
	 * Creates a term path given the AST Node of a parsed IStrategoTerm file.
	 * The resulting path relates to the actual AST, ignoring the 'appl' etc constructors
	 * of the IStrategoTerm syntax.
	 */
	public static IStrategoList createPathFromParsedIStrategoTerm(final IStrategoTerm node, Context context) {
		IStrategoTerm top = ParentAttachment.getRoot(node);
		final IStrategoTerm marker = context.getFactory().makeString(ContentProposerSemantic.COMPLETION_TOKEN);
		top = oncetd_1_0.instance.invoke(context, top, new Strategy() {
			@Override
			public IStrategoTerm invoke(Context context, IStrategoTerm current) {
				if (hasImploderOrigin(current) && tryGetOrigin(current) == node) {
					return explode_aterm_0_0.instance.invoke(context, marker);
				} else {
					return null;
				}
			}
		});
		top = implode_aterm_0_0.instance.invoke(context, top);
		return (IStrategoList) position_of_term_1_0.instance.invoke(context, top, new Strategy() {
			@Override
			public IStrategoTerm invoke(Context context, IStrategoTerm current) {
				return marker.equals(current) ? current : null;
			}
		});
	}
	
	/**
	 * Determine the path to a term in 'ast' with origin 'origin'.
	 */
	public static IStrategoList getTermPathWithOrigin(Context context, IStrategoTerm ast, IStrategoTerm origin) {
		if (ast == null)
			return null;
		if (isTermList(origin)) {
			// Lists have no origin information, try to find the node by its first child.
			if (origin.getSubtermCount() > 0) {
				IStrategoList subtermPath = getTermPathWithOrigin(context, ast, origin.getSubterm(0));
				if (subtermPath != null){
					// Arrays.copyOf is Java 1.6
					//IStrategoTerm[] originPath = Arrays.copyOf(subtermPath.getAllSubterms(), subtermPath.getSubtermCount()-1);
					IStrategoTerm[] allSubterms = subtermPath.getAllSubterms();
					IStrategoTerm[] originPath = new IStrategoTerm[subtermPath.getSubtermCount()-1];
					System.arraycopy(allSubterms, 0, originPath, 0, originPath.length);
					TermFactory factory = new TermFactory();
					return factory.makeList(originPath);
				}
			}
			return null;
		}
		
		final IStrategoTerm originChild = origin.getSubtermCount() == 0
				? null
				: (IStrategoTerm) origin.getSubterm(0);
		
		class TestOrigin extends Strategy {
			IStrategoTerm origin1;
			IStrategoTerm nextBest;
			
			@Override
			public IStrategoTerm invoke(Context context, IStrategoTerm current) {
				if (hasImploderOrigin(current)) {
					IStrategoTerm currentOrigin = tryGetOrigin(current);
					if (currentOrigin == origin1) return current;
					IStrategoTerm currentImploderOrigin = ImploderAttachment.getImploderOrigin(currentOrigin);
					IStrategoTerm imploderOrigin1 = ImploderAttachment.getImploderOrigin(origin1);
					if (	
							currentImploderOrigin != null &&
							imploderOrigin1 != null &&
							ImploderAttachment.getLeftToken(currentImploderOrigin).getStartOffset() == ImploderAttachment.getLeftToken(imploderOrigin1).getStartOffset() &&
							ImploderAttachment.getRightToken(currentImploderOrigin).getEndOffset() == ImploderAttachment.getRightToken(imploderOrigin1).getEndOffset()
					){
						if(currentOrigin.equals(origin1))
							return current; 
						if(current.getTermType() == origin1.getTermType()){
							if(current.getTermType() == IStrategoTerm.APPL){
								IStrategoAppl currentAppl = (IStrategoAppl)current;
								IStrategoAppl origin1Appl = (IStrategoAppl)origin1;
								if(currentAppl.getName().equals(origin1Appl.getName()) && currentAppl.getSubtermCount() == origin1Appl.getSubtermCount())
									return current;
							}
							nextBest = current;							
						}
					}
					// sets a term as 'nextBest' if one of the subterms of its origin-term is the originChild
					if (nextBest == null && originChild != null) {
						for (int i = 0, max = currentOrigin.getSubtermCount(); i < max; i++)
							if (currentOrigin.getSubterm(i) == originChild)
								nextBest = currentOrigin;
					}
				}
				else { // sets a term as 'nextBest' in case no origin term exists, but one of its subterms is origin-related to the originChild
					if (current == origin1) return current;
					if (nextBest == null && originChild != null) {
						for (int i = 0, max = current.getSubtermCount(); i < max; i++)
							if (tryGetOrigin(current.getSubterm(i)) == originChild)
								nextBest = current;
					}					
				}
				return null;
			}
		}
		TestOrigin testOrigin = new TestOrigin();
		testOrigin.origin1 = origin;		
		generator.init(context);
		IStrategoTerm perfectMatch = position_of_term_1_0.instance.invoke(context, ast, testOrigin);
		if (perfectMatch != null) {
			return (IStrategoList) perfectMatch;
		} else if (testOrigin.nextBest != null) {
//			Environment.logWarning("Could not determine term corresponding to " + origin.toString() + " in resulting AST; using next best match " + testOrigin.nextBest);
			testOrigin.origin1 = testOrigin.nextBest;
			return (IStrategoList) position_of_term_1_0.instance.invoke(context, ast, testOrigin);
		} else {
//			Environment.logWarning("Could not determine term corresponding to " + origin.toString() + " in resulting AST");
			return null;
		}
	}

	public static IStrategoTerm getTermAtPath(Context context, IStrategoTerm term, IStrategoList path) {
		return term_at_position_0_1.instance.invoke(context, term, path);
	}

	private static int indexOfIdentical(IStrategoTerm parent, IStrategoTerm node) {
		int index = 0;
		for (int size = parent.getSubtermCount(); index < size; index++) {
			if (parent.getSubterm(index) == node) break;
		}
{'fraction_non_alphanumeric': 0.10335128665469778, 'fraction_numerical': 0.006582884500299222, 'mean_word_length': 4.4934253780407625, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 23, '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': '6820760', 'n_tokens_mistral': 6198, 'n_tokens_neox': 5333, 'n_words': 1150}