package polyglot.lex;

import java.io.Reader;
import java.io.FilterReader;
import java.io.IOException;

/** A reader that translates escaped unicode into unicode characters. */
public class EscapedUnicodeReader extends FilterReader {

  int pushback=-1;
  boolean isEvenSlash = true;

  public EscapedUnicodeReader(Reader in) {
    super(in);
  }
  public int read() throws IOException {
    int r = (pushback==-1)?in.read():pushback; pushback=-1;
    
    if (r!='\\') {
      isEvenSlash=true;
      return r;
    } else { // found a backslash;
      if (!isEvenSlash) { // Only even slashes are eligible unicode escapes.
	isEvenSlash=true;
	return r;
      }
      
      // Check for the trailing u.
      pushback=in.read();
      if (pushback!='u') {
	isEvenSlash=false;
	return '\\';
      }

      // OK, we've found backslash-u.  
      // Reset pushback and snarf up all trailing u's.
      pushback=-1;
      while((r=in.read())=='u')
	;
      // Now we should find 4 hex digits. 
      // If we don't, we can raise bloody hell.
      int val=0;
      for (int i=0; i<4; i++, r=in.read()) {
	int d=Character.digit((char)r, 16);
	if (r<0 || d<0)
	  throw new Error("Invalid unicode escape character.");
	val = (val*16) + d;
      }
      // yeah, we made it.
      pushback = r;
      isEvenSlash=true;
      return val;
    }
  }
  // synthesize array read from single-character read.
  public int read(char cbuf[], int off, int len) throws IOException {
    for (int i=0; i<len; i++) {
      int c = read();
      if (c==-1) return (i==0)?-1:i; // end of stream reached.
      else cbuf[i+off] = (char) c;
    }
    return len;
  }

  public boolean markSupported() { return false; }

  public boolean ready() throws IOException {
    if (pushback!=-1) return true;
    else return in.ready();
  }
}

@@ -1148,18 +1148,417 @@
  %7C%7C d%3C0)
-%0A%09
+ %7B%0A            // invalid unicode character. Spend some time getting a %0A            // meaningful error message%0A            String code = %22%22;%0A            for (int j = 0; j %3C i; j++) %7B%0A                code = Character.forDigit(val %25 16, 16) + code;%0A                val = val/16;%0A            %7D%0A            for (; i%3C4; i++, r=in.read()) %7B%0A                code += ((char)r);%0A            %7D%0A            %0A%09  
   throw 
@@ -1565,13 +1565,19 @@
 new 
-Error
+IOException
 (%22In
@@ -1610,12 +1610,33 @@
 cter
-.%22);
+: %5C%5Cu%22 + code);%0A        %7D
 %0A%09va

Replace the Error thrown on an invalid unicode escape character with an IOException.