diff dmdscript_tango/parse.d @ 0:55c2951c07be

initial, files origin, premoved tree
author saaadel
date Sun, 24 Jan 2010 12:34:47 +0200
parents
children 8363a4bf6a8f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/parse.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1427 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2005 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * www.digitalmars.com
+ * Use at your own risk. There is no warranty, express or implied.
+ * License for redistribution is by the GNU General Public License in gpl.txt.
+ *
+ * A binary, non-exclusive license for commercial use can be
+ * purchased from www.digitalmars.com/dscript/buy.html.
+ *
+ * DMDScript is implemented in the D Programming Language,
+ * www.digitalmars.com/d/
+ *
+ * For a C++ implementation of DMDScript, including COM support,
+ * see www.digitalmars.com/dscript/cppscript.html.
+ */
+
+
+module dmdscript.parse;
+
+import dmdscript.script;
+import dmdscript.lexer;
+import dmdscript.functiondefinition;
+import dmdscript.expression;
+import dmdscript.statement;
+import dmdscript.identifier;
+import dmdscript.ir;
+import dmdscript.errmsgs;
+
+class Parser : Lexer
+{
+    uint flags;
+
+    enum
+    {
+	normal		= 0,
+	initial		= 1,
+
+	allowIn		= 0,
+	noIn		= 2,
+
+	// Flag if we're in the for statement header, as
+	// automatic semicolon insertion is suppressed inside it.
+	inForHeader	= 4,
+    }
+
+    FunctionDefinition lastnamedfunc;
+
+
+    this(char[] sourcename, tchar[] base, int useStringtable)
+    {
+	//writefln("Parser.this(base = '%s')", base);
+	super(sourcename, base, useStringtable);
+	nextToken();		// start up the scanner
+    }
+
+    ~this()
+    {
+	lastnamedfunc = null;
+    }
+
+
+    /**********************************************
+     * Return !=0 on error, and fill in *perrinfo.
+     */
+
+    static int parseFunctionDefinition(out FunctionDefinition pfd,
+	    d_string params, d_string bdy, out ErrInfo perrinfo)
+    {
+	Parser p;
+	Identifier*[] parameters;
+	TopStatement[] topstatements;
+	FunctionDefinition fd = null;
+	int result;
+
+	p = new Parser("anonymous", params, 0);
+
+	// Parse FormalParameterList
+	while (p.token.value != TOKeof)
+	{
+	    if (p.token.value != TOKidentifier)
+	    {
+		p.error(errmsgtbl[ERR_FPL_EXPECTED_IDENTIFIER], p.token.toString());
+		goto Lreturn;
+	    }
+	    parameters ~= p.token.ident;
+	    p.nextToken();
+	    if (p.token.value == TOKcomma)
+		p.nextToken();
+	    else if (p.token.value == TOKeof)
+		break;
+	    else
+	    {
+		p.error(errmsgtbl[ERR_FPL_EXPECTED_COMMA], p.token.toString());
+		goto Lreturn;
+	    }
+	}
+	if (p.errinfo.message)
+	    goto Lreturn;
+
+	delete p;
+
+	// Parse StatementList
+	p = new Parser("anonymous", bdy, 0);
+	for (;;)
+	{   TopStatement ts;
+
+	    if (p.token.value == TOKeof)
+		break;
+	    ts = p.parseStatement();
+	    topstatements ~= ts;
+	}
+
+	fd = new FunctionDefinition(0, 0, null, parameters, topstatements);
+	fd.isanonymous = 1;
+
+    Lreturn:
+	pfd = fd;
+	perrinfo = p.errinfo;
+	result = (p.errinfo.message != null);
+	delete p;
+	p = null;
+	return result;
+    }
+
+    /**********************************************
+     * Return !=0 on error, and fill in *perrinfo.
+     */
+
+    int parseProgram(out TopStatement[] topstatements, ErrInfo *perrinfo)
+    {
+	topstatements = parseTopStatements();
+	check(TOKeof);
+	//writef("parseProgram done\n");
+	*perrinfo = errinfo;
+	//clearstack();
+	return errinfo.message != null;
+    }
+
+    TopStatement[] parseTopStatements()
+    {
+	TopStatement[] topstatements;
+	TopStatement ts;
+
+	//writefln("parseTopStatements()");
+	for (;;)
+	{
+	    switch (token.value)
+	    {
+		case TOKfunction:
+		    ts = parseFunction(0);
+		    topstatements ~= ts;
+		    break;
+
+		case TOKeof:
+		    return topstatements;
+
+		case TOKrbrace:
+		    return topstatements;
+
+		default:
+		    ts = parseStatement();
+		    topstatements ~= ts;
+		    break;
+	    }
+	}
+	assert(0);
+    }
+
+    /***************************
+     * flag:
+     *	0	Function statement
+     *	1	Function literal
+     */
+
+    TopStatement parseFunction(int flag)
+    {   Identifier* name;
+	Identifier*[] parameters;
+	TopStatement[] topstatements;
+	FunctionDefinition f;
+	Expression e = null;
+	Loc loc;
+
+	//writef("parseFunction()\n");
+	loc = currentline;
+	nextToken();
+	name = null;
+	if (token.value == TOKidentifier)
+	{
+	    name = token.ident;
+	    nextToken();
+
+	    if (!flag && token.value == TOKdot)
+	    {
+		// Regard:
+		//	function A.B() { }
+		// as:
+		//	A.B = function() { }
+		// This is not ECMA, but a jscript feature
+
+		e = new IdentifierExpression(loc, name);
+		name = null;
+
+		while (token.value == TOKdot)
+		{
+		    nextToken();
+		    if (token.value == TOKidentifier)
+		    {	e = new DotExp(loc, e, token.ident);
+			nextToken();
+		    }
+		    else
+		    {
+			error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_2PARAM], ".", token.toString());
+			break;
+		    }
+		}
+	    }
+	}
+
+	check(TOKlparen);
+	if (token.value == TOKrparen)
+	    nextToken();
+	else
+	{
+	    for (;;)
+	    {
+		if (token.value == TOKidentifier)
+		{
+		    parameters ~= token.ident;
+		    nextToken();
+		    if (token.value == TOKcomma)
+		    {   nextToken();
+			continue;
+		    }
+		    if (!check(TOKrparen))
+			break;
+		}
+		else
+		    error(ERR_EXPECTED_IDENTIFIER);
+		break;
+	    }
+	}
+
+	check(TOKlbrace);
+	topstatements = parseTopStatements();
+	check(TOKrbrace);
+
+	f = new FunctionDefinition(loc, 0, name, parameters, topstatements);
+
+	lastnamedfunc = f;
+
+	//writef("parseFunction() done\n");
+	if (!e)
+	    return f;
+
+	// Construct:
+	//	A.B = function() { }
+
+	Expression e2 = new FunctionLiteral(loc, f);
+
+	e = new AssignExp(loc, e, e2);
+
+	Statement s = new ExpStatement(loc, e);
+
+	return s;
+    }
+
+    /*****************************************
+     */
+
+    Statement parseStatement()
+    {   Statement s;
+	Token *t;
+	Loc loc;
+
+	//writefln("parseStatement()");
+	loc = currentline;
+	switch (token.value)
+	{
+	    case TOKidentifier:
+	    case TOKthis:
+		// Need to look ahead to see if it is a declaration, label, or expression
+		t = peek(&token);
+		if (t.value == TOKcolon && token.value == TOKidentifier)
+		{   // It's a label
+		    Identifier *ident;
+
+		    ident = token.ident;
+		    nextToken();
+		    nextToken();
+		    s = parseStatement();
+		    s = new LabelStatement(loc, ident, s);
+		}
+		else if (t.value == TOKassign ||
+			 t.value == TOKdot ||
+			 t.value == TOKlbracket)
+		{   Expression exp;
+
+		    exp = parseExpression();
+		    parseOptionalSemi();
+		    s = new ExpStatement(loc, exp);
+		}
+		else
+		{   Expression exp;
+
+		    exp = parseExpression(initial);
+		    parseOptionalSemi();
+		    s = new ExpStatement(loc, exp);
+		}
+		break;
+
+	    case TOKreal:
+	    case TOKstring:
+	    case TOKdelete:
+	    case TOKlparen:
+	    case TOKplusplus:
+	    case TOKminusminus:
+	    case TOKplus:
+	    case TOKminus:
+	    case TOKnot:
+	    case TOKtilde:
+	    case TOKtypeof:
+	    case TOKnull:
+	    case TOKnew:
+	    case TOKtrue:
+	    case TOKfalse:
+	    case TOKvoid:
+	    {   Expression exp;
+
+		exp = parseExpression(initial);
+		parseOptionalSemi();
+		s = new ExpStatement(loc, exp);
+		break;
+	    }
+
+	    case TOKvar:
+	    {
+		Identifier *ident;
+		Expression init;
+		VarDeclaration v;
+		VarStatement vs;
+
+		vs = new VarStatement(loc);
+		s = vs;
+
+		nextToken();
+		for (;;)
+		{   loc = currentline;
+
+		    if (token.value != TOKidentifier)
+		    {
+			error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_PARAM], token.toString());
+			break;
+		    }
+		    ident = token.ident;
+		    init = null;
+		    nextToken();
+		    if (token.value == TOKassign)
+		    {   uint flags_save;
+
+			nextToken();
+			flags_save = flags;
+			flags &= ~initial;
+			init = parseAssignExp();
+			flags = flags_save;
+		    }
+		    v = new VarDeclaration(loc, ident, init);
+		    vs.vardecls ~= v;
+		    if (token.value != TOKcomma)
+			break;
+		    nextToken();
+		}
+		if (!(flags & inForHeader))
+		    parseOptionalSemi();
+		break;
+	    }
+
+	    case TOKlbrace:
+	    {   BlockStatement bs;
+
+		nextToken();
+		bs = new BlockStatement(loc);
+		while (token.value != TOKrbrace)
+		{
+		    if (token.value == TOKeof)
+		    {   /* { */
+			error(ERR_UNTERMINATED_BLOCK);
+			break;
+		    }
+		    bs.statements ~= parseStatement();
+		}
+		s = bs;
+		nextToken();
+
+		// The following is to accommodate the jscript bug:
+		//	if (i) {return(0);}; else ...
+		if (token.value == TOKsemicolon)
+		    nextToken();
+
+		break;
+	    }
+
+	    case TOKif:
+	    {   Expression condition;
+		Statement ifbody;
+		Statement elsebody;
+
+		nextToken();
+		condition = parseParenExp();
+		ifbody = parseStatement();
+		if (token.value == TOKelse)
+		{
+		    nextToken();
+		    elsebody = parseStatement();
+		}
+		else
+		    elsebody = null;
+		s = new IfStatement(loc, condition, ifbody, elsebody);
+		break;
+	    }
+
+	    case TOKswitch:
+	    {   Expression condition;
+		Statement bdy;
+
+		nextToken();
+		condition = parseParenExp();
+		bdy = parseStatement();
+		s = new SwitchStatement(loc, condition, bdy);
+		break;
+	    }
+
+	    case TOKcase:
+	    {   Expression exp;
+
+		nextToken();
+		exp = parseExpression();
+		check(TOKcolon);
+		s = new CaseStatement(loc, exp);
+		break;
+	    }
+
+	    case TOKdefault:
+		nextToken();
+		check(TOKcolon);
+		s = new DefaultStatement(loc);
+		break;
+
+	    case TOKwhile:
+	    {   Expression condition;
+		Statement bdy;
+
+		nextToken();
+		condition = parseParenExp();
+		bdy = parseStatement();
+		s = new WhileStatement(loc, condition, bdy);
+		break;
+	    }
+
+	    case TOKsemicolon:
+		nextToken();
+		s = new EmptyStatement(loc);
+		break;
+
+	    case TOKdo:
+	    {   Statement bdy;
+		Expression condition;
+
+		nextToken();
+		bdy = parseStatement();
+		check(TOKwhile);
+		condition = parseParenExp();
+		parseOptionalSemi();
+		s = new DoStatement(loc, bdy, condition);
+		break;
+	    }
+
+	    case TOKfor:
+	    {
+		Statement init;
+		Statement bdy;
+
+		nextToken();
+		flags |= inForHeader;
+		check(TOKlparen);
+		if (token.value == TOKvar)
+		{
+		    init = parseStatement();
+		}
+		else
+		{   Expression e;
+
+		    e = parseOptionalExpression(noIn);
+		    init = e ? new ExpStatement(loc, e) : null;
+		}
+
+		if (token.value == TOKsemicolon)
+		{   Expression condition;
+		    Expression increment;
+
+		    nextToken();
+		    condition = parseOptionalExpression();
+		    check(TOKsemicolon);
+		    increment = parseOptionalExpression();
+		    check(TOKrparen);
+		    flags &= ~inForHeader;
+
+		    bdy = parseStatement();
+		    s = new ForStatement(loc, init, condition, increment, bdy);
+		}
+		else if (token.value == TOKin)
+		{   Expression inexp;
+		    VarStatement vs;
+
+		    // Check that there's only one VarDeclaration
+		    // in init.
+		    if (init.st == VARSTATEMENT)
+		    {
+			vs = cast(VarStatement)init;
+			if (vs.vardecls.length != 1)
+			    error(errmsgtbl[ERR_TOO_MANY_IN_VARS], vs.vardecls.length);
+		    }
+
+		    nextToken();
+		    inexp = parseExpression();
+		    check(TOKrparen);
+		    flags &= ~inForHeader;
+		    bdy = parseStatement();
+		    s = new ForInStatement(loc, init, inexp, bdy);
+		}
+		else
+		{
+		    error(errmsgtbl[ERR_IN_EXPECTED], token.toString());
+		    s = null;
+		}
+		break;
+	    }
+
+	    case TOKwith:
+	    {   Expression exp;
+		Statement bdy;
+
+		nextToken();
+		exp = parseParenExp();
+		bdy = parseStatement();
+		s = new WithStatement(loc, exp, bdy);
+		break;
+	    }
+
+	    case TOKbreak:
+	    {   Identifier *ident;
+
+		nextToken();
+		if (token.sawLineTerminator && token.value != TOKsemicolon)
+		{   // Assume we saw a semicolon
+		    ident = null;
+		}
+		else
+		{
+		    if (token.value == TOKidentifier)
+		    {   ident = token.ident;
+			nextToken();
+		    }
+		    else
+			ident = null;
+		    parseOptionalSemi();
+		}
+		s = new BreakStatement(loc, ident);
+		break;
+	    }
+
+	    case TOKcontinue:
+	    {   Identifier *ident;
+
+		nextToken();
+		if (token.sawLineTerminator && token.value != TOKsemicolon)
+		{   // Assume we saw a semicolon
+		    ident = null;
+		}
+		else
+		{
+		    if (token.value == TOKidentifier)
+		    {   ident = token.ident;
+			nextToken();
+		    }
+		    else
+			ident = null;
+		    parseOptionalSemi();
+		}
+		s = new ContinueStatement(loc, ident);
+		break;
+	    }
+
+	    case TOKgoto:
+	    {   Identifier *ident;
+
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error(errmsgtbl[ERR_GOTO_LABEL_EXPECTED], token.toString());
+		    s = null;
+		    break;
+		}
+		ident = token.ident;
+		nextToken();
+		parseOptionalSemi();
+		s = new GotoStatement(loc, ident);
+		break;
+	    }
+
+	    case TOKreturn:
+	    {   Expression exp;
+
+		nextToken();
+		if (token.sawLineTerminator && token.value != TOKsemicolon)
+		{   // Assume we saw a semicolon
+		    s = new ReturnStatement(loc, null);
+		}
+		else
+		{   exp = parseOptionalExpression();
+		    parseOptionalSemi();
+		    s = new ReturnStatement(loc, exp);
+		}
+		break;
+	    }
+
+	    case TOKthrow:
+	    {   Expression exp;
+
+		nextToken();
+		exp = parseExpression();
+		parseOptionalSemi();
+		s = new ThrowStatement(loc, exp);
+		break;
+	    }
+
+	    case TOKtry:
+	    {   Statement bdy;
+		Identifier *catchident;
+		Statement catchbody;
+		Statement finalbody;
+
+		nextToken();
+		bdy = parseStatement();
+		if (token.value == TOKcatch)
+		{
+		    nextToken();
+		    check(TOKlparen);
+		    catchident = null;
+		    if (token.value == TOKidentifier)
+			catchident = token.ident;
+		    check(TOKidentifier);
+		    check(TOKrparen);
+		    catchbody = parseStatement();
+		}
+		else
+		{   catchident = null;
+		    catchbody = null;
+		}
+
+		if (token.value == TOKfinally)
+		{   nextToken();
+		    finalbody = parseStatement();
+		}
+		else
+		    finalbody = null;
+
+		if (!catchbody && !finalbody)
+		{   error(ERR_TRY_CATCH_EXPECTED);
+		    s = null;
+		}
+		else
+		{
+		    s = new TryStatement(loc, bdy, catchident, catchbody, finalbody);
+		}
+		break;
+	    }
+
+	    default:
+		error(errmsgtbl[ERR_STATEMENT_EXPECTED], token.toString());
+		nextToken();
+		s = null;
+		break;
+	}
+
+	//writefln("parseStatement() done");
+	return s;
+    }
+
+
+
+    Expression parseOptionalExpression(uint flags = 0)
+    {
+	Expression e;
+
+	if (token.value == TOKsemicolon || token.value == TOKrparen)
+	    e = null;
+	else
+	    e = parseExpression(flags);
+	return e;
+    }
+
+    // Follow ECMA 7.8.1 rules for inserting semicolons
+    void parseOptionalSemi()
+    {
+	if (token.value != TOKeof &&
+	    token.value != TOKrbrace &&
+	    !(token.sawLineTerminator && (flags & inForHeader) == 0)
+	   )
+	    check(TOKsemicolon);
+    }
+
+    int check(TOK value)
+    {
+	if (token.value != value)
+	{
+	    error(errmsgtbl[ERR_EXPECTED_GENERIC], token.toString(), Token.toString(value));
+	    return 0;
+	}
+	nextToken();
+	return 1;
+    }
+
+    /********************************* Expression Parser ***************************/
+
+
+    Expression parseParenExp()
+    {   Expression e;
+
+	check(TOKlparen);
+	e = parseExpression();
+	check(TOKrparen);
+	return e;
+    }
+
+    Expression parsePrimaryExp(int innew)
+    {   Expression e;
+	Loc loc;
+
+	loc = currentline;
+	switch (token.value)
+	{
+	    case TOKthis:
+		e = new ThisExpression(loc);
+		nextToken();
+		break;
+
+	    case TOKnull:
+		e = new NullExpression(loc);
+		nextToken();
+		break;
+
+	    case TOKtrue:
+		e = new BooleanExpression(loc, 1);
+		nextToken();
+		break;
+
+	    case TOKfalse:
+		e = new BooleanExpression(loc, 0);
+		nextToken();
+		break;
+
+	    case TOKreal:
+		e = new RealExpression(loc, token.realvalue);
+		nextToken();
+		break;
+
+	    case TOKstring:
+		e = new StringExpression(loc, token.string);
+		token.string = null;	// release to gc
+		nextToken();
+		break;
+
+	    case TOKregexp:
+		e = new RegExpLiteral(loc, token.string);
+		token.string = null;	// release to gc
+		nextToken();
+		break;
+
+	    case TOKidentifier:
+		e = new IdentifierExpression(loc, token.ident);
+		token.ident = null;		// release to gc
+		nextToken();
+		break;
+
+	    case TOKlparen:
+		e = parseParenExp();
+		break;
+
+	    case TOKlbracket:
+		e = parseArrayLiteral();
+		break;
+
+	    case TOKlbrace:
+		if (flags & initial)
+		{
+		    error(ERR_OBJ_LITERAL_IN_INITIALIZER);
+		    nextToken();
+		    return null;
+		}
+		e = parseObjectLiteral();
+		break;
+
+	    case TOKfunction:
+    //	    if (flags & initial)
+    //		goto Lerror;
+		e = parseFunctionLiteral();
+		break;
+
+	    case TOKnew:
+	    {   Expression newarg;
+		Expression[] arguments;
+
+		nextToken();
+		newarg = parsePrimaryExp(1);
+		arguments = parseArguments();
+		e = new NewExp(loc, newarg, arguments);
+		break;
+	    }
+
+	    default:
+    //	Lerror:
+		error(errmsgtbl[ERR_EXPECTED_EXPRESSION], token.toString());
+		nextToken();
+		return null;
+	}
+	return parsePostExp(e, innew);
+    }
+
+    Expression[] parseArguments()
+    {
+	Expression[] arguments = null;
+
+	if (token.value == TOKlparen)
+	{
+	    nextToken();
+	    if (token.value != TOKrparen)
+	    {
+		for (;;)
+		{   Expression arg;
+
+		    arg = parseAssignExp();
+		    arguments ~= arg;
+		    if (token.value == TOKrparen)
+			break;
+		    if (!check(TOKcomma))
+			break;
+		}
+	    }
+	    nextToken();
+	}
+	return arguments;
+    }
+
+    Expression parseArrayLiteral()
+    {
+	Expression e;
+	Expression[] elements;
+	Loc loc;
+
+	//writef("parseArrayLiteral()\n");
+	loc = currentline;
+	check(TOKlbracket);
+	if (token.value != TOKrbracket)
+	{
+	    for (;;)
+	    {
+		if (token.value == TOKcomma)
+		    // Allow things like [1,2,,,3,]
+		    // Like Explorer 4, and unlike Netscape, the
+		    // trailing , indicates another null element.
+		    elements ~= cast(Expression)null;
+		else if (token.value == TOKrbracket)
+		{
+		    elements ~= cast(Expression)null;
+		    break;
+		}
+		else
+		{   e = parseAssignExp();
+		    elements ~= e;
+		    if (token.value != TOKcomma)
+			break;
+		}
+		nextToken();
+	    }
+	}
+	check(TOKrbracket);
+	e = new ArrayLiteral(loc, elements);
+	return e;
+    }
+
+    Expression parseObjectLiteral()
+    {
+	Expression e;
+	Field[] fields;
+	Loc loc;
+
+	//writef("parseObjectLiteral()\n");
+	loc = currentline;
+	check(TOKlbrace);
+	if (token.value == TOKrbrace)
+	    nextToken();
+	else
+	{
+	    for (;;)
+	    {   Field f;
+		Identifier* ident;
+
+		if (token.value != TOKidentifier)
+		{   error(ERR_EXPECTED_IDENTIFIER);
+		    break;
+		}
+		ident = token.ident;
+		nextToken();
+		check(TOKcolon);
+		f = new Field(ident, parseAssignExp());
+		fields ~= f;
+		if (token.value != TOKcomma)
+		    break;
+		nextToken();
+	    }
+	    check(TOKrbrace);
+	}
+	e = new ObjectLiteral(loc, fields);
+	return e;
+    }
+
+    Expression parseFunctionLiteral()
+    {   FunctionDefinition f;
+	Loc loc;
+
+	loc = currentline;
+	f = cast(FunctionDefinition)parseFunction(1);
+	return new FunctionLiteral(loc, f);
+    }
+
+    Expression parsePostExp(Expression e, int innew)
+    {   Loc loc;
+
+	for (;;)
+	{
+	    loc = currentline;
+	    //loc = (Loc)token.ptr;
+	    switch (token.value)
+	    {
+		case TOKdot:
+		    nextToken();
+		    if (token.value == TOKidentifier)
+		    {
+			e = new DotExp(loc, e, token.ident);
+		    }
+		    else
+		    {
+			error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_2PARAM], ".", token.toString());
+			return e;
+		    }
+		    break;
+
+		case TOKplusplus:
+		    if (token.sawLineTerminator && !(flags & inForHeader))
+			goto Linsert;
+		    e = new PostIncExp(loc, e);
+		    break;
+
+		case TOKminusminus:
+		    if (token.sawLineTerminator && !(flags & inForHeader))
+		    {
+		    Linsert:
+			// insert automatic semicolon
+			insertSemicolon(token.sawLineTerminator);
+			return e;
+		    }
+		    e = new PostDecExp(loc, e);
+		    break;
+
+		case TOKlparen:
+		{   // function call
+		    Expression[] arguments;
+
+		    if (innew)
+			return e;
+		    arguments = parseArguments();
+		    e = new CallExp(loc, e, arguments);
+		    continue;
+		}
+
+		case TOKlbracket:
+		{   // array dereference
+		    Expression index;
+
+		    nextToken();
+		    index = parseExpression();
+		    check(TOKrbracket);
+		    e = new ArrayExp(loc, e, index);
+		    continue;
+		}
+
+		default:
+		    return e;
+	    }
+	    nextToken();
+	}
+	assert(0);
+    }
+
+    Expression parseUnaryExp()
+    {   Expression e;
+	Loc loc;
+
+	loc = currentline;
+	switch (token.value)
+	{
+	    case TOKplusplus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new PreExp(loc, IRpreinc, e);
+		break;
+
+	    case TOKminusminus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new PreExp(loc, IRpredec, e);
+		break;
+
+	    case TOKminus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKneg, IRneg, e);
+		break;
+
+	    case TOKplus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKpos, IRpos, e);
+		break;
+
+	    case TOKnot:
+		nextToken();
+		e = parseUnaryExp();
+		e = new NotExp(loc, e);
+		break;
+
+	    case TOKtilde:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKtilde, IRcom, e);
+		break;
+
+	    case TOKdelete:
+		nextToken();
+		e = parsePrimaryExp(0);
+		e = new DeleteExp(loc, e);
+		break;
+
+	    case TOKtypeof:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKtypeof, IRtypeof, e);
+		break;
+
+	    case TOKvoid:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKvoid, IRundefined, e);
+		break;
+
+	    default:
+		e = parsePrimaryExp(0);
+		break;
+	}
+	return e;
+    }
+
+    Expression parseMulExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseUnaryExp();
+	for (;;)
+	{
+	    switch (token.value)
+	    {
+		case TOKmultiply:
+		    nextToken();
+		    e2 = parseUnaryExp();
+		    e = new XBinExp(loc, TOKmultiply, IRmul, e, e2);
+		    continue;
+
+		case TOKregexp:
+		    // Rescan as if it was a "/"
+		    rescan();
+		case TOKdivide:
+		    nextToken();
+		    e2 = parseUnaryExp();
+		    e = new XBinExp(loc, TOKdivide, IRdiv, e, e2);
+		    continue;
+
+		case TOKpercent:
+		    nextToken();
+		    e2 = parseUnaryExp();
+		    e = new XBinExp(loc, TOKpercent, IRmod, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseAddExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseMulExp();
+	for (;;)
+	{
+	    switch (token.value)
+	    {
+		case TOKplus:
+		    nextToken();
+		    e2 = parseMulExp();
+		    e = new AddExp(loc, e, e2);
+		    continue;
+
+		case TOKminus:
+		    nextToken();
+		    e2 = parseMulExp();
+		    e = new XBinExp(loc, TOKminus, IRsub, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseShiftExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseAddExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKshiftleft:	ircode = IRshl;		goto L1;
+		case TOKshiftright:	ircode = IRshr;		goto L1;
+		case TOKushiftright:	ircode = IRushr;	goto L1;
+
+		L1: nextToken();
+		    e2 = parseAddExp();
+		    e = new XBinExp(loc, op, ircode, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseRelExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseShiftExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKless:		ircode = IRclt;	goto L1;
+		case TOKlessequal:	ircode = IRcle;	goto L1;
+		case TOKgreater:	ircode = IRcgt;	goto L1;
+		case TOKgreaterequal:	ircode = IRcge;	goto L1;
+
+		L1:
+		    nextToken();
+		    e2 = parseShiftExp();
+		    e = new CmpExp(loc, op, ircode, e, e2);
+		    continue;
+
+		case TOKinstanceof:
+		    nextToken();
+		    e2 = parseShiftExp();
+		    e = new XBinExp(loc, TOKinstanceof, IRinstance, e, e2);
+		    continue;
+
+		case TOKin:
+		    if (flags & noIn)
+			break;		// disallow
+		    nextToken();
+		    e2 = parseShiftExp();
+		    e = new InExp(loc, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseEqualExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseRelExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKequal:	     ircode = IRceq;	    goto L1;
+		case TOKnotequal:    ircode = IRcne;	    goto L1;
+		case TOKidentity:    ircode = IRcid;	    goto L1;
+		case TOKnonidentity: ircode = IRcnid;	    goto L1;
+
+		L1:
+		    nextToken();
+		    e2 = parseRelExp();
+		    e = new CmpExp(loc, op, ircode, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseAndExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseEqualExp();
+	while (token.value == TOKand)
+	{
+	    nextToken();
+	    e2 = parseEqualExp();
+	    e = new XBinExp(loc, TOKand, IRand, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseXorExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseAndExp();
+	while (token.value == TOKxor)
+	{
+	    nextToken();
+	    e2 = parseAndExp();
+	    e = new XBinExp(loc, TOKxor, IRxor, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseOrExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseXorExp();
+	while (token.value == TOKor)
+	{
+	    nextToken();
+	    e2 = parseXorExp();
+	    e = new XBinExp(loc, TOKor, IRor, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseAndAndExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseOrExp();
+	while (token.value == TOKandand)
+	{
+	    nextToken();
+	    e2 = parseOrExp();
+	    e = new AndAndExp(loc, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseOrOrExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseAndAndExp();
+	while (token.value == TOKoror)
+	{
+	    nextToken();
+	    e2 = parseAndAndExp();
+	    e = new OrOrExp(loc, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseCondExp()
+    {   Expression e;
+	Expression e1;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseOrOrExp();
+	if (token.value == TOKquestion)
+	{
+	    nextToken();
+	    e1 = parseAssignExp();
+	    check(TOKcolon);
+	    e2 = parseAssignExp();
+	    e = new CondExp(loc, e, e1, e2);
+	}
+	return e;
+    }
+
+    Expression parseAssignExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseCondExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKassign:
+		    nextToken();
+		    e2 = parseAssignExp();
+		    e = new AssignExp(loc, e, e2);
+		    continue;
+
+		case TOKplusass:
+		    nextToken();
+		    e2 = parseAssignExp();
+		    e = new AddAssignExp(loc, e, e2);
+		    continue;
+
+		case TOKminusass:	ircode = IRsub;	 goto L1;
+		case TOKmultiplyass:	ircode = IRmul;	 goto L1;
+		case TOKdivideass:	ircode = IRdiv;	 goto L1;
+		case TOKpercentass:	ircode = IRmod;	 goto L1;
+		case TOKandass:		ircode = IRand;	 goto L1;
+		case TOKorass:		ircode = IRor;	 goto L1;
+		case TOKxorass:		ircode = IRxor;	 goto L1;
+		case TOKshiftleftass:	ircode = IRshl;	 goto L1;
+		case TOKshiftrightass:	ircode = IRshr;	 goto L1;
+		case TOKushiftrightass:	ircode = IRushr; goto L1;
+
+		L1: nextToken();
+		    e2 = parseAssignExp();
+		    e = new BinAssignExp(loc, op, ircode, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseExpression(uint flags = 0)
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+	uint flags_save;
+
+	//writefln("Parser.parseExpression()");
+	flags_save = this.flags;
+	this.flags = flags;
+	loc = currentline;
+	e = parseAssignExp();
+	while (token.value == TOKcomma)
+	{
+	    nextToken();
+	    e2 = parseAssignExp();
+	    e = new CommaExp(loc, e, e2);
+	}
+	this.flags = flags_save;
+	return e;
+    }
+
+}
+
+/********************************* ***************************/
+