/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla 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/MPL/
*
* 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 the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mike Ang
* Igor Bukanov
* Yuh-Ruey Chen
* Ethan Hugg
* Bob Jervis
* Terry Lucas
* Mike McCabe
* Milen Nankov
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (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
* MPL, indicate your decision by deleting the provisions above and replacing
* 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 MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.javascript;
import java.io.Reader;
import java.io.IOException;
import java.util.Hashtable;
/**
* This class implements the JavaScript parser.
*
* It is based on the C source files jsparse.c and jsparse.h
* in the jsref package.
*
* @see TokenStream
*
* @author Mike McCabe
* @author Brendan Eich
*/
public class Parser
{
// TokenInformation flags : currentFlaggedToken stores them together
// with token type
final static int
CLEAR_TI_MASK = 0xFFFF, // mask to clear token information bits
TI_AFTER_EOL = 1 << 16, // first token of the source line
TI_CHECK_LABEL = 1 << 17; // indicates to check for label
CompilerEnvirons compilerEnv;
private ErrorReporter errorReporter;
private String sourceURI;
boolean calledByCompileFunction;
private TokenStream ts;
private int currentFlaggedToken;
private int syntaxErrorCount;
private IRFactory nf;
private int nestingOfFunction;
private Decompiler decompiler;
private String encodedSource;
// The following are per function variables and should be saved/restored
// during function parsing.
// XXX Move to separated class?
ScriptOrFnNode currentScriptOrFn;
private int nestingOfWith;
private Hashtable labelSet; // map of label names into nodes
private ObjArray loopSet;
private ObjArray loopAndSwitchSet;
private boolean hasReturnValue;
private int functionEndFlags;
// end of per function variables
// Exception to unwind
private static class ParserException extends RuntimeException
{
static final long serialVersionUID = 5882582646773765630L;
}
public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter)
{
this.compilerEnv = compilerEnv;
this.errorReporter = errorReporter;
}
protected Decompiler createDecompiler(CompilerEnvirons compilerEnv)
{
return new Decompiler();
}
void addStrictWarning(String messageId, String messageArg)
{
if (compilerEnv.isStrictMode())
addWarning(messageId, messageArg);
}
void addWarning(String messageId, String messageArg)
{
String message = ScriptRuntime.getMessage1(messageId, messageArg);
if (compilerEnv.reportWarningAsError()) {
++syntaxErrorCount;
errorReporter.error(message, sourceURI, ts.getLineno(),
ts.getLine(), ts.getOffset());
} else
errorReporter.warning(message, sourceURI, ts.getLineno(),
ts.getLine(), ts.getOffset());
}
void addError(String messageId)
{
++syntaxErrorCount;
String message = ScriptRuntime.getMessage0(messageId);
errorReporter.error(message, sourceURI, ts.getLineno(),
ts.getLine(), ts.getOffset());
}
void addError(String messageId, String messageArg)
{
++syntaxErrorCount;
String message = ScriptRuntime.getMessage1(messageId, messageArg);
errorReporter.error(message, sourceURI, ts.getLineno(),
ts.getLine(), ts.getOffset());
}
RuntimeException reportError(String messageId)
{
addError(messageId);
// Throw a ParserException exception to unwind the recursive descent
// parse.
throw new ParserException();
}
private int peekToken()
throws IOException
{
int tt = currentFlaggedToken;
if (tt == Token.EOF) {
while ((tt = ts.getToken()) == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT) {
if (tt == Token.CONDCOMMENT) {
/* Support for JScript conditional comments */
decompiler.addJScriptConditionalComment(ts.getString());
} else {
/* Support for preserved comments */
decompiler.addPreservedComment(ts.getString());
}
}
if (tt == Token.EOL) {
do {
tt = ts.getToken();
if (tt == Token.CONDCOMMENT) {
/* Support for JScript conditional comments */
decompiler.addJScriptConditionalComment(ts.getString());
} else if (tt == Token.KEEPCOMMENT) {
/* Support for preserved comments */
decompiler.addPreservedComment(ts.getString());
}
} while (tt == Token.EOL || tt == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT);
tt |= TI_AFTER_EOL;
}
currentFlaggedToken = tt;
}
return tt & CLEAR_TI_MASK;
}
private int peekFlaggedToken()
throws IOException
{
peekToken();
return currentFlaggedToken;
}
private void consumeToken()
{
currentFlaggedToken = Token.EOF;
}
private int nextToken()
throws IOException
{
int tt = peekToken();
consumeToken();
return tt;
}
private int nextFlaggedToken()
throws IOException
{
peekToken();
int ttFlagged = currentFlaggedToken;
consumeToken();
return ttFlagged;
}
private boolean matchToken(int toMatch)
throws IOException
{
int tt = peekToken();
if (tt != toMatch) {
return false;
}
consumeToken();
return true;
}
private int peekTokenOrEOL()
throws IOException
{
int tt = peekToken();
// Check for last peeked token flags
if ((currentFlaggedToken & TI_AFTER_EOL) != 0) {
tt = Token.EOL;
}
return tt;
}
private void setCheckForLabel()
{
if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME)
throw Kit.codeBug();
currentFlaggedToken |= TI_CHECK_LABEL;
}
private void mustMatchToken(int toMatch, String messageId)
throws IOException, ParserException
{
if (!matchToken(toMatch)) {
reportError(messageId);
}
}
private void mustHaveXML()
{
评论0
最新资源