// (c) 2007 David Holroyd

package uk.co.badgersinfoil.antlr.unicodeid;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.ibm.icu.lang.UCharacter;


public class UnicodeIdentifierGenerator {

	public static void main(String[] args) {
		UnicodeIdentifierGenerator gen = new UnicodeIdentifierGenerator();
		gen.gen();
		gen.emit(new PrintWriter(System.out));
	}

	private List idStartRanges = new ArrayList();
	private List idPartRanges = new ArrayList();

	private void gen() {
		int lastStart = -1;
		int lastPart = -1;
		for (int ch=0; ch<0xffff; ch++) {
			if (UCharacter.isUnicodeIdentifierStart(ch) || ch=='_') {
				if (lastStart == -1) {
					lastStart = ch;
				}
			} else {
				if (lastStart != -1) {
					idStartRanges.add(new Range(lastStart, ch-1));
					lastStart = -1;
				}
			}
			if (UCharacter.isUnicodeIdentifierPart(ch)) {
				if (lastPart == -1) {
					lastPart = ch;
				}
			} else {
				if (lastPart != -1) {
					idPartRanges.add(new Range(lastPart, ch-1));
					lastPart = -1;
				}
			}
		}
	}

	public void emit(PrintWriter out) {
		out.println("fragment UNICODE_IDENTIFIER_START");
		out.print("\t:\t");
		toTokenSyntax(idStartRanges, out);
		out.println();
		out.println("\t;");

		out.println("fragment UNICODE_IDENTIFIER_PART");
		out.print("\t:\t");
		toTokenSyntax(idPartRanges, out);
		out.println();
		out.println("\t;");

		out.flush();
	}

	private void toTokenSyntax(List ranges, PrintWriter out) {
		for (Iterator i=ranges.iterator(); i.hasNext(); ) {
			Range r = (Range)i.next();
			if (r.isSingleValue()) {
				out.print("'"+toUnicodeEscape(r.start)+"'");
			} else {
				out.print("'"+toUnicodeEscape(r.start)+"'..'"+toUnicodeEscape(r.stop)+"'");
			}
			if (i.hasNext()) {
				out.print(" | ");
			}
		}
	}

	private String toUnicodeEscape(int ch) {
		if (ch <= 0xf) {
			return "\\u000"+Integer.toHexString(ch);
		}
		if (ch <= 0xff) {
			return "\\u00"+Integer.toHexString(ch);
		}
		if (ch <= 0xfff) {
			return "\\u0"+Integer.toHexString(ch);
		}
		return "\\u"+Integer.toHexString(ch);
	}

	private static class Range {
		public int start, stop;
		public Range(int start, int stop) {
			this.start = start;  this.stop = stop;
		}
		public boolean isSingleValue() { return start==stop; }
	}
}