<commit_before>package wyil.lang;

import java.util.ArrayList;

import wyautl.lang.*;

/**
 * <p>
 * This simplification rule converts a type into <i>conjunctive normal form</i>.
 * This is achieved by repeated application of the following rewrites:
 * </p>
 * <ol>
 * <li><code>T | void</code> => <code>T</code>.</li>
 * <li><code>T | any</code> => <code>any</code>.</li>
 * <li><code>T & void</code> => <code>void</code>.</li>
 * <li><code>T & any</code> => <code>T</code>.</li>
 * <li><code>X<T | X></code> => <code>T</code>.</li>
 * <li><code>X<T & X></code> => <code>void</code>.</li>
 * <li><code>!!T</code> => <code>T</code>.</li>
 * <li><code>!any</code> => <code>void</code>.</li>
 * <li><code>!void</code> => <code>any</code>.</li>
 * <li><code>!(T_1 | T_2)</code> => <code>!T_1 & !T_2</code>.</li>
 * <li><code>!(T_1 & T_2)</code> => <code>!T_1 | !T_2</code>.</li>
 * <li><code>(T_1 | T_2) | T_3</code> => <code>(T_1 | T_2 | T_3)</code>.</li>
 * <li><code>(T_1 & T_2) & T_3</code> => <code>(T_1 & T_2 & T_3)</code>.</li>
 * <li><code>T_1 & (T_2|T_3)</code> => <code>(T_1 & T_2) | (T_1 & T_3)</code>.</li>
 * <li><code>[T_1] & [T_2] & T_3</code> => <code>[T_1 & T_2] & T_3)</code>.</li>
 * <li><code>![T_1] & ![T_2] & T_3</code> => <code>![T_1 | T_2] & T_3)</code>.</li>
 * <li><code>[T_1] & {T_2}</code> => <code>void</code>.</li>
 * </ol>
 * <p>
 * <b>NOTE:</b> applications of this rewrite rule may leave states which are
 * unreachable from the root. Therefore, the resulting automata should be
 * extracted after rewriting to eliminate any such states.
 * </p>
 * 
 * @author djp
 * 
 */
public final class ConjunctiveNormalForm implements RewriteRule {

	public final boolean apply(int index, Automata automata) {
		Automata.State state = automata.states[index];
		switch (state.kind) {
			case Type.K_UNION :
				return applyUnion(index, state, automata);
			case Type.K_INTERSECTION :
				return applyIntersection(index, state, automata);
			case Type.K_NEGATION :
				return applyNot(index, state, automata);
		}
		return false;
	}

	public boolean applyNot(int index, Automata.State state, Automata automata) {
		int childIndex = state.children[0];
		Automata.State child = automata.states[childIndex];
		switch (child.kind) {
			case Type.K_ANY :
				automata.states[index] = new Automata.State(Type.K_VOID);
				return true;
			case Type.K_VOID :
				automata.states[index] = new Automata.State(Type.K_ANY);
				return true;
			case Type.K_NEGATION :
				// bypass this node altogether
				int childChildIndex = child.children[0];
				Automata.State childChild = automata.states[childChildIndex];
				automata.states[index] = new Automata.State(childChild);
				return true;
			case Type.K_UNION :
			case Type.K_INTERSECTION : {
				int[] child_children = child.children;
				int[] nchildren = new int[child_children.length];
				Automata.State[] nstates = new Automata.State[child_children.length];
				for (int i = 0; i != child_children.length; ++i) {
					int[] children = new int[1];
					children[0] = child_children[i];
					nchildren[i] = i + automata.size();
					nstates[i] = new Automata.State(Type.K_NEGATION, children);
				}
				Automatas.inplaceAppendAll(automata, nstates);<commit_msg>Bug fix for compound types.<commit_after>package wyil.lang;

import java.util.ArrayList;

import wyautl.lang.*;

/**
 * <p>
 * This simplification rule converts a type into <i>conjunctive normal form</i>.
 * This is achieved by repeated application of the following rewrites:
 * </p>
 * <ol>
 * <li><code>T | void</code> => <code>T</code>.</li>
 * <li><code>T | any</code> => <code>any</code>.</li>
 * <li><code>T & void</code> => <code>void</code>.</li>
 * <li><code>T & any</code> => <code>T</code>.</li>
 * <li><code>X<T | X></code> => <code>T</code>.</li>
 * <li><code>X<T & X></code> => <code>void</code>.</li>
 * <li><code>!!T</code> => <code>T</code>.</li>
 * <li><code>!any</code> => <code>void</code>.</li>
 * <li><code>!void</code> => <code>any</code>.</li>
 * <li><code>!(T_1 | T_2)</code> => <code>!T_1 & !T_2</code>.</li>
 * <li><code>!(T_1 & T_2)</code> => <code>!T_1 | !T_2</code>.</li>
 * <li><code>(T_1 | T_2) | T_3</code> => <code>(T_1 | T_2 | T_3)</code>.</li>
 * <li><code>(T_1 & T_2) & T_3</code> => <code>(T_1 & T_2 & T_3)</code>.</li>
 * <li><code>T_1 & (T_2|T_3)</code> => <code>(T_1 & T_2) | (T_1 & T_3)</code>.</li>
 * <li><code>[T_1] & [T_2] & T_3</code> => <code>[T_1 & T_2] & T_3)</code>.</li>
 * <li><code>![T_1] & ![T_2] & T_3</code> => <code>![T_1 | T_2] & T_3)</code>.</li>
 * <li><code>[T_1] & {T_2}</code> => <code>void</code>.</li>
 * </ol>
 * <p>
 * <b>NOTE:</b> applications of this rewrite rule may leave states which are
 * unreachable from the root. Therefore, the resulting automata should be
 * extracted after rewriting to eliminate any such states.
 * </p>
 * 
 * @author djp
 * 
 */
public final class ConjunctiveNormalForm implements RewriteRule {

	public final boolean apply(int index, Automata automata) {
		Automata.State state = automata.states[index];
		switch (state.kind) {
			case Type.K_UNION :
				return applyUnion(index, state, automata);
			case Type.K_INTERSECTION :
				return applyIntersection(index, state, automata);
			case Type.K_NEGATION :
				return applyNot(index, state, automata);
			case Type.K_DICTIONARY:
			case Type.K_RECORD:
			case Type.K_TUPLE:
			case Type.K_FUNCTION:
			case Type.K_METHOD:
			case Type.K_HEADLESS:
				return applyCompound(index, state, automata);
		}
		return false;
	}

	public boolean applyCompound(int index, Automata.State state, Automata automata) {
		int kind = state.kind;
		int[] children = state.children;
		for(int i=0;i<children.length;++i) {
			if(i == 0 && kind == Type.K_HEADLESS) {
				// headless method return type allowed to be void
				continue;				
			} else if(i == 1 && kind == Type.K_METHOD) {
				// method return type allowed to be void
				continue;
			}
			Automata.State child = automata.states[children[i]];
			if(child.kind == Type.K_VOID) {
				automata.states[index] = new Automata.State(Type.K_VOID);
				return true;
			}			
		}
		return false;
	}
	
	public boolean applyNot(int index, Automata.State state, Automata automata) {
		int childIndex = state.children[0];
		Automata.State child = automata.states[childIndex];
		switch (child.kind) {
			case Type.K_ANY :
				automata.states[index] = new Automata.State(Type.K_VOID);
				return true;
			case Type.K_VOID :
				automata.states[index] = new Automata.State(Type.K_ANY);
				return true;
			case Type.K_NEGATION :
				// bypass this node altogether
				int childChildIndex = child.children[0];
				Automata.State childChild = automata.states[childChildIndex];
				automata.states[index] = new Automata.State(childChild);
				return true;
			case Type.K_UNION :
			case Type.K_INTERSECTION : {
				int[] child_children = child.children;
				int[] nchildren = new int[child_children.length];
				Automata.State[] nstates = new Automata.State[child_children.length];
				for (int i = 0; i != child_children.length; ++i) {
					int[] children = new int[1];
					children[0] = child_children[i];
					nchildren[i] = i + automata.size();
					nstates[i] = new Automata.State(Type.K_NEGATION, children);
				}
				Automatas.inplaceAppendAll(automata, nstates);
{'fraction_non_alphanumeric': 0.19270976616231086, 'fraction_numerical': 0.013067400275103164, 'mean_word_length': 3.7553956834532376, 'pattern_counts': {'":': 0, '<': 232, '<?xml version=': 0, '>': 265, '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': '963626', 'n_tokens_mistral': 3030, 'n_tokens_neox': 2748, 'n_words': 573}