/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.awk;

import java.io.IOException;
import java.io.StringReader;

import net.morilib.awk.misc.PushbackLineNumberReader;
import net.morilib.awk.parser.AwkAssignop;
import net.morilib.awk.parser.AwkFloatToken;
import net.morilib.awk.parser.AwkIntegerToken;
import net.morilib.awk.parser.AwkLexer;
import net.morilib.awk.parser.AwkOperator;
import net.morilib.awk.parser.AwkRelop;
import net.morilib.awk.parser.AwkReserved;
import net.morilib.awk.parser.AwkStringToken;
import net.morilib.awk.parser.AwkToken;
import net.morilib.awk.parser.AwkSymbol;

import junit.framework.TestCase;

public class AwkLexerTest extends TestCase {

	static PushbackLineNumberReader rds(String s) {
		return new PushbackLineNumberReader(new StringReader(s));
	}

	static void nt(PushbackLineNumberReader rd, AwkToken t) {
		try {
			assertEquals(AwkLexer.getToken(rd), t);
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	static void nt(PushbackLineNumberReader rd, long t, int r) {
		try {
			assertEquals(AwkLexer.getToken(rd),
					new AwkIntegerToken(Long.toString(t, r), r));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	static void nt(PushbackLineNumberReader rd, long t) {
		nt(rd, t, 10);
	}

	static void nt(PushbackLineNumberReader rd, double t) {
		try {
			assertEquals(AwkLexer.getToken(rd), new AwkFloatToken(t));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	static void nv(PushbackLineNumberReader rd, String s) {
		try {
			assertEquals(AwkLexer.getToken(rd),
					AwkSymbol.getInstance(s));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	static void ns(PushbackLineNumberReader rd, String s) {
		try {
			assertEquals(AwkLexer.getToken(rd),
					AwkStringToken.getInstance(s));
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
	}

	static void es(String s, String t) {
		assertEquals(t, AwkLexer.escape(s));
	}

	public void testEscape1() {
		es("\\a\\b\\f\\n\\r\\t\\v", "\u0007\u0008\u000c\n\r\u0009\u000b");
		es("\\077\\177\\x7f\\x00\\u007f",
				"\u003f\u007f\u007f\u0000\u007f");
		es("abc\\n", "abc\n");
		es("abc\\", "abc\\");
		es("abc\\07", "abc\\07");
		es("abc\\077", "abc\u003f");
		es("abc\\x0", "abc\\x0");
		es("abc\\x77", "abc\u0077");
		es("abc\\u007", "abc\\u007");
		es("abc\\u0077", "abc\u0077");
	}

	public void testEscape2() {
		es("\\088", "?");
		es("\\xgg", "?");
		es("\\u00gg", "?");
	}

	public void testLexer1() {
		PushbackLineNumberReader r = rds("{}?:()~");

		nt(r, AwkReserved.BLOCK_B);
		nt(r, AwkReserved.BLOCK_E);
		nt(r, AwkOperator.TRI1);
		nt(r, AwkOperator.TRI2);
		nt(r, AwkOperator.LPAREN);
		nt(r, AwkOperator.RPAREN);
		nt(r, AwkOperator.MATCH);
		nt(r, AwkReserved.ENDMARKER);
	}

	public void testLexer2() {
		PushbackLineNumberReader r = rds("1+2 - 3");

		nt(r, 1);
		nt(r, AwkOperator.ADD);
		nt(r, 2);
		nt(r, AwkOperator.SUB);
		nt(r, 3);
	}

//	public void testLexer3() {
//		PushbackLineNumberReader r = rds("print \"aaa\" \"\\\"\\n\\r\\b\" \"\"");
//
//		nv(r, "print");
//		ns(r, "aaa");
//		ns(r, "\"\n\r\b");
//		ns(r, "");
//	}

	public void testLexer4() {
		PushbackLineNumberReader r = rds("< > <= >= = == ! != !~ + ++ - -- * ^ / && ||");

		nt(r, AwkRelop.LT);  nt(r, AwkRelop.GT);
		nt(r, AwkRelop.LE);  nt(r, AwkRelop.GE);
		nt(r, AwkAssignop.ASSIGN);  nt(r, AwkRelop.EQ);
		nt(r, AwkOperator.L_NOT);   nt(r, AwkRelop.NE);
		nt(r, AwkOperator.NMATCH);
		nt(r, AwkOperator.ADD);  nt(r, AwkOperator.INC);
		nt(r, AwkOperator.SUB);  nt(r, AwkOperator.DEC);
		nt(r, AwkOperator.MUL);
		nt(r, AwkOperator.POW);
		nt(r, AwkOperator.DIV);
		nt(r, AwkOperator.L_AND);
		nt(r, AwkOperator.L_OR);
	}

	public void testLexer5() {
		PushbackLineNumberReader r = rds("+= -= *= /= ^=");

		nt(r, AwkAssignop.A_ADD);
		nt(r, AwkAssignop.A_SUB);
		nt(r, AwkAssignop.A_MUL);
		nt(r, AwkAssignop.A_DIV);
		nt(r, AwkAssignop.A_POW);
//		nt(r, AwkAssignop.A_B_AND);
//		nt(r, AwkAssignop.A_B_OR);
	}

	public void testLexer6() {
		PushbackLineNumberReader r = rds("if else for in do while break continue next exit");

		nt(r, AwkReserved.IF);
		nt(r, AwkReserved.ELSE);
		nt(r, AwkReserved.FOR);
		nt(r, AwkOperator.IN);
		nt(r, AwkReserved.DO);
		nt(r, AwkReserved.WHILE);
		nt(r, AwkReserved.BREAK);
		nt(r, AwkReserved.CONT);
		nt(r, AwkReserved.NEXT);
		nt(r, AwkReserved.EXIT);
	}

	public void testLexer7() {
		PushbackLineNumberReader r = rds("72 072 0x72 0xab 0xCD 0xEf");

		nt(r, 72, 10);
		nt(r, 072, 8);
		nt(r, 0x72, 16);
		nt(r, 0xab, 16);
		nt(r, 0xcd, 16);
		nt(r, 0xef, 16);
	}

	public void testLexer9() {
		PushbackLineNumberReader r = rds("3.14 1e7 1e+7 1e-7 3.1E7 3.1E-7");

		nt(r, 3.14);
		nt(r, 1e7);
		nt(r, 1e7);
		nt(r, 1e-7);
		nt(r, 3.1e7);
		nt(r, 3.1e-7);
	}

}
