/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (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.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */

#ifndef _JS_TOKEN_STREAM_H_
#define _JS_TOKEN_STREAM_H_

#include "js-zonenew.h"
#include "js-linebuffer.h"
#include "js-scriptable.h"

#if !defined(TARGET_OS_VW)
#undef VOID
#endif

/* Classes */
class JSTokenStream: public JSZoneNew {
    friend class JSNativeGlobal;
    public:
	static	const int
        	TSF_NEWLINES	= 0x0001,  // tokenize newlines
        	TSF_FUNCTION	= 0x0002,  // scanning inside function body
        	TSF_RETURN_EXPR	= 0x0004,  // function has 'return expr;'
        	TSF_RETURN_VOID	= 0x0008,  // function has 'return;'
        	TSF_REGEXP	= 0x0010;  // looking for a regular expression

	static const int
		// start enum
		_ERROR	= -1, // well-known as the only code < EOF
		_EOF	= 0,  // end of file token - (not EOF_CHAR)
		EOL		= 1,  // end of line
		// Beginning here are interpreter bytecodes.
		// Their values must not exceed 127.
		POPV		= 2,
		ENTERWITH	= 3,
		LEAVEWITH	= 4,
		RETURN		= 5,
		GOTO		= 6,
		IFEQ		= 7,
		IFNE		= 8,
		DUP		= 9,
		SETNAME		= 10,
		BITOR		= 11,
		BITXOR		= 12,
		BITAND		= 13,
		EQ		= 14,
		NE		= 15,
		LT		= 16,
		LE		= 17,
		GT		= 18,
		GE		= 19,
		LSH		= 20,
		RSH		= 21,
		URSH		= 22,
		ADD		= 23,
		SUB		= 24,
		MUL		= 25,
		DIV		= 26,
		MOD		= 27,
		BITNOT		= 28,
		NEG		= 29,
		NEW		= 30,
		DELPROP		= 31,
		TYPEOF		= 32,
		NAMEINC		= 33,
		PROPINC		= 34,
		ELEMINC		= 35,
		NAMEDEC		= 36,
		PROPDEC		= 37,
		ELEMDEC		= 38,
		GETPROP		= 39,
		SETPROP		= 40,
		GETELEM		= 41,
		SETELEM		= 42,
		CALL		= 43,
		NAME		= 44,
		NUMBER		= 45,
		STRING		= 46,
#ifdef VX
		_ZERO		= 47,
#else
		ZERO		= 47,
#endif
		ONE		= 48,
#if defined(CYGWIN)
		__NULL	= 49,
#else /* !defined(CYGWIN) */
		_NULL	= 49,
#endif /* !defined(CYGWIN) */
		THIS		= 50,
		_FALSE		= 51,
		_TRUE		= 52,
		SHEQ		= 53,   // shallow equality (===)
		SHNE		= 54,   // shallow inequality (!==)
		CLOSURE		= 55,
		OBJECT		= 56,
		POP		= 57,
		POS		= 58,
		VARINC		= 59,
		VARDEC		= 60,
		BINDNAME	= 61,
		THROW		= 62,
		IN		= 63,
		INSTANCEOF	= 64,
		GOSUB		= 65,
		RETSUB		= 66,
		CALLSPECIAL	= 67,
		GETTHIS		= 68,
		NEWTEMP		= 69,
		USETEMP		= 70,
		GETBASE		= 71,
		GETVAR		= 72,
		SETVAR		= 73,
		UNDEFINED	= 74,
		TRY		= 75,
		ENDTRY		= 76,
		NEWSCOPE	= 77,
		TYPEOFNAME	= 78,
		ENUMINIT	= 79,
		ENUMNEXT	= 80,
		GETPROTO	= 81,
		GETPARENT	= 82,
		SETPROTO	= 83,
		SETPARENT	= 84,
		SCOPE		= 85,
		GETSCOPEPARENT = 86,
		JTHROW		= 87,
		// End of interpreter bytecodes
		SEMI		= 88,  // semicolon
		LB		= 89,  // left and right brackets
		RB		= 90,
		LC		= 91,  // left and right curlies (braces)
		RC		= 92,
		LP		= 93,  // left and right parentheses
		RP		= 94,
		COMMA		= 95,  // comma operator
		ASSIGN		= 96, // assignment ops (= += -= etc.)
		HOOK		= 97, // conditional (?:)
		COLON		= 98,
		OR		= 99, // logical or (||)
		AND		= 100, // logical and (&&)
		EQOP		= 101, // equality ops (== !=)
		RELOP		= 102, // relational ops (< <= > >=)
		SHOP		= 103, // shift ops (<< >> >>>)
		UNARYOP		= 104, // unary prefix operator
		INC		= 105, // increment/decrement (++ --)
		DEC		= 106,
		DOT		= 107, // member operator (.)
		PRIMARY		= 108, // true, false, null, this
		FUNCTION	= 109, // function keyword
		EXPORT		= 110, // export keyword
#ifdef VX
		_IMPORT		= 111, // import keyword
#else
		IMPORT		= 111, // import keyword
#endif
		IF		= 112, // if keyword
		ELSE		= 113, // else keyword
		SWITCH		= 114, // switch keyword
		CASE		= 115, // case keyword
		DEFAULT		= 116, // default keyword
		WHILE		= 117, // while keyword
		DO		= 118, // do keyword
		FOR		= 119, // for keyword
		BREAK		= 120, // break keyword
		CONTINUE	= 121, // continue keyword
		VAR		= 122, // var keyword
		WITH		= 123, // with keyword
		CATCH		= 124, // catch keyword
		FINALLY		= 125, // finally keyword
		RESERVED	= 126, // reserved keywords

		/** Added by Mike - these are JSOPs in the jsref, but I
		 * don't have them yet in the java implementation...
		 * so they go here.  Also whatever I needed.

		 * Most of these go in the 'op' field when returning
		 * more general token types, eg. 'DIV' as the op of
		 * 'ASSIGN'.
		 */
		NOP		= 127, // NOP
		NOT		= 128, // etc.
		PRE		= 129, // for INC, DEC nodes.
		POST		= 130,

		/**
		 * For JSOPs associated with keywords...
		 * eg. op = THIS; token = PRIMARY
		 */

		VOID		= 131,

		/* types used for the parse tree - these never get
		 * returned by the scanner.
		 */
		BLOCK		= 132, // statement block
		ARRAYLIT	= 133, // array literal
		OBJLIT		= 134, // object literal
		LABEL		= 135, // label
		TARGET		= 136,
		LOOP		= 137,
		ENUMDONE	= 138,
		EXPRSTMT	= 139,
		PARENT		= 140,
		CONVERT		= 141,
		JSR		= 142,
		NEWLOCAL	= 143,
		USELOCAL	= 144,
		SCRIPT		= 145,   // top-level node for entire script
		
		/**
		 * For the interpreted mode indicating a line number
		 * change in icodes.
		 */
		LINE		= 146,
#ifdef REUSE_LOCAL
		SOURCEFILE	= 147,
		DELTEMP		= 148;
#else
		SOURCEFILE	= 147;
#endif

		static const int	EOF_CHAR = -1;
    protected:
	static	jsString_t	*names;
	static	int		namesLength;

	JSLineBuffer	in;
	jsString_t	sourceName;
	jsString_t	line;
	JSScriptable	*scope;
	int		pushbackToken;
	int		tokenno;
	jsString_t	string;
	double		number;

	int		op;
#ifdef FASTER
	jsString_t	_string;
	jsString_t	regExp;
#endif

    public:
	int		flags;
	jsString_t	regExpFlags;

    protected:
	static	void	checkNames();
	static	jsBool_t
			isAlpha(int c);
	static	jsBool_t
			isDigit(int c);
	static	jsBool_t
			isXDigit(int c);
	static	jsBool_t
			isJSIdentifier(jsString_t s);
	static	int	digit(jsChar_t c, int radix);
	static	jsBool_t
			isJavaIdentifierPart(int c);
	static	jsBool_t
			isJavaIdentifierStart(int c);

	void	setString(JSContext *cx, jsString_t string);
	jsString_t
		tokenToString(JSContext *cx, int token);

    public:
	static	void	classInitialize();
	static	jsString_t
			tokenToName(int type);
	static	jsBool_t
			isJSSpace(int c);
	static	jsBool_t
			isJSLineTerminator(int c);

	JSTokenStream(JSContext *cx, JSReader *in, JSScriptable *scope,
		jsString_t sourceName, int lineno);
	virtual ~JSTokenStream() {
	}

	int	stringToKeyword(jsString_t name);
	JSScriptable *
		getScope();
	jsBool_t
		matchToken(JSContext *cx, int toMatch);
	void	clearPushback();
	void	ungetToken(JSContext *cx, int tt);
	int	peekToken(JSContext *cx);
	int	peekTokenSameLine(JSContext *cx);
	int	getToken(JSContext *cx);
	void	reportSyntaxError(JSContext *cx, jsString_t messageProperty,
			...);
	jsString_t
		getSourceName();
	int	getLineno();
	int	getOp();
	jsString_t
		getString();
	double	getNumber();
	jsString_t
		getLine(JSContext *cx);
	int	getOffset();
	int	getTokenno();
	jsBool_t
		eof();
	void	destroy(JSContext *cx);
} ;

/* Inlines */
inline jsString_t
JSTokenStream::getSourceName()
{
    return sourceName;
}
inline int
JSTokenStream::getLineno()
{
    return in.getLineno();
}
inline int
JSTokenStream::getOp()
{
    return op;
}
inline jsString_t
JSTokenStream::getString()
{
    return string;
}
inline double
JSTokenStream::getNumber()
{
    return number;
}
inline jsString_t
JSTokenStream::getLine(JSContext *cx)
{
    return in.getLine(cx);
}
inline int
JSTokenStream::getOffset()
{
    return in.getOffset();
}
inline int
JSTokenStream::getTokenno()
{
    return tokenno;
}
inline jsBool_t
JSTokenStream::eof()
{
    return in.eof();
}

#endif /* _JS_TOKEN_STREAM_H_ */

