<commit_before>// Copyright (c) 2011, <NAME> (<EMAIL>)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package wyrl.io;

import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.math.BigInteger;
import java.util.*;

import wyautl.core.Automaton;
import wyautl.io.BinaryAutomataReader;
import wyautl.util.BigRational;
import wybs.io.BinaryInputStream;
import wybs.io.BinaryOutputStream;
import wyrl.core.Attribute;
import wyrl.core.Expr;
import wyrl.core.Pattern;
import wyrl.core.SpecFile;
import wyrl.core.Type;
import wyrl.core.Types;
import wyrl.core.SpecFile.RuleDecl;
import wyrl.util.*;
import static wyrl.core.Attribute.*;
import static wyrl.core.SpecFile.*;

public class NewJavaFileWriter {
	private PrintWriter out;
	
	public NewJavaFileWriter(Writer os) {
		this.out = new PrintWriter(os);
	}

	public NewJavaFileWriter(OutputStream os) {
		this.out = new PrintWriter(os);
	}

	public void write(SpecFile spec) throws IOException {			
		reset();
		translate(spec,spec);		
	}
	
	private void translate(SpecFile spec, SpecFile root) throws IOException {						
		PrintWriter saved = out;		
		
		if(root == spec) {			

			if (!spec.pkg.equals("")) {
				myOut("package " + spec.pkg + ";");
				myOut("");
			}
			
			writeImports();
			myOut("public final class " + spec.name + " {");
			
		}
		
		for (Decl d : spec.declarations) {
			if(d instanceof IncludeDecl) {
				IncludeDecl id = (IncludeDecl) d;
				SpecFile file = id.file;
				translate(file,root);				
			} else  if (d instanceof TermDecl) {
				translate((TermDecl) d);
			} else if (d instanceof RewriteDecl) {
				translate((RewriteDecl) d,root);
			} 
		}
		
		if(root == spec) {
			writeSchema(spec);
			writeTypeTests();
			writePatterns(spec);
			writeRuleArrays(spec);
			writeMainMethod();
		}
		
		if(root == spec) {			
			myOut("}");
			out.close();
		}
		
		out = saved;
	}

	/**
	 * Reset all global information before proceeding to write out another file.
	 */
	protected void reset() {
		termCounter = 0;		
		reductionCounter = 0;
		inferenceCounter = 0;
	}
	
	protected void writeImports() {
		myOut("import java.io.*;");
		myOut("import java.util.*;");
		myOut("import java.math.BigInteger;");
		myOut("import wyautl.util.BigRational;");
		myOut("import wyautl.io.*;");
		myOut("import wyautl.core.*;");
		myOut("import wyautl.rw.*;");
		myOut("import wyrl.core.*;");
		myOut("import wyrl.util.Runtime;");
		myOut("import wyrl.util.AbstractRewriteRule;");
		myOut("import wyrl.util.Pair;");
		myOut();
	}
	
	public void translate(TermDecl decl) {
		myOut(1, "// term " + decl.type);
		String name = decl.type.name();
		myOut(1, "public final static int K_" + name + " = "
				+ termCounter++ + ";");
		if (decl.type.element() == null) {
			myOut(1, "public final static Automaton.Term " + name
					+ " = new Automaton.Term(K_" + name + ");");
		} else {
			Type.Ref data = decl.type.element();
			Type element = data.element();
			if(element instanceof Type.Collection) {
				// add two helpers
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, int... r0) {" );
				if(element instanceof Type.Set) { 
					myOut(2,"int r1 = automaton.add(new Automaton.Set(r0));");
				} else if(element instanceof Type.Bag) {
					myOut(2,"int r1 = automaton.add(new Automaton.Bag(r0));");
				} else {
					myOut(2,"int r1 = automaton.add(new Automaton.List(r0));");
				}
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
				
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, List<Integer> r0) {" );
				if(element instanceof Type.Set) { 
					myOut(2,"int r1 = automaton.add(new Automaton.Set(r0));");
				} else if(element instanceof Type.Bag) {
					myOut(2,"int r1 = automaton.add(new Automaton.Bag(r0));");
				} else {
					myOut(2,"int r1 = automaton.add(new Automaton.List(r0));");
				}
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else if(element instanceof Type.Int) {
				// add two helpers
				myOut(1, "public final static int " + name 
						+ "(Automaton automaton, long r0) {" );			
				myOut(2,"int r1 = automaton.add(new Automaton.Int(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
				
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, BigInteger r0) {" );	
				myOut(2,"int r1 = automaton.add(new Automaton.Int(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else if(element instanceof Type.Real) {
				// add two helpers
				myOut(1, "public final static int " + name 
						+ "(Automaton automaton, long r0) {" );			
				myOut(2,"int r1 = automaton.add(new Automaton.Real(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
				
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, BigRational r0) {" );	
				myOut(2,"int r1 = automaton.add(new Automaton.Real(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else if(element instanceof Type.Strung) {
				// add two helpers
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, String r0) {" );	
				myOut(2,"int r1 = automaton.add(new Automaton.Strung(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else {
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, " + type2JavaType(data) + " r0) {" );			
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r0));");
				myOut(1,"}");
			}
			
		}
		myOut();
	}

	private int termCounter = 0;
	private int reductionCounter = 0;
	private int inferenceCounter = 0;

	public void translate(RewriteDecl decl, SpecFile file) {		
		register(decl.pattern);
		
		boolean isReduction = decl instanceof ReduceDecl;
		Type param = decl.pattern.attribute(Attribute.Type.class).type; 
		myOut(1, "// " + decl.pattern);
		
		if (isReduction) {
			myOut(1, "private final static class Reduction_" + reductionCounter
					+ " extends AbstractRewriteRule implements ReductionRule {");
		} else {
			myOut(1, "private final static class Inference_" + inferenceCounter
					+ " extends AbstractRewriteRule implements InferenceRule {");
		}

		// ===============================================
		// Constructor
		// ===============================================

		myOut();
		if(isReduction) {			
			myOut(2, "public Reduction_" + reductionCounter++ + "(Pattern pattern) { super(pattern,SCHEMA); }");
		} else {
			myOut(2, "public Inference_" + inferenceCounter++ + "(Pattern pattern) { super(pattern,SCHEMA); }");
		}

		// ===============================================
		// Probe
		// ===============================================
		myOut();

		myOut(2,"public final void probe(Automaton automaton, int root, List<Activation> activations) {");
		Environment environment = new Environment();
		int thus = environment.allocate(param,"this");
		myOut(3,  "int r" + thus + " = root;");		
		int level = translatePatternMatch(3,decl.pattern,thus,environment);
		
		// Add the appropriate activation
		indent(level);out.print("int[] state = {");		
		for(int i=0;i!=environment.size();++i) {	
			Pair<Type, String> t = environment.get(i);
			if (t.first() == Type.T_VOID()) {
				// In this case, we have allocated a temporary variable which
				// should not be loaded into the activation state.
				continue;
			}
			if(i != 0) { out.print(", "); }
			out.print("r" + i);			
		}
		out.println("};");
		
		myOut(level,"activations.add(new Activation(this,null,state));");
		
		// close the pattern match
		while(level > 2) { myOut(--level,"}"); }
		
		// ===============================================
		// Apply
		// ===============================================
		
		myOut();
		
		myOut(2,"public final boolean apply(Automaton automaton, Object _state) {");
		myOut(3,"int[] state = (int[]) _state;");
		
		// first, unpack the state
		myOut(3,  "int r" + thus + " = state[0];");
		environment = new Environment();
		thus = environment.allocate(param,"this");
		
		for(Pair<String,Type> p : decl.pattern.declarations()) {
			String name = p.first();
			Type type = p.second();
			int index = environment.allocate(type,name);
			myOut(3, type2JavaType(type) + " r" + index + " = ("
					+ type2JavaType(type,false) + ") state[" + index + "]; // " + name);
		}
		// second, translate the individual rules
		for(RuleDecl rd : decl.rules) {
			translate(3,rd,isReduction,environment,file);
		}
		
		myOut(3,"return false;");
		myOut(2,"}");
		
		myOut(1,"}"); // end class		
	}

	/**
	 * Translate the test to see whether a pattern is accepted or not. A key
	 * requirement of this translation procedure is that it does not allocate
	 * *any* memory during the process.
	 * 
	 * @param pattern
	 *            The pattern being translated
	 * @param freeRegister
	 *            The next available free register.
	 * @return The next available free register after this translation.
	 */
	protected int translatePatternMatch(int level, Pattern pattern, int source,
			Environment environment) {
		if (pattern instanceof Pattern.Leaf) {
			return translatePatternMatch(level, (Pattern.Leaf) pattern, source,
					environment);
		} else if (pattern instanceof Pattern.Term) {
			return translatePatternMatch(level, (Pattern.Term) pattern, source,
					environment);
		} else if (pattern instanceof Pattern.BagOrSet) {
			return translatePatternMatch(level, (Pattern.BagOrSet) pattern, source,
					environment);
		} else {
			return translatePatternMatch(level, (Pattern.List) pattern, source,
					environment);
		}
	}
	
	public int translatePatternMatch(int level, Pattern.Leaf pattern,
			int source, Environment environment) {
		Type element = pattern.type().element();
		if (element == Type.T_ANY()) {
			// In this very special case, we don't need to do anything.
			return level;
		} else {
			int typeIndex = register(pattern.type);
			myOut(level++, "if(Runtime.accepts(type" + typeIndex
					+ ",automaton,automaton.get(r" + source + "), SCHEMA)) {");
			return level;
		}
	}
	
	public int translatePatternMatch(int level, Pattern.Term pattern,
			int source, Environment environment) {
		myOut(level, "Automaton.State s" + source + " = automaton.get(r"
				+ source + ");");
		myOut(level++, "if(s" + source + ".kind == K_" + pattern.name + ") {");
		myOut(level, "Automaton.Term t" + source + " = (Automaton.Term) s"
				+ source + ";");		
		if (pattern.data != null) {
			int target = environment.allocate(Type.T_ANY(), pattern.variable);
			myOut(level, "int r" + target + " = t" + source + ".contents;");
			return translatePatternMatch(level, pattern.data, target,
					environment);
		} else {
			return level;
		}
	}
	
	public int translatePatternMatch(int level, Pattern.List pattern, int source, Environment environment) {
		myOut(level, "Automaton.State s" + source + " = automaton.get(r"
				+ source + ");");
		myOut(level++, "if(s" + source + " instanceof Automaton.List) {");
		myOut(level, "Automaton.List l" + source + " = (Automaton.List) s"
				+ source + ";");
		
		Pair<Pattern, String>[] elements = pattern.elements;
		for (int i = 0; i != elements.length; ++i) {
			Pair<Pattern, String> p = elements[i];
			Pattern pat = p.first();			
			if(pattern.unbounded && (i+1) == elements.length) {
				int element = environment.allocate(Type.T_VOID());
				String idx = "i" + source;
				myOut(level,"boolean m" + source + " = true;");
				myOut(level++, "for(int " + idx + "=" + i + "; " + idx + " < l"
						+ source + ".size(); " + idx + "++) {");
				myOut(level, "int r" + element + " = l"
						+ source + ".get(" + idx + ");");
				int myLevel = level;
				level = translatePatternMatch(level, pat, element, environment);
				if(myLevel != level) {
					myOut(level,"continue;");
					myOut(--level,"} else { m" + source + "=false; break; }");
				}
				while(level >= myLevel) { myOut(--level,"}"); }
				myOut(level++,"if(m" + source + ") {");
			} else {				
				int element = environment.allocate(Type.T_ANY());
				myOut(level, "int r" + element + " = l"
						+ source + ".get(" + i + ");");
				level = translatePatternMatch(level, pat, element, environment);
			}			
		}
		
		return level;
	}
	
	public int translatePatternMatch(int level, Pattern.BagOrSet pattern, int source, Environment environment) {
		myOut(level, "Automaton.State s" + source + " = automaton.get(r"
				+ source + ");");
		if(pattern instanceof Pattern.Bag) { 
			myOut(level++, "if(s" + source + " instanceof Automaton.Bag) {");
		} else {
			myOut(level++, "if(s" + source + " instanceof Automaton.Set) {");
		}
		myOut(level, "Automaton.Collection c" + source + " = (Automaton.Collection) s"
				+ source + ";");
		
		// construct a for-loop for each fixed element to match
		Pair<Pattern, String>[] elements = pattern.elements;
		int[] indices = new int[elements.length];
		for (int i = 0; i != elements.length; ++i) {
			boolean isUnbounded = pattern.unbounded && (i+1) == elements.length;
			Pair<Pattern, String> p = elements[i];
			Pattern pat = p.first();
			int index = environment.allocate(isUnbounded ? Type.T_VOID() : Type.T_ANY());
			String idx = "i" + index;
			indices[i] = index;			
			if(isUnbounded) { myOut(level,"boolean m" + i + " = true;"); }
			myOut(level++,"for(int " + idx + "=0;" + idx + "!=c" + source + ".size();++" + idx + ") {");			
			if(i != 0) {
				indent(level);out.print("if(");
				// check against earlier indices
				for(int j=0;j<i;++j) {
					if(j!=0) {
						out.print(" || ");
					}
					out.print(idx + " == i" + indices[j]);
				}
				out.println(") { continue; }");
			}
			myOut(level, "int r" + index + " = c" + source + ".get(" + idx + ");");
			int myLevel = level;<commit_msg>WYRL: making progress.  A long way to go though.<commit_after>// Copyright (c) 2011, <NAME> (<EMAIL>)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package wyrl.io;

import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.math.BigInteger;
import java.util.*;

import wyautl.core.Automaton;
import wyautl.io.BinaryAutomataReader;
import wyautl.util.BigRational;
import wybs.io.BinaryInputStream;
import wybs.io.BinaryOutputStream;
import wyrl.core.Attribute;
import wyrl.core.Expr;
import wyrl.core.Pattern;
import wyrl.core.SpecFile;
import wyrl.core.Type;
import wyrl.core.Types;
import wyrl.core.SpecFile.RuleDecl;
import wyrl.util.*;
import static wyrl.core.Attribute.*;
import static wyrl.core.SpecFile.*;

public class NewJavaFileWriter {
	private PrintWriter out;
	
	public NewJavaFileWriter(Writer os) {
		this.out = new PrintWriter(os);
	}

	public NewJavaFileWriter(OutputStream os) {
		this.out = new PrintWriter(os);
	}

	public void write(SpecFile spec) throws IOException {			
		reset();
		translate(spec,spec);		
	}
	
	private void translate(SpecFile spec, SpecFile root) throws IOException {						
		PrintWriter saved = out;		
		
		if(root == spec) {			

			if (!spec.pkg.equals("")) {
				myOut("package " + spec.pkg + ";");
				myOut("");
			}
			
			writeImports();
			myOut("public final class " + spec.name + " {");
			
		}
		
		for (Decl d : spec.declarations) {
			if(d instanceof IncludeDecl) {
				IncludeDecl id = (IncludeDecl) d;
				SpecFile file = id.file;
				translate(file,root);				
			} else  if (d instanceof TermDecl) {
				translate((TermDecl) d);
			} else if (d instanceof RewriteDecl) {
				translate((RewriteDecl) d,root);
			} 
		}
		
		if(root == spec) {
			writeSchema(spec);
			writeTypeTests();
			writePatterns(spec);
			writeRuleArrays(spec);
			writeMainMethod();
		}
		
		if(root == spec) {			
			myOut("}");
			out.close();
		}
		
		out = saved;
	}

	/**
	 * Reset all global information before proceeding to write out another file.
	 */
	protected void reset() {
		termCounter = 0;		
		reductionCounter = 0;
		inferenceCounter = 0;
	}
	
	protected void writeImports() {
		myOut("import java.io.*;");
		myOut("import java.util.*;");
		myOut("import java.math.BigInteger;");
		myOut("import wyautl.util.BigRational;");
		myOut("import wyautl.io.*;");
		myOut("import wyautl.core.*;");
		myOut("import wyautl.rw.*;");
		myOut("import wyrl.core.*;");
		myOut("import wyrl.util.Runtime;");
		myOut("import wyrl.util.AbstractRewriteRule;");
		myOut("import wyrl.util.Pair;");
		myOut();
	}
	
	public void translate(TermDecl decl) {
		myOut(1, "// term " + decl.type);
		String name = decl.type.name();
		myOut(1, "public final static int K_" + name + " = "
				+ termCounter++ + ";");
		if (decl.type.element() == null) {
			myOut(1, "public final static Automaton.Term " + name
					+ " = new Automaton.Term(K_" + name + ");");
		} else {
			Type.Ref data = decl.type.element();
			Type element = data.element();
			if(element instanceof Type.Collection) {
				// add two helpers
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, int... r0) {" );
				if(element instanceof Type.Set) { 
					myOut(2,"int r1 = automaton.add(new Automaton.Set(r0));");
				} else if(element instanceof Type.Bag) {
					myOut(2,"int r1 = automaton.add(new Automaton.Bag(r0));");
				} else {
					myOut(2,"int r1 = automaton.add(new Automaton.List(r0));");
				}
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
				
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, List<Integer> r0) {" );
				if(element instanceof Type.Set) { 
					myOut(2,"int r1 = automaton.add(new Automaton.Set(r0));");
				} else if(element instanceof Type.Bag) {
					myOut(2,"int r1 = automaton.add(new Automaton.Bag(r0));");
				} else {
					myOut(2,"int r1 = automaton.add(new Automaton.List(r0));");
				}
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else if(element instanceof Type.Int) {
				// add two helpers
				myOut(1, "public final static int " + name 
						+ "(Automaton automaton, long r0) {" );			
				myOut(2,"int r1 = automaton.add(new Automaton.Int(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
				
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, BigInteger r0) {" );	
				myOut(2,"int r1 = automaton.add(new Automaton.Int(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else if(element instanceof Type.Real) {
				// add two helpers
				myOut(1, "public final static int " + name 
						+ "(Automaton automaton, long r0) {" );			
				myOut(2,"int r1 = automaton.add(new Automaton.Real(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
				
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, BigRational r0) {" );	
				myOut(2,"int r1 = automaton.add(new Automaton.Real(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else if(element instanceof Type.Strung) {
				// add two helpers
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, String r0) {" );	
				myOut(2,"int r1 = automaton.add(new Automaton.Strung(r0));");
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r1));");
				myOut(1,"}");
			} else {
				myOut(1, "public final static int " + name
						+ "(Automaton automaton, " + type2JavaType(data) + " r0) {" );			
				myOut(2,"return automaton.add(new Automaton.Term(K_" + name + ", r0));");
				myOut(1,"}");
			}
			
		}
		myOut();
	}

	private int termCounter = 0;
	private int reductionCounter = 0;
	private int inferenceCounter = 0;

	public void translate(RewriteDecl decl, SpecFile file) {		
		register(decl.pattern);
		
		boolean isReduction = decl instanceof ReduceDecl;
		Type param = decl.pattern.attribute(Attribute.Type.class).type; 
		myOut(1, "// " + decl.pattern);
		
		if (isReduction) {
			myOut(1, "private final static class Reduction_" + reductionCounter
					+ " extends AbstractRewriteRule implements ReductionRule {");
		} else {
			myOut(1, "private final static class Inference_" + inferenceCounter
					+ " extends AbstractRewriteRule implements InferenceRule {");
		}

		// ===============================================
		// Constructor
		// ===============================================

		myOut();
		if(isReduction) {			
			myOut(2, "public Reduction_" + reductionCounter++ + "(Pattern pattern) { super(pattern,SCHEMA); }");
		} else {
			myOut(2, "public Inference_" + inferenceCounter++ + "(Pattern pattern) { super(pattern,SCHEMA); }");
		}

		// ===============================================
		// Probe
		// ===============================================
		myOut();

		myOut(2,"public final void probe(Automaton automaton, int root, List<Activation> activations) {");
		Environment environment = new Environment();
		int thus = environment.allocate(param,"this");
		myOut(3,  "int r" + thus + " = root;");		
		int level = translatePatternMatch(3,decl.pattern,thus,environment);
		
		// Add the appropriate activation
		indent(level);out.print("int[] state = {");		
		for(int i=0;i!=environment.size();++i) {	
			Pair<Type, String> t = environment.get(i);
			if (t.first() == Type.T_VOID()) {
				// In this case, we have allocated a temporary variable which
				// should not be loaded into the activation state.
				continue;
			}
			if(i != 0) { out.print(", "); }
			out.print("r" + i);			
		}
		out.println("};");
		
		myOut(level,"activations.add(new Activation(this,null,state));");
		
		// close the pattern match
		while(level > 2) { myOut(--level,"}"); }
		
		// ===============================================
		// Apply
		// ===============================================
		
		myOut();
		
		myOut(2,"public final boolean apply(Automaton automaton, Object _state) {");
		myOut(3,"int[] state = (int[]) _state;");
		
		// first, unpack the state
		myOut(3,  "int r" + thus + " = state[0];");
		environment = new Environment();
		thus = environment.allocate(param,"this");
		
		for(Pair<String,Type> p : decl.pattern.declarations()) {
			String name = p.first();
			Type type = p.second();
			int index = environment.allocate(type,name);
			myOut(3, type2JavaType(type) + " r" + index + " = ("
					+ type2JavaType(type,false) + ") state[" + index + "]; // " + name);
		}
		// second, translate the individual rules
		for(RuleDecl rd : decl.rules) {
			translate(3,rd,isReduction,environment,file);
		}
		
		myOut(3,"return false;");
		myOut(2,"}");
		
		myOut(1,"}"); // end class		
	}

	/**
	 * Translate the test to see whether a pattern is accepted or not. A key
	 * requirement of this translation procedure is that it does not allocate
	 * *any* memory during the process.
	 * 
	 * @param pattern
	 *            The pattern being translated
	 * @param freeRegister
	 *            The next available free register.
	 * @return The next available free register after this translation.
	 */
	protected int translatePatternMatch(int level, Pattern pattern, int source,
			Environment environment) {
		if (pattern instanceof Pattern.Leaf) {
			return translatePatternMatch(level, (Pattern.Leaf) pattern, source,
					environment);
		} else if (pattern instanceof Pattern.Term) {
			return translatePatternMatch(level, (Pattern.Term) pattern, source,
					environment);
		} else if (pattern instanceof Pattern.BagOrSet) {
			return translatePatternMatch(level, (Pattern.BagOrSet) pattern, source,
					environment);
		} else {
			return translatePatternMatch(level, (Pattern.List) pattern, source,
					environment);
		}
	}
	
	public int translatePatternMatch(int level, Pattern.Leaf pattern,
			int source, Environment environment) {
		Type element = pattern.type().element();
		if (element == Type.T_ANY()) {
			// In this very special case, we don't need to do anything.
			return level;
		} else {
			int typeIndex = register(pattern.type);
			myOut(level++, "if(Runtime.accepts(type" + typeIndex
					+ ",automaton,automaton.get(r" + source + "), SCHEMA)) {");
			return level;
		}
	}
	
	public int translatePatternMatch(int level, Pattern.Term pattern,
			int source, Environment environment) {
		myOut(level, "Automaton.State s" + source + " = automaton.get(r"
				+ source + ");");
		myOut(level++, "if(s" + source + ".kind == K_" + pattern.name + ") {");
		myOut(level, "Automaton.Term t" + source + " = (Automaton.Term) s"
				+ source + ";");		
		if (pattern.data != null) {
			int target = environment.allocate(Type.T_ANY(), pattern.variable);
			myOut(level, "int r" + target + " = t" + source + ".contents;");
			return translatePatternMatch(level, pattern.data, target,
					environment);
		} else {
			return level;
		}
	}
	
	public int translatePatternMatch(int level, Pattern.List pattern, int source, Environment environment) {
		myOut(level, "Automaton.State s" + source + " = automaton.get(r"
				+ source + ");");
		myOut(level++, "if(s" + source + " instanceof Automaton.List) {");
		myOut(level, "Automaton.List l" + source + " = (Automaton.List) s"
				+ source + ";");
		
		Pair<Pattern, String>[] elements = pattern.elements;
		for (int i = 0; i != elements.length; ++i) {
			Pair<Pattern, String> p = elements[i];
			Pattern pat = p.first();			
			if(pattern.unbounded && (i+1) == elements.length) {
				int element = environment.allocate(Type.T_VOID());
				String idx = "i" + source;
				myOut(level,"boolean m" + source + " = true;");
				myOut(level++, "for(int " + idx + "=" + i + "; " + idx + " < l"
						+ source + ".size(); " + idx + "++) {");
				myOut(level, "int r" + element + " = l"
						+ source + ".get(" + idx + ");");
				int myLevel = level;
				level = translatePatternMatch(level, pat, element, environment);
				if(myLevel != level) {
					myOut(level,"continue;");
					myOut(--level,"} else { m" + source + "=false; break; }");
				}
				while(level >= myLevel) { myOut(--level,"}"); }
				myOut(level++,"if(m" + source + ") {");
			} else {				
				int element = environment.allocate(Type.T_ANY());
				myOut(level, "int r" + element + " = l"
						+ source + ".get(" + i + ");");
				level = translatePatternMatch(level, pat, element, environment);
			}			
		}
		
		return level;
	}
	
	public int translatePatternMatch(int level, Pattern.BagOrSet pattern, int source, Environment environment) {
		myOut(level, "Automaton.State s" + source + " = automaton.get(r"
				+ source + ");");
		if(pattern instanceof Pattern.Bag) { 
			myOut(level++, "if(s" + source + " instanceof Automaton.Bag) {");
		} else {
			myOut(level++, "if(s" + source + " instanceof Automaton.Set) {");
		}
		myOut(level, "Automaton.Collection c" + source + " = (Automaton.Collection) s"
				+ source + ";");
		
		// construct a for-loop for each fixed element to match
		Pair<Pattern, String>[] elements = pattern.elements;
		int[] indices = new int[elements.length];
		for (int i = 0; i != elements.length; ++i) {
			boolean isUnbounded = pattern.unbounded && (i+1) == elements.length;
			Pair<Pattern, String> p = elements[i];
			Pattern pat = p.first();
			int index = environment.allocate(isUnbounded ? Type.T_VOID() : Type.T_ANY());
			String idx = "i" + index;
			indices[i] = index;			
			if(isUnbounded) { myOut(level,"boolean m" + i + " = true;"); }
			
			// TODO: at some point here, we want to check whether or not it's
			// actually worth having a loop in the unbounded case. Specifically,
			// when the type being matched is any then we can just drop the loop
			// altogether.
			
			myOut(level++,"for(int " + idx + "=0;" + idx + "!=c" + source + ".size();++" + idx + ") {");			
			if(i != 0) {
				indent(level);out.print("if(");
				// check against earlier indices
				for(int j=0;j<i;++j) {
					if(j!=0) {
						out.print(" || ");
					}
					out.print(idx + " == i" + indices[j]);
				}
				out.println(") { continue; }");
			}
			myOut(level, "int r" + index + " = c" + source + ".get(" + idx + ");");
			int myLevel = level;
{'fraction_non_alphanumeric': 0.17249230374551053, 'fraction_numerical': 0.007503848127244741, 'mean_word_length': 3.419642857142857, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, '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': '4815853', 'n_tokens_mistral': 11670, 'n_tokens_neox': 9812, 'n_words': 2649}