0001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
0002: *
0003: * ***** BEGIN LICENSE BLOCK *****
0004: * Version: MPL 1.1/GPL 2.0
0005: *
0006: * The contents of this file are subject to the Mozilla Public License Version
0007: * 1.1 (the "License"); you may not use this file except in compliance with
0008: * the License. You may obtain a copy of the License at
0009: * http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the
0014: * License.
0015: *
0016: * The Original Code is Rhino code, released
0017: * May 6, 1999.
0018: *
0019: * The Initial Developer of the Original Code is
0020: * Netscape Communications Corporation.
0021: * Portions created by the Initial Developer are Copyright (C) 1997-1999
0022: * the Initial Developer. All Rights Reserved.
0023: *
0024: * Contributor(s):
0025: * Mike Ang
0026: * Igor Bukanov
0027: * Yuh-Ruey Chen
0028: * Ethan Hugg
0029: * Bob Jervis
0030: * Terry Lucas
0031: * Mike McCabe
0032: * Milen Nankov
0033: *
0034: * Alternatively, the contents of this file may be used under the terms of
0035: * the GNU General Public License Version 2 or later (the "GPL"), in which
0036: * case the provisions of the GPL are applicable instead of those above. If
0037: * you wish to allow use of your version of this file only under the terms of
0038: * the GPL and not to allow others to use your version of this file under the
0039: * MPL, indicate your decision by deleting the provisions above and replacing
0040: * them with the notice and other provisions required by the GPL. If you do
0041: * not delete the provisions above, a recipient may use your version of this
0042: * file under either the MPL or the GPL.
0043: *
0044: * ***** END LICENSE BLOCK ***** */
0045:
0046: package org.mozilla.javascript;
0047:
0048: import java.io.Reader;
0049: import java.io.IOException;
0050: import java.util.ArrayList;
0051: import java.util.Hashtable;
0052: import java.util.List;
0053:
0054: /**
0055: * This class implements the JavaScript parser.
0056: *
0057: * It is based on the C source files jsparse.c and jsparse.h
0058: * in the jsref package.
0059: *
0060: * @see TokenStream
0061: *
0062: * @author Mike McCabe
0063: * @author Brendan Eich
0064: */
0065:
0066: public class Parser {
0067: // TokenInformation flags : currentFlaggedToken stores them together
0068: // with token type
0069: // <netbeans>
0070: public// </netbeans>
0071: final static int CLEAR_TI_MASK = 0xFFFF, // mask to clear token information bits
0072: TI_AFTER_EOL = 1 << 16, // first token of the source line
0073: TI_CHECK_LABEL = 1 << 17; // indicates to check for label
0074:
0075: CompilerEnvirons compilerEnv;
0076: private ErrorReporter errorReporter;
0077: private String sourceURI;
0078: boolean calledByCompileFunction;
0079:
0080: private TokenStream ts;
0081: // <netbeans>
0082: private int peekedTokenStart;
0083: private int peekedTokenEnd;
0084: private int matchedTokenStart;
0085: private int matchedTokenEnd;
0086: private int matchedToken;
0087: private boolean jsonMode;
0088:
0089: public void setJsonMode(boolean jsonMode) {
0090: this .jsonMode = jsonMode;
0091: }
0092:
0093: // </netbeans>
0094: private int currentFlaggedToken;
0095: private int syntaxErrorCount;
0096:
0097: private IRFactory nf;
0098:
0099: private int nestingOfFunction;
0100:
0101: private Decompiler decompiler;
0102: private String encodedSource;
0103:
0104: // The following are per function variables and should be saved/restored
0105: // during function parsing.
0106: // XXX Move to separated class?
0107: ScriptOrFnNode currentScriptOrFn;
0108: private int nestingOfWith;
0109: private Hashtable labelSet; // map of label names into nodes
0110: private ObjArray loopSet;
0111: private ObjArray loopAndSwitchSet;
0112: private boolean hasReturnValue;
0113: private int functionEndFlags;
0114:
0115: // end of per function variables
0116:
0117: // Exception to unwind
0118: private static class ParserException extends RuntimeException {
0119: static final long serialVersionUID = 5882582646773765630L;
0120: }
0121:
0122: public Parser(CompilerEnvirons compilerEnv,
0123: ErrorReporter errorReporter) {
0124: this .compilerEnv = compilerEnv;
0125: this .errorReporter = errorReporter;
0126: }
0127:
0128: protected Decompiler createDecompiler(CompilerEnvirons compilerEnv) {
0129: return new Decompiler();
0130: }
0131:
0132: void addStrictWarning(String messageId, String messageArg
0133: // <netbeans>
0134: // Additional error parameters that can be passed to the error handler
0135: , Object params
0136: // </netbeans>
0137: ) {
0138: if (compilerEnv.isStrictMode())
0139: addWarning(messageId, messageArg
0140: // <netbeans>
0141: // Additional error parameters that can be passed to the error handler
0142: , params
0143: // </netbeans>
0144: );
0145: }
0146:
0147: void addWarning(String messageId, String messageArg
0148: // <netbeans>
0149: // Additional error parameters that can be passed to the error handler
0150: , Object params
0151: // </netbeans>
0152: ) {
0153: String message = ScriptRuntime.getMessage1(messageId,
0154: messageArg);
0155: if (compilerEnv.reportWarningAsError()) {
0156: ++syntaxErrorCount;
0157: errorReporter.error(message, sourceURI, ts.getLineno(), ts
0158: .getLine(), ts.getOffset()
0159: // <netbeans>
0160: , messageId, params
0161: // </netbeans>
0162: );
0163: } else
0164: errorReporter.warning(message, sourceURI, ts.getLineno(),
0165: ts.getLine(), ts.getOffset()
0166: // <netbeans>
0167: , messageId, params
0168: // </netbeans>
0169: );
0170: }
0171:
0172: void addError(String messageId) {
0173: ++syntaxErrorCount;
0174: String message = ScriptRuntime.getMessage0(messageId);
0175: errorReporter.error(message, sourceURI, ts.getLineno(), ts
0176: .getLine(), ts.getOffset()
0177: // <netbeans>
0178: , messageId, null
0179: // </netbeans>
0180: );
0181: }
0182:
0183: void addError(String messageId, String messageArg
0184: // <netbeans>
0185: // Additional error parameters that can be passed to the error handler
0186: , Object params
0187: // </netbeans>
0188: ) {
0189: ++syntaxErrorCount;
0190: String message = ScriptRuntime.getMessage1(messageId,
0191: messageArg);
0192: errorReporter.error(message, sourceURI, ts.getLineno(), ts
0193: .getLine(), ts.getOffset()
0194: // <netbeans>
0195: , messageId, params
0196: // </netbeans>
0197: );
0198: }
0199:
0200: RuntimeException reportError(String messageId) {
0201: addError(messageId);
0202:
0203: // Throw a ParserException exception to unwind the recursive descent
0204: // parse.
0205: throw new ParserException();
0206: }
0207:
0208: private int peekToken() throws IOException {
0209: int tt = currentFlaggedToken;
0210: if (tt == Token.EOF) {
0211: // <netbeans>
0212: peekedTokenStart = ts.getBufferOffset();
0213: // </netbeans>
0214: tt = ts.getToken();
0215: if (tt == Token.EOL) {
0216: do {
0217: // <netbeans>
0218: peekedTokenStart = ts.getBufferOffset();
0219: // </netbeans>
0220: tt = ts.getToken();
0221: } while (tt == Token.EOL);
0222: tt |= TI_AFTER_EOL;
0223: }
0224: currentFlaggedToken = tt;
0225: // <netbeans>
0226: peekedTokenStart += ts.seenSpaces();
0227: peekedTokenEnd = ts.getBufferOffset();
0228: // </netbeans>
0229: }
0230: return tt & CLEAR_TI_MASK;
0231: }
0232:
0233: private int peekFlaggedToken() throws IOException {
0234: peekToken();
0235: return currentFlaggedToken;
0236: }
0237:
0238: private void consumeToken() {
0239: // <netbeans>
0240: // Consume token gets called as part of nextToken() for example so doesn't help us very much
0241: //currentFlaggedTokenOffset = -1;
0242: matchedToken = currentFlaggedToken;
0243: matchedTokenStart = peekedTokenStart;
0244: matchedTokenEnd = peekedTokenEnd;
0245: // </netbeans>
0246: currentFlaggedToken = Token.EOF;
0247: }
0248:
0249: private int nextToken() throws IOException {
0250: int tt = peekToken();
0251: consumeToken();
0252: return tt;
0253: }
0254:
0255: private int nextFlaggedToken() throws IOException {
0256: peekToken();
0257: int ttFlagged = currentFlaggedToken;
0258: consumeToken();
0259: return ttFlagged;
0260: }
0261:
0262: private boolean matchToken(int toMatch) throws IOException {
0263: int tt = peekToken();
0264: if (tt != toMatch) {
0265: return false;
0266: }
0267: consumeToken();
0268: return true;
0269: }
0270:
0271: private int peekTokenOrEOL() throws IOException {
0272: int tt = peekToken();
0273: // Check for last peeked token flags
0274: if ((currentFlaggedToken & TI_AFTER_EOL) != 0) {
0275: tt = Token.EOL;
0276: }
0277: return tt;
0278: }
0279:
0280: private void setCheckForLabel() {
0281: if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME)
0282: throw Kit.codeBug();
0283: currentFlaggedToken |= TI_CHECK_LABEL;
0284: }
0285:
0286: private void mustMatchToken(int toMatch, String messageId)
0287: throws IOException, ParserException {
0288: if (!matchToken(toMatch)) {
0289: reportError(messageId);
0290: }
0291: }
0292:
0293: private void mustHaveXML() {
0294: if (!compilerEnv.isXmlAvailable()) {
0295: reportError("msg.XML.not.available");
0296: }
0297: }
0298:
0299: public String getEncodedSource() {
0300: return encodedSource;
0301: }
0302:
0303: public boolean eof() {
0304: return ts.eof();
0305: }
0306:
0307: boolean insideFunction() {
0308: return nestingOfFunction != 0;
0309: }
0310:
0311: private Node enterLoop(Node loopLabel) {
0312: Node loop = nf.createLoopNode(loopLabel, ts.getLineno());
0313: // <netbeans>
0314: int startOffset = getStartOffset();
0315: // TODO: Compute end position, perhaps in exitLoop?
0316: loop.setSourceBounds(startOffset, startOffset);
0317: // </netbeans>
0318: if (loopSet == null) {
0319: loopSet = new ObjArray();
0320: if (loopAndSwitchSet == null) {
0321: loopAndSwitchSet = new ObjArray();
0322: }
0323: }
0324: loopSet.push(loop);
0325: loopAndSwitchSet.push(loop);
0326: return loop;
0327: }
0328:
0329: private void exitLoop() {
0330: loopSet.pop();
0331: loopAndSwitchSet.pop();
0332: }
0333:
0334: private Node enterSwitch(Node switchSelector, int lineno) {
0335: Node switchNode = nf.createSwitch(switchSelector, lineno);
0336: // <netbeans>
0337: int startOffset = getStartOffset();
0338: // TODO: Compute end position, perhaps in exitSwitch??
0339: switchNode.setSourceBounds(startOffset, startOffset);
0340: // </netbeans>
0341: if (loopAndSwitchSet == null) {
0342: loopAndSwitchSet = new ObjArray();
0343: }
0344: loopAndSwitchSet.push(switchNode);
0345: return switchNode;
0346: }
0347:
0348: private void exitSwitch() {
0349: // <netbeans>
0350: //loopAndSwitchSet.pop();
0351: Node switchNode = (Node) loopAndSwitchSet.pop();
0352: setSourceOffsets(switchNode, switchNode.getSourceStart());
0353: // </netbeaans>
0354: }
0355:
0356: /*
0357: * Build a parse tree from the given sourceString.
0358: *
0359: * @return an Object representing the parsed
0360: * program. If the parse fails, null will be returned. (The
0361: * parse failure will result in a call to the ErrorReporter from
0362: * CompilerEnvirons.)
0363: */
0364: public ScriptOrFnNode parse(String sourceString, String sourceURI,
0365: int lineno) {
0366: this .sourceURI = sourceURI;
0367: this .ts = new TokenStream(this , null, sourceString, lineno);
0368: try {
0369: // <netbeans>
0370: setJsonMode(false);
0371: // </netbeans>
0372: return parse();
0373: } catch (IOException ex) {
0374: // Should never happen
0375: throw new IllegalStateException();
0376: }
0377: }
0378:
0379: /*
0380: * Build a parse tree from the given sourceString.
0381: *
0382: * @return an Object representing the parsed
0383: * program. If the parse fails, null will be returned. (The
0384: * parse failure will result in a call to the ErrorReporter from
0385: * CompilerEnvirons.)
0386: */
0387: public ScriptOrFnNode parse(Reader sourceReader, String sourceURI,
0388: int lineno) throws IOException {
0389: this .sourceURI = sourceURI;
0390: this .ts = new TokenStream(this , sourceReader, null, lineno);
0391: return parse();
0392: }
0393:
0394: private ScriptOrFnNode parse() throws IOException {
0395: this .decompiler = createDecompiler(compilerEnv);
0396: this .nf = new IRFactory(this );
0397: currentScriptOrFn = nf.createScript();
0398: int sourceStartOffset = decompiler.getCurrentOffset();
0399: // <netbeans>
0400: int realSourceStartOffset = ts.getBufferOffset();
0401: // </netbeans>
0402: this .encodedSource = null;
0403: decompiler.addToken(Token.SCRIPT);
0404:
0405: this .currentFlaggedToken = Token.EOF;
0406: this .syntaxErrorCount = 0;
0407:
0408: int baseLineno = ts.getLineno(); // line number where source starts
0409:
0410: /* so we have something to add nodes to until
0411: * we've collected all the source */
0412: Node pn = nf.createLeaf(Token.BLOCK);
0413:
0414: try {
0415: for (;;) {
0416: int tt = peekToken();
0417:
0418: if (tt <= Token.EOF) {
0419: break;
0420: }
0421:
0422: Node n;
0423: if (tt == Token.FUNCTION) {
0424: // <netbeans>
0425: int startOffset = peekedTokenStart;
0426: // </netbeans>
0427: consumeToken();
0428: try {
0429: n = function(calledByCompileFunction ? FunctionNode.FUNCTION_EXPRESSION
0430: : FunctionNode.FUNCTION_STATEMENT);
0431: // <netbeans>
0432: setSourceOffsets(n, startOffset);
0433: // </netbeans>
0434: } catch (ParserException e) {
0435: break;
0436: }
0437: } else {
0438: n = statement();
0439: }
0440: nf.addChildToBack(pn, n);
0441: }
0442: } catch (StackOverflowError ex) {
0443: String msg = ScriptRuntime
0444: .getMessage0("msg.too.deep.parser.recursion");
0445: throw Context.reportRuntimeError(msg, sourceURI, ts
0446: .getLineno(), null, 0);
0447: }
0448:
0449: if (this .syntaxErrorCount != 0) {
0450: String msg = String.valueOf(this .syntaxErrorCount);
0451: msg = ScriptRuntime.getMessage1("msg.got.syntax.errors",
0452: msg);
0453: // <netbeans>
0454: //throw errorReporter.runtimeError(msg, sourceURI, baseLineno,
0455: // null, 0);
0456: // Don't show an error for this at all!
0457: //EvaluatorException exc = errorReporter.runtimeError(msg, sourceURI, baseLineno,
0458: // null, 0);
0459: //if (exc != null) {
0460: // throw exc;
0461: //} else {
0462: // currentScriptOrFn.setSourceName(sourceURI);
0463: // currentScriptOrFn.setBaseLineno(baseLineno);
0464: // currentScriptOrFn.setEndLineno(ts.getLineno());
0465: //
0466: // return currentScriptOrFn;
0467: return null;
0468: //}
0469: // </netbeans>
0470: }
0471:
0472: currentScriptOrFn.setSourceName(sourceURI);
0473: currentScriptOrFn.setBaseLineno(baseLineno);
0474: currentScriptOrFn.setEndLineno(ts.getLineno());
0475:
0476: int sourceEndOffset = decompiler.getCurrentOffset();
0477: currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset,
0478: sourceEndOffset);
0479: // <netbeans>
0480: int realSourceEndOffset = getEndOffset();
0481: currentScriptOrFn.setSourceBounds(realSourceStartOffset,
0482: realSourceEndOffset);
0483: // </netbeans>
0484:
0485: nf.initScript(currentScriptOrFn, pn);
0486:
0487: if (compilerEnv.isGeneratingSource()) {
0488: encodedSource = decompiler.getEncodedSource();
0489: }
0490: this .decompiler = null; // It helps GC
0491:
0492: return currentScriptOrFn;
0493: }
0494:
0495: /*
0496: * The C version of this function takes an argument list,
0497: * which doesn't seem to be needed for tree generation...
0498: * it'd only be useful for checking argument hiding, which
0499: * I'm not doing anyway...
0500: */
0501: private Node parseFunctionBody() throws IOException {
0502: ++nestingOfFunction;
0503: // <netbeans>
0504: int startOffset = getStartOffset();
0505: // </netbeans>
0506: Node pn = nf.createBlock(ts.getLineno());
0507: try {
0508: bodyLoop: for (;;) {
0509: Node n;
0510: int tt = peekToken();
0511: switch (tt) {
0512: case Token.ERROR:
0513: case Token.EOF:
0514: case Token.RC:
0515: break bodyLoop;
0516:
0517: case Token.FUNCTION:
0518: consumeToken();
0519: n = function(FunctionNode.FUNCTION_STATEMENT);
0520: break;
0521: default:
0522: n = statement();
0523: break;
0524: }
0525: nf.addChildToBack(pn, n);
0526: }
0527: } catch (ParserException e) {
0528: // Ignore it
0529: } finally {
0530: --nestingOfFunction;
0531: }
0532:
0533: // <netbeans>
0534: //setSourceOffsets(pn, startOffset);
0535: pn.setSourceBounds(startOffset, getEndOffset());
0536: // </netbeans>
0537: return pn;
0538: }
0539:
0540: private Node function(int functionType) throws IOException,
0541: ParserException {
0542: int syntheticType = functionType;
0543: int baseLineno = ts.getLineno(); // line number where source starts
0544:
0545: int functionSourceStart = decompiler
0546: .markFunctionStart(functionType);
0547: // <netbeans>
0548: int realSourceStartOffset = getStartOffset();
0549: int realSourceEndOffset = realSourceStartOffset;
0550: Node funcNameNode = null;
0551: // </netbeans>
0552: String name;
0553: Node memberExprNode = null;
0554: if (matchToken(Token.NAME)) {
0555: name = ts.getString();
0556: // <netbeans>
0557: funcNameNode = Node.newString(Token.FUNCNAME, name);
0558: setSourceOffsets(funcNameNode, getStartOffset());
0559: // </netbeans>
0560: decompiler.addName(name);
0561: if (!matchToken(Token.LP)) {
0562: if (compilerEnv.isAllowMemberExprAsFunctionName()) {
0563: // Extension to ECMA: if 'function <name>' does not follow
0564: // by '(', assume <name> starts memberExpr
0565: Node memberExprHead = nf.createName(name);
0566: name = "";
0567: memberExprNode = memberExprTail(false,
0568: memberExprHead);
0569: }
0570: mustMatchToken(Token.LP, "msg.no.paren.parms");
0571: }
0572: } else if (matchToken(Token.LP)) {
0573: // Anonymous function
0574: name = "";
0575: } else {
0576: name = "";
0577: if (compilerEnv.isAllowMemberExprAsFunctionName()) {
0578: // Note that memberExpr can not start with '(' like
0579: // in function (1+2).toString(), because 'function (' already
0580: // processed as anonymous function
0581: memberExprNode = memberExpr(false);
0582: }
0583: mustMatchToken(Token.LP, "msg.no.paren.parms");
0584: }
0585:
0586: if (memberExprNode != null) {
0587: syntheticType = FunctionNode.FUNCTION_EXPRESSION;
0588: }
0589:
0590: boolean nested = insideFunction();
0591:
0592: FunctionNode fnNode = nf.createFunction(name);
0593: // <netbeans>
0594: // Add a special node for the function name with proper offsets etc.
0595: // for IDE usage in refactoring, highlighting etc.
0596: if (funcNameNode != null) {
0597: fnNode.addChildToFront(funcNameNode);
0598: }
0599: // </netbeans>
0600:
0601: if (nested || nestingOfWith > 0) {
0602: // 1. Nested functions are not affected by the dynamic scope flag
0603: // as dynamic scope is already a parent of their scope.
0604: // 2. Functions defined under the with statement also immune to
0605: // this setup, in which case dynamic scope is ignored in favor
0606: // of with object.
0607: fnNode.itsIgnoreDynamicScope = true;
0608: }
0609:
0610: int functionIndex = currentScriptOrFn.addFunction(fnNode);
0611:
0612: int functionSourceEnd;
0613:
0614: ScriptOrFnNode savedScriptOrFn = currentScriptOrFn;
0615: currentScriptOrFn = fnNode;
0616: int savedNestingOfWith = nestingOfWith;
0617: nestingOfWith = 0;
0618: Hashtable savedLabelSet = labelSet;
0619: labelSet = null;
0620: ObjArray savedLoopSet = loopSet;
0621: loopSet = null;
0622: ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
0623: loopAndSwitchSet = null;
0624: boolean savedHasReturnValue = hasReturnValue;
0625: int savedFunctionEndFlags = functionEndFlags;
0626:
0627: Node body;
0628: try {
0629: decompiler.addToken(Token.LP);
0630: if (!matchToken(Token.RP)) {
0631: boolean first = true;
0632: do {
0633: if (!first)
0634: decompiler.addToken(Token.COMMA);
0635: first = false;
0636: mustMatchToken(Token.NAME, "msg.no.parm");
0637: String s = ts.getString();
0638: // <netbeans>
0639: Node paramNode = Node.newString(Token.PARAMETER, s);
0640: setSourceOffsets(paramNode, getStartOffset());
0641: fnNode.addChildToBack(paramNode);
0642: // </netbeans>
0643: if (fnNode.hasParamOrVar(s)) {
0644: addWarning("msg.dup.parms", s
0645: // <netbeans> - pass in additional parameters for the error
0646: , paramNode
0647: // </netbeans>
0648: );
0649: }
0650: fnNode.addParam(s);
0651: decompiler.addName(s);
0652: } while (matchToken(Token.COMMA));
0653:
0654: mustMatchToken(Token.RP, "msg.no.paren.after.parms");
0655: }
0656: decompiler.addToken(Token.RP);
0657:
0658: mustMatchToken(Token.LC, "msg.no.brace.body");
0659: decompiler.addEOL(Token.LC);
0660: body = parseFunctionBody();
0661: mustMatchToken(Token.RC, "msg.no.brace.after.body");
0662:
0663: if (compilerEnv.isStrictMode()
0664: && !body.hasConsistentReturnUsage()) {
0665: String msg = name.length() > 0 ? "msg.no.return.value"
0666: : "msg.anon.no.return.value";
0667: addStrictWarning(msg, name
0668: // <netbeans> - pass in additional parameters for the error
0669: , fnNode
0670: // </netbeans>
0671: );
0672: }
0673:
0674: decompiler.addToken(Token.RC);
0675: functionSourceEnd = decompiler
0676: .markFunctionEnd(functionSourceStart);
0677: // <netbeans>
0678: realSourceEndOffset = getEndOffset();
0679: // </netbeans>
0680:
0681: if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
0682: // Add EOL only if function is not part of expression
0683: // since it gets SEMI + EOL from Statement in that case
0684: decompiler.addToken(Token.EOL);
0685: }
0686: } finally {
0687: hasReturnValue = savedHasReturnValue;
0688: functionEndFlags = savedFunctionEndFlags;
0689: loopAndSwitchSet = savedLoopAndSwitchSet;
0690: loopSet = savedLoopSet;
0691: labelSet = savedLabelSet;
0692: nestingOfWith = savedNestingOfWith;
0693: currentScriptOrFn = savedScriptOrFn;
0694: }
0695:
0696: fnNode.setEncodedSourceBounds(functionSourceStart,
0697: functionSourceEnd);
0698: fnNode.setSourceName(sourceURI);
0699: fnNode.setBaseLineno(baseLineno);
0700: fnNode.setEndLineno(ts.getLineno());
0701: // <netbeans>
0702: fnNode.setSourceBounds(realSourceStartOffset,
0703: realSourceEndOffset);
0704: // </netbeans>
0705:
0706: if (name != null) {
0707: int index = currentScriptOrFn.getParamOrVarIndex(name);
0708: if (index >= 0 && index < currentScriptOrFn.getParamCount()) {
0709: // Find the parameter node of the given index
0710: Node n = fnNode.getFirstChild();
0711: for (int i = 0; i < index && n != null;) {
0712: if (n.getType() == Token.PARAMETER) {
0713: i++;
0714: if (i == index) {
0715: break;
0716: }
0717: }
0718: n = n.getParentNode();
0719: }
0720: addStrictWarning("msg.var.hides.arg", name
0721: // <netbeans> - pass in additional parameters for the error
0722: , n
0723: // </netbeans>
0724: );
0725: }
0726: }
0727:
0728: Node pn = nf.initFunction(fnNode, functionIndex, body,
0729: syntheticType);
0730: if (memberExprNode != null) {
0731: // <netbeans>
0732: // TODO - how should I update the pn offsets based on this?
0733: // </netbeans>
0734: pn = nf.createAssignment(Token.ASSIGN, memberExprNode, pn);
0735: if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
0736: // XXX check JScript behavior: should it be createExprStatement?
0737: pn = nf.createExprStatementNoReturn(pn, baseLineno);
0738: }
0739: }
0740:
0741: // <netbeans>
0742: // TODO - how does memberExprNode deal with this?
0743: pn.setSourceBounds(fnNode.getSourceStart(), fnNode
0744: .getSourceEnd());
0745: // </netbeans>
0746: return pn;
0747: }
0748:
0749: private Node statements() throws IOException {
0750: // <netbeans>
0751: int startOffset = getStartOffset();
0752: // </netbeans>
0753: Node pn = nf.createBlock(ts.getLineno());
0754:
0755: int tt;
0756: while ((tt = peekToken()) > Token.EOF && tt != Token.RC) {
0757: nf.addChildToBack(pn, statement());
0758: }
0759:
0760: // <netbeans>
0761: setSourceOffsets(pn, startOffset);
0762: // </netbeans>
0763:
0764: return pn;
0765: }
0766:
0767: private Node condition() throws IOException, ParserException {
0768: mustMatchToken(Token.LP, "msg.no.paren.cond");
0769:
0770: decompiler.addToken(Token.LP);
0771: // <netbeans>
0772: // NOTE - the END offset is AFTER the left parenthesis! We don't
0773: // want to include it since we're not creating a node wrapping the
0774: // parens!
0775: int startOffset = getEndOffset();
0776: // </netbeans>
0777: Node pn = expr(false);
0778: // <netbeans>
0779: int endOffset = getEndOffset();
0780: pn.setSourceBounds(startOffset, endOffset);
0781: // </netbeans>
0782: mustMatchToken(Token.RP, "msg.no.paren.after.cond");
0783: decompiler.addToken(Token.RP);
0784:
0785: // Report strict warning on code like "if (a = 7) ...". Suppress the
0786: // warning if the condition is parenthesized, like "if ((a = 7)) ...".
0787: if (pn.getProp(Node.PARENTHESIZED_PROP) == null
0788: && (pn.getType() == Token.SETNAME
0789: || pn.getType() == Token.SETPROP || pn
0790: .getType() == Token.SETELEM)) {
0791: addStrictWarning("msg.equal.as.assign", ""
0792: // <netbeans> - pass in additional parameters for the error
0793: , pn
0794: // </netbeans>
0795: );
0796: }
0797:
0798: return pn;
0799: }
0800:
0801: // match a NAME; return null if no match.
0802: private Node matchJumpLabelName() throws IOException,
0803: ParserException {
0804: // TODO - handle positions here?
0805: Node label = null;
0806:
0807: int tt = peekTokenOrEOL();
0808: if (tt == Token.NAME) {
0809: consumeToken();
0810: String name = ts.getString();
0811: decompiler.addName(name);
0812: if (labelSet != null) {
0813: label = (Node) labelSet.get(name);
0814: }
0815: if (label == null) {
0816: reportError("msg.undef.label");
0817: }
0818: }
0819:
0820: return label;
0821: }
0822:
0823: private Node statement() throws IOException {
0824: // <netbeans>
0825: int startOffset = getStartOffset();
0826: // </netbeans>
0827: try {
0828: Node pn = statementHelper(null);
0829: if (pn != null) {
0830: if (compilerEnv.isStrictMode() && !pn.hasSideEffects())
0831: addStrictWarning("msg.no.side.effects", ""
0832: // <netbeans> - pass in additional parameters for the error
0833: , pn
0834: // </netbeans>
0835: );
0836: return pn;
0837: }
0838: } catch (ParserException e) {
0839: }
0840:
0841: // skip to end of statement
0842: int lineno = ts.getLineno();
0843: guessingStatementEnd: for (;;) {
0844: int tt = peekTokenOrEOL();
0845: consumeToken();
0846: switch (tt) {
0847: case Token.ERROR:
0848: case Token.EOF:
0849: case Token.EOL:
0850: case Token.SEMI:
0851: break guessingStatementEnd;
0852: }
0853: }
0854: // <netbeans>
0855: //return nf.createExprStatement(nf.createName("error"), lineno);
0856: return setSourceOffsets(nf.createExprStatement(nf
0857: .createName("error"), lineno), startOffset);
0858: // </netbeans>
0859: }
0860:
0861: /**
0862: * Whether the "catch (e: e instanceof Exception) { ... }" syntax
0863: * is implemented.
0864: */
0865:
0866: private Node statementHelper(Node statementLabel)
0867: throws IOException, ParserException {
0868: Node pn = null;
0869:
0870: int tt;
0871:
0872: tt = peekToken();
0873:
0874: // <netbeans>
0875: int startOffset = peekedTokenStart;
0876: // </netbeans>
0877:
0878: switch (tt) {
0879: case Token.IF: {
0880: consumeToken();
0881:
0882: decompiler.addToken(Token.IF);
0883: int lineno = ts.getLineno();
0884: Node cond = condition();
0885: decompiler.addEOL(Token.LC);
0886: Node ifTrue = statement();
0887: Node ifFalse = null;
0888: if (matchToken(Token.ELSE)) {
0889: decompiler.addToken(Token.RC);
0890: decompiler.addToken(Token.ELSE);
0891: decompiler.addEOL(Token.LC);
0892: ifFalse = statement();
0893: }
0894: decompiler.addEOL(Token.RC);
0895: pn = nf.createIf(cond, ifTrue, ifFalse, lineno);
0896: // <netbeans>
0897: pn.setSourceBounds(startOffset, getEndOffset());
0898: // </netbeans>
0899: return pn;
0900: }
0901:
0902: case Token.SWITCH: {
0903: consumeToken();
0904:
0905: decompiler.addToken(Token.SWITCH);
0906: int lineno = ts.getLineno();
0907: mustMatchToken(Token.LP, "msg.no.paren.switch");
0908: decompiler.addToken(Token.LP);
0909: pn = enterSwitch(expr(false), lineno);
0910: try {
0911: mustMatchToken(Token.RP, "msg.no.paren.after.switch");
0912: decompiler.addToken(Token.RP);
0913: mustMatchToken(Token.LC, "msg.no.brace.switch");
0914: decompiler.addEOL(Token.LC);
0915:
0916: boolean hasDefault = false;
0917: switchLoop: for (;;) {
0918: tt = nextToken();
0919: Node caseExpression;
0920: switch (tt) {
0921: case Token.RC:
0922: break switchLoop;
0923:
0924: case Token.CASE:
0925: decompiler.addToken(Token.CASE);
0926: caseExpression = expr(false);
0927: mustMatchToken(Token.COLON, "msg.no.colon.case");
0928: decompiler.addEOL(Token.COLON);
0929: break;
0930:
0931: case Token.DEFAULT:
0932: if (hasDefault) {
0933: reportError("msg.double.switch.default");
0934: }
0935: decompiler.addToken(Token.DEFAULT);
0936: hasDefault = true;
0937: caseExpression = null;
0938: mustMatchToken(Token.COLON, "msg.no.colon.case");
0939: decompiler.addEOL(Token.COLON);
0940: break;
0941:
0942: default:
0943: reportError("msg.bad.switch");
0944: break switchLoop;
0945: }
0946:
0947: Node block = nf.createLeaf(Token.BLOCK);
0948: // <netbeans>
0949: int blockStart = getStartOffset();
0950: pn.setSourceBounds(blockStart, blockStart);
0951: // </netbeans>
0952:
0953: while ((tt = peekToken()) != Token.RC
0954: && tt != Token.CASE && tt != Token.DEFAULT
0955: && tt != Token.EOF) {
0956: nf.addChildToBack(block, statement());
0957: }
0958:
0959: // caseExpression == null => add default lable
0960: nf.addSwitchCase(pn, caseExpression, block);
0961: }
0962: decompiler.addEOL(Token.RC);
0963: nf.closeSwitch(pn);
0964: } finally {
0965: exitSwitch();
0966: }
0967: // <netbeans>
0968: setSourceOffsets(pn, startOffset);
0969: // </netbeans>
0970: return pn;
0971: }
0972:
0973: case Token.WHILE: {
0974: consumeToken();
0975: decompiler.addToken(Token.WHILE);
0976:
0977: Node loop = enterLoop(statementLabel);
0978: try {
0979: Node cond = condition();
0980: decompiler.addEOL(Token.LC);
0981: Node body = statement();
0982: decompiler.addEOL(Token.RC);
0983: pn = nf.createWhile(loop, cond, body);
0984: // <netbeans>
0985: setSourceOffsets(pn, startOffset);
0986: // </netbeans>
0987: } finally {
0988: exitLoop();
0989: }
0990: return pn;
0991: }
0992:
0993: case Token.DO: {
0994: consumeToken();
0995: decompiler.addToken(Token.DO);
0996: decompiler.addEOL(Token.LC);
0997:
0998: Node loop = enterLoop(statementLabel);
0999: try {
1000: Node body = statement();
1001: decompiler.addToken(Token.RC);
1002: mustMatchToken(Token.WHILE, "msg.no.while.do");
1003: decompiler.addToken(Token.WHILE);
1004: Node cond = condition();
1005: pn = nf.createDoWhile(loop, body, cond);
1006: } finally {
1007: exitLoop();
1008: }
1009: // Always auto-insert semicon to follow SpiderMonkey:
1010: // It is required by EMAScript but is ignored by the rest of
1011: // world, see bug 238945
1012: matchToken(Token.SEMI);
1013: decompiler.addEOL(Token.SEMI);
1014: // <netbeans>
1015: setSourceOffsets(pn, startOffset);
1016: // </netbeans>
1017: return pn;
1018: }
1019:
1020: case Token.FOR: {
1021: consumeToken();
1022: boolean isForEach = false;
1023: decompiler.addToken(Token.FOR);
1024:
1025: Node loop = enterLoop(statementLabel);
1026: try {
1027:
1028: Node init; // Node init is also foo in 'foo in Object'
1029: Node cond; // Node cond is also object in 'foo in Object'
1030: Node incr = null; // to kill warning
1031: Node body;
1032:
1033: // See if this is a for each () instead of just a for ()
1034: if (matchToken(Token.NAME)) {
1035: decompiler.addName(ts.getString());
1036: if (ts.getString().equals("each")) {
1037: isForEach = true;
1038: } else {
1039: reportError("msg.no.paren.for");
1040: }
1041: }
1042:
1043: mustMatchToken(Token.LP, "msg.no.paren.for");
1044: decompiler.addToken(Token.LP);
1045: // <netbeans>
1046: int realSourceStartOffset = getStartOffset();
1047: // </netbeans>
1048: tt = peekToken();
1049: if (tt == Token.SEMI) {
1050: init = nf.createLeaf(Token.EMPTY);
1051: } else {
1052: if (tt == Token.VAR) {
1053: // set init to a var list or initial
1054: consumeToken(); // consume the 'var' token
1055: init = variables(Token.FOR);
1056: // <netbeans>
1057: // TODO - This isn't right, there could be MULTIPLE variables... they should
1058: // all be marked somehow
1059: int realSourceEndOffset = getEndOffset();
1060: init.setSourceBounds(realSourceStartOffset,
1061: realSourceEndOffset);
1062: // </netbeans>
1063: } else {
1064: init = expr(true);
1065: }
1066: }
1067:
1068: if (matchToken(Token.IN)) {
1069: decompiler.addToken(Token.IN);
1070: // 'cond' is the object over which we're iterating
1071: cond = expr(false);
1072: } else { // ordinary for loop
1073: mustMatchToken(Token.SEMI, "msg.no.semi.for");
1074: decompiler.addToken(Token.SEMI);
1075: if (peekToken() == Token.SEMI) {
1076: // no loop condition
1077: // TODO - position?
1078: cond = nf.createLeaf(Token.EMPTY);
1079: } else {
1080: cond = expr(false);
1081: }
1082:
1083: mustMatchToken(Token.SEMI, "msg.no.semi.for.cond");
1084: decompiler.addToken(Token.SEMI);
1085: if (peekToken() == Token.RP) {
1086: incr = nf.createLeaf(Token.EMPTY);
1087: // TODO Position?
1088: } else {
1089: incr = expr(false);
1090: }
1091: }
1092:
1093: mustMatchToken(Token.RP, "msg.no.paren.for.ctrl");
1094: decompiler.addToken(Token.RP);
1095: decompiler.addEOL(Token.LC);
1096: body = statement();
1097: decompiler.addEOL(Token.RC);
1098:
1099: if (incr == null) {
1100: // cond could be null if 'in obj' got eaten
1101: // by the init node.
1102: pn = nf.createForIn(loop, init, cond, body,
1103: isForEach);
1104: } else {
1105: pn = nf.createFor(loop, init, cond, incr, body);
1106: }
1107: } finally {
1108: exitLoop();
1109: }
1110: // <netbeans>
1111: setSourceOffsets(pn, startOffset);
1112: // </netbeans>
1113: return pn;
1114: }
1115:
1116: case Token.TRY: {
1117: consumeToken();
1118: int lineno = ts.getLineno();
1119:
1120: Node tryblock;
1121: Node catchblocks = null;
1122: Node finallyblock = null;
1123:
1124: decompiler.addToken(Token.TRY);
1125: decompiler.addEOL(Token.LC);
1126: tryblock = statement();
1127: decompiler.addEOL(Token.RC);
1128:
1129: catchblocks = nf.createLeaf(Token.BLOCK);
1130:
1131: boolean sawDefaultCatch = false;
1132: int peek = peekToken();
1133: if (peek == Token.CATCH) {
1134: while (matchToken(Token.CATCH)) {
1135: if (sawDefaultCatch) {
1136: reportError("msg.catch.unreachable");
1137: }
1138: decompiler.addToken(Token.CATCH);
1139: mustMatchToken(Token.LP, "msg.no.paren.catch");
1140: decompiler.addToken(Token.LP);
1141:
1142: mustMatchToken(Token.NAME, "msg.bad.catchcond");
1143: // <netbeans>
1144: int varStart = getStartOffset();
1145: int varEnd = matchedTokenEnd;
1146: // </netbeans>
1147: String varName = ts.getString();
1148: decompiler.addName(varName);
1149:
1150: Node catchCond = null;
1151: if (matchToken(Token.IF)) {
1152: decompiler.addToken(Token.IF);
1153: catchCond = expr(false);
1154: } else {
1155: sawDefaultCatch = true;
1156: }
1157:
1158: mustMatchToken(Token.RP, "msg.bad.catchcond");
1159: decompiler.addToken(Token.RP);
1160: mustMatchToken(Token.LC, "msg.no.brace.catchblock");
1161: decompiler.addEOL(Token.LC);
1162:
1163: // <netbeans>
1164: catchblocks.setSourceBounds(startOffset,
1165: getEndOffset());
1166: // </netbeans>
1167: nf.addChildToBack(catchblocks, nf.createCatch(
1168: varName, catchCond, statements(), ts
1169: .getLineno()));
1170: // <netbeans>
1171: Node varNode = catchblocks.getLastChild()
1172: .getFirstChild();
1173: varNode.setSourceBounds(varStart, varEnd);
1174: // </netbeans>
1175:
1176: mustMatchToken(Token.RC, "msg.no.brace.after.body");
1177: decompiler.addEOL(Token.RC);
1178: }
1179: } else if (peek != Token.FINALLY) {
1180: mustMatchToken(Token.FINALLY, "msg.try.no.catchfinally");
1181: }
1182:
1183: if (matchToken(Token.FINALLY)) {
1184: decompiler.addToken(Token.FINALLY);
1185: decompiler.addEOL(Token.LC);
1186: finallyblock = statement();
1187: decompiler.addEOL(Token.RC);
1188: }
1189:
1190: pn = nf.createTryCatchFinally(tryblock, catchblocks,
1191: finallyblock, lineno);
1192:
1193: // <netbeans>
1194: setSourceOffsets(pn, startOffset);
1195: // </netbeans>
1196: return pn;
1197: }
1198:
1199: case Token.THROW: {
1200: consumeToken();
1201: if (peekTokenOrEOL() == Token.EOL) {
1202: // ECMAScript does not allow new lines before throw expression,
1203: // see bug 256617
1204: reportError("msg.bad.throw.eol");
1205: }
1206:
1207: int lineno = ts.getLineno();
1208: decompiler.addToken(Token.THROW);
1209: pn = nf.createThrow(expr(false), lineno);
1210: // <netbeans>
1211: pn.setSourceBounds(startOffset, getEndOffset());
1212: // </netbeans>
1213: break;
1214: }
1215:
1216: case Token.BREAK: {
1217: consumeToken();
1218: int lineno = ts.getLineno();
1219:
1220: decompiler.addToken(Token.BREAK);
1221:
1222: // matchJumpLabelName only matches if there is one
1223: Node breakStatement = matchJumpLabelName();
1224: if (breakStatement == null) {
1225: if (loopAndSwitchSet == null
1226: || loopAndSwitchSet.size() == 0) {
1227: reportError("msg.bad.break");
1228: return null;
1229: }
1230: breakStatement = (Node) loopAndSwitchSet.peek();
1231: }
1232: pn = nf.createBreak(breakStatement, lineno);
1233: // <netbeans>
1234: setSourceOffsets(pn, startOffset);
1235: // </netbeans>
1236: break;
1237: }
1238:
1239: case Token.CONTINUE: {
1240: consumeToken();
1241: int lineno = ts.getLineno();
1242:
1243: decompiler.addToken(Token.CONTINUE);
1244:
1245: Node loop;
1246: // matchJumpLabelName only matches if there is one
1247: Node label = matchJumpLabelName();
1248: if (label == null) {
1249: if (loopSet == null || loopSet.size() == 0) {
1250: reportError("msg.continue.outside");
1251: return null;
1252: }
1253: loop = (Node) loopSet.peek();
1254: } else {
1255: loop = nf.getLabelLoop(label);
1256: if (loop == null) {
1257: reportError("msg.continue.nonloop");
1258: return null;
1259: }
1260: }
1261: pn = nf.createContinue(loop, lineno);
1262: // <netbeans>
1263: setSourceOffsets(pn, startOffset);
1264: // </netbeans>
1265: break;
1266: }
1267:
1268: case Token.WITH: {
1269: consumeToken();
1270:
1271: decompiler.addToken(Token.WITH);
1272: int lineno = ts.getLineno();
1273: mustMatchToken(Token.LP, "msg.no.paren.with");
1274: decompiler.addToken(Token.LP);
1275: Node obj = expr(false);
1276: mustMatchToken(Token.RP, "msg.no.paren.after.with");
1277: decompiler.addToken(Token.RP);
1278: decompiler.addEOL(Token.LC);
1279:
1280: ++nestingOfWith;
1281: Node body;
1282: try {
1283: body = statement();
1284: } finally {
1285: --nestingOfWith;
1286: }
1287:
1288: decompiler.addEOL(Token.RC);
1289:
1290: pn = nf.createWith(obj, body, lineno);
1291: // <netbeans>
1292: setSourceOffsets(pn, startOffset);
1293: // </netbeans>
1294: return pn;
1295: }
1296:
1297: case Token.CONST:
1298: case Token.VAR: {
1299: consumeToken();
1300: pn = variables(tt);
1301: // <netbeans>
1302: setSourceOffsets(pn, startOffset);
1303: // </netbeans>
1304: break;
1305: }
1306:
1307: case Token.RETURN: {
1308: if (!insideFunction()) {
1309: reportError("msg.bad.return");
1310: }
1311: consumeToken();
1312: decompiler.addToken(Token.RETURN);
1313: int lineno = ts.getLineno();
1314:
1315: Node retExpr;
1316: /* This is ugly, but we don't want to require a semicolon. */
1317: tt = peekTokenOrEOL();
1318: switch (tt) {
1319: case Token.SEMI:
1320: case Token.RC:
1321: case Token.EOF:
1322: case Token.EOL:
1323: case Token.ERROR:
1324: retExpr = null;
1325: break;
1326: default:
1327: retExpr = expr(false);
1328: hasReturnValue = true;
1329: }
1330: pn = nf.createReturn(retExpr, lineno);
1331: // <netbeans>
1332: pn.setSourceBounds(startOffset, getEndOffset());
1333: // </netbeans>
1334:
1335: // see if we need a strict mode warning
1336: if (retExpr == null) {
1337: if (functionEndFlags == Node.END_RETURNS_VALUE)
1338: addStrictWarning("msg.return.inconsistent", ""
1339: // <netbeans> - pass in additional parameters for the error
1340: , pn
1341: // </netbeans>
1342: );
1343:
1344: functionEndFlags |= Node.END_RETURNS;
1345: } else {
1346: if (functionEndFlags == Node.END_RETURNS)
1347: addStrictWarning("msg.return.inconsistent", ""
1348: // <netbeans> - pass in additional parameters for the error
1349: , pn
1350: // </netbeans>
1351: );
1352:
1353: functionEndFlags |= Node.END_RETURNS_VALUE;
1354: }
1355:
1356: break;
1357: }
1358:
1359: case Token.LC:
1360: consumeToken();
1361: if (statementLabel != null) {
1362: decompiler.addToken(Token.LC);
1363: }
1364: pn = statements();
1365: mustMatchToken(Token.RC, "msg.no.brace.block");
1366: if (statementLabel != null) {
1367: decompiler.addEOL(Token.RC);
1368: }
1369: // <netbeans>
1370: pn.setSourceBounds(startOffset, getEndOffset());
1371: // </netbeans>
1372: return pn;
1373:
1374: case Token.ERROR:
1375: // Fall thru, to have a node for error recovery to work on
1376: case Token.SEMI:
1377: consumeToken();
1378: pn = nf.createLeaf(Token.EMPTY);
1379: return pn;
1380:
1381: case Token.FUNCTION: {
1382: consumeToken();
1383: pn = function(FunctionNode.FUNCTION_EXPRESSION_STATEMENT);
1384: // <netbeans>
1385: setSourceOffsets(pn, startOffset);
1386: // </netbeans>
1387: return pn;
1388: }
1389:
1390: case Token.DEFAULT:
1391: consumeToken();
1392: mustHaveXML();
1393:
1394: decompiler.addToken(Token.DEFAULT);
1395: int nsLine = ts.getLineno();
1396:
1397: if (!(matchToken(Token.NAME) && ts.getString()
1398: .equals("xml"))) {
1399: reportError("msg.bad.namespace");
1400: }
1401: decompiler.addName(" xml");
1402:
1403: if (!(matchToken(Token.NAME) && ts.getString().equals(
1404: "namespace"))) {
1405: reportError("msg.bad.namespace");
1406: }
1407: decompiler.addName(" namespace");
1408:
1409: if (!matchToken(Token.ASSIGN)) {
1410: reportError("msg.bad.namespace");
1411: }
1412: decompiler.addToken(Token.ASSIGN);
1413:
1414: Node expr = expr(false);
1415: pn = nf.createDefaultNamespace(expr, nsLine);
1416: // <netbeans>
1417: setSourceOffsets(pn, startOffset);
1418: // </netbeans>
1419: break;
1420:
1421: case Token.NAME: {
1422: int lineno = ts.getLineno();
1423: String name = ts.getString();
1424: setCheckForLabel();
1425: pn = expr(false);
1426: if (pn.getType() != Token.LABEL) {
1427: pn = nf.createExprStatement(pn, lineno);
1428: } else {
1429: // Parsed the label: push back token should be
1430: // colon that primaryExpr left untouched.
1431: if (peekToken() != Token.COLON)
1432: Kit.codeBug();
1433: consumeToken();
1434: // depend on decompiling lookahead to guess that that
1435: // last name was a label.
1436: decompiler.addName(name);
1437: decompiler.addEOL(Token.COLON);
1438:
1439: if (labelSet == null) {
1440: labelSet = new Hashtable();
1441: } else if (labelSet.containsKey(name)) {
1442: reportError("msg.dup.label");
1443: }
1444:
1445: boolean firstLabel;
1446: if (statementLabel == null) {
1447: firstLabel = true;
1448: statementLabel = pn;
1449: } else {
1450: // Discard multiple label nodes and use only
1451: // the first: it allows to simplify IRFactory
1452: firstLabel = false;
1453: }
1454: labelSet.put(name, statementLabel);
1455: try {
1456: pn = statementHelper(statementLabel);
1457: } finally {
1458: labelSet.remove(name);
1459: }
1460: if (firstLabel) {
1461: pn = nf.createLabeledStatement(statementLabel, pn);
1462: }
1463: // <netbeans>
1464: setSourceOffsets(pn, startOffset);
1465: // </netbeans>
1466: return pn;
1467: }
1468: // <netbeans>
1469: setSourceOffsets(pn, startOffset);
1470: // </netbeans>
1471: break;
1472: }
1473:
1474: default: {
1475: int lineno = ts.getLineno();
1476: pn = expr(false);
1477: pn = nf.createExprStatement(pn, lineno);
1478: // <netbeans>
1479: setSourceOffsets(pn, startOffset);
1480: // </netbeans>
1481: break;
1482: }
1483: }
1484:
1485: int ttFlagged = peekFlaggedToken();
1486: switch (ttFlagged & CLEAR_TI_MASK) {
1487: case Token.SEMI:
1488: // Consume ';' as a part of expression
1489: consumeToken();
1490: break;
1491: case Token.ERROR:
1492: case Token.EOF:
1493: case Token.RC:
1494: // Autoinsert ;
1495: break;
1496: default:
1497: if ((ttFlagged & TI_AFTER_EOL) == 0) {
1498: // Report error if no EOL or autoinsert ; otherwise
1499: reportError("msg.no.semi.stmt");
1500: }
1501: break;
1502: }
1503: decompiler.addEOL(Token.SEMI);
1504:
1505: // <netbeans>
1506: setSourceOffsets(pn, startOffset);
1507: // </netbeans>
1508:
1509: return pn;
1510: }
1511:
1512: /**
1513: * Parse a 'var' or 'const' statement, or a 'var' init list in a for
1514: * statement.
1515: * @param context A token value: either VAR, CONST or FOR depending on
1516: * context.
1517: * @return The parsed statement
1518: * @throws IOException
1519: * @throws ParserException
1520: */
1521: private Node variables(int context) throws IOException,
1522: ParserException {
1523: // <netbeans>
1524: int startOffset = getStartOffset();
1525: // </netbeans>
1526:
1527: Node pn;
1528: boolean first = true;
1529:
1530: if (context == Token.CONST) {
1531: pn = nf.createVariables(Token.CONST, ts.getLineno());
1532: decompiler.addToken(Token.CONST);
1533: } else {
1534: pn = nf.createVariables(Token.VAR, ts.getLineno());
1535: decompiler.addToken(Token.VAR);
1536: }
1537:
1538: for (;;) {
1539: Node name;
1540: Node init;
1541: mustMatchToken(Token.NAME, "msg.bad.var");
1542: // <netbeans>
1543: int nameStartOffset = getStartOffset();
1544: // </netbeans>
1545: String s = ts.getString();
1546:
1547: if (!first)
1548: decompiler.addToken(Token.COMMA);
1549: first = false;
1550:
1551: decompiler.addName(s);
1552:
1553: // <netbeans>
1554: name = nf.createName(s);
1555: // </netbeans>
1556: if (context == Token.CONST) {
1557: if (!currentScriptOrFn.addConst(s)) {
1558: // We know it's already defined, since addConst passes if
1559: // it's not defined at all. The addVar call just confirms
1560: // what it is.
1561: if (currentScriptOrFn.addVar(s) != ScriptOrFnNode.DUPLICATE_CONST)
1562: addError("msg.var.redecl", s
1563: // <netbeans>
1564: , name
1565: // </netbeans>
1566: );
1567: else
1568: addError("msg.const.redecl", s
1569: // <netbeans>
1570: , name
1571: // </netbeans>
1572: );
1573: }
1574: } else {
1575: int dupState = currentScriptOrFn.addVar(s);
1576: if (dupState == ScriptOrFnNode.DUPLICATE_CONST)
1577: addError("msg.const.redecl", s
1578: // <netbeans>
1579: , name
1580: // </netbeans>
1581: );
1582: else if (dupState == ScriptOrFnNode.DUPLICATE_PARAMETER)
1583: addStrictWarning("msg.var.hides.arg", s
1584: // <netbeans> - pass in additional parameters for the error
1585: , name
1586: // </netbeans>
1587: );
1588: else if (dupState == ScriptOrFnNode.DUPLICATE_VAR)
1589: addStrictWarning("msg.var.redecl", s
1590: // <netbeans> - pass in additional parameters for the error
1591: , name
1592: // </netbeans>
1593: );
1594: }
1595: // <netbeans>
1596: // Moved up before the if so we can pass it to the error handler
1597: //name = nf.createName(s);
1598: // </netbeans>
1599:
1600: // <netbeans>
1601: setSourceOffsets(name, nameStartOffset);
1602: // </netbeans>
1603:
1604: // omitted check for argument hiding
1605:
1606: if (matchToken(Token.ASSIGN)) {
1607: decompiler.addToken(Token.ASSIGN);
1608:
1609: init = assignExpr(context == Token.FOR);
1610: nf.addChildToBack(name, init);
1611: }
1612: nf.addChildToBack(pn, name);
1613: if (!matchToken(Token.COMMA))
1614: break;
1615: }
1616:
1617: // <netbeans>
1618: pn.setSourceBounds(startOffset, getEndOffset());
1619: // </netbeans>
1620:
1621: return pn;
1622: }
1623:
1624: private Node expr(boolean inForInit) throws IOException,
1625: ParserException {
1626: // <netbeans>
1627: int startOffset = getStartOffset();
1628: // </netbeans>
1629:
1630: Node pn = assignExpr(inForInit);
1631: while (matchToken(Token.COMMA)) {
1632: decompiler.addToken(Token.COMMA);
1633: if (compilerEnv.isStrictMode() && !pn.hasSideEffects())
1634: addStrictWarning("msg.no.side.effects", ""
1635: // <netbeans>
1636: , pn
1637: // </netbeans>
1638: );
1639: pn = nf
1640: .createBinary(Token.COMMA, pn,
1641: assignExpr(inForInit));
1642: }
1643:
1644: // <netbeans>
1645: setSourceOffsets(pn, startOffset);
1646: // </netbeans>
1647:
1648: return pn;
1649: }
1650:
1651: private Node assignExpr(boolean inForInit) throws IOException,
1652: ParserException {
1653: // <netbeans>
1654: int startOffset = getStartOffset();
1655: // </netbeans>
1656:
1657: Node pn = condExpr(inForInit);
1658:
1659: int tt = peekToken();
1660: if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN) {
1661: consumeToken();
1662: decompiler.addToken(tt);
1663: pn = nf.createAssignment(tt, pn, assignExpr(inForInit));
1664: }
1665:
1666: // <netbeans>
1667: setSourceOffsets(pn, startOffset);
1668: // </netbeans>
1669:
1670: return pn;
1671: }
1672:
1673: private Node condExpr(boolean inForInit) throws IOException,
1674: ParserException {
1675: // <netbeans>
1676: int startOffset = getStartOffset();
1677: // </netbeans>
1678:
1679: Node pn = orExpr(inForInit);
1680:
1681: if (matchToken(Token.HOOK)) {
1682: decompiler.addToken(Token.HOOK);
1683: Node ifTrue = assignExpr(false);
1684: mustMatchToken(Token.COLON, "msg.no.colon.cond");
1685: decompiler.addToken(Token.COLON);
1686: Node ifFalse = assignExpr(inForInit);
1687: return nf.createCondExpr(pn, ifTrue, ifFalse);
1688: }
1689:
1690: // <netbeans>
1691: setSourceOffsets(pn, startOffset);
1692: // </netbeans>
1693:
1694: return pn;
1695: }
1696:
1697: private Node orExpr(boolean inForInit) throws IOException,
1698: ParserException {
1699: // <netbeans>
1700: int startOffset = getStartOffset();
1701: // </netbeans>
1702:
1703: Node pn = andExpr(inForInit);
1704: if (matchToken(Token.OR)) {
1705: decompiler.addToken(Token.OR);
1706: pn = nf.createBinary(Token.OR, pn, orExpr(inForInit));
1707: }
1708:
1709: // <netbeans>
1710: setSourceOffsets(pn, startOffset);
1711: // </netbeans>
1712:
1713: return pn;
1714: }
1715:
1716: private Node andExpr(boolean inForInit) throws IOException,
1717: ParserException {
1718: // <netbeans>
1719: int startOffset = getStartOffset();
1720: // </netbeans>
1721:
1722: Node pn = bitOrExpr(inForInit);
1723: if (matchToken(Token.AND)) {
1724: decompiler.addToken(Token.AND);
1725: pn = nf.createBinary(Token.AND, pn, andExpr(inForInit));
1726: }
1727:
1728: // <netbeans>
1729: setSourceOffsets(pn, startOffset);
1730: // </netbeans>
1731:
1732: return pn;
1733: }
1734:
1735: private Node bitOrExpr(boolean inForInit) throws IOException,
1736: ParserException {
1737: // <netbeans>
1738: int startOffset = getStartOffset();
1739: // </netbeans>
1740:
1741: Node pn = bitXorExpr(inForInit);
1742: while (matchToken(Token.BITOR)) {
1743: decompiler.addToken(Token.BITOR);
1744: pn = nf
1745: .createBinary(Token.BITOR, pn,
1746: bitXorExpr(inForInit));
1747: }
1748:
1749: // <netbeans>
1750: setSourceOffsets(pn, startOffset);
1751: // </netbeans>
1752:
1753: return pn;
1754: }
1755:
1756: private Node bitXorExpr(boolean inForInit) throws IOException,
1757: ParserException {
1758: // <netbeans>
1759: int startOffset = getStartOffset();
1760: // </netbeans>
1761:
1762: Node pn = bitAndExpr(inForInit);
1763: while (matchToken(Token.BITXOR)) {
1764: decompiler.addToken(Token.BITXOR);
1765: pn = nf.createBinary(Token.BITXOR, pn,
1766: bitAndExpr(inForInit));
1767: }
1768:
1769: // <netbeans>
1770: setSourceOffsets(pn, startOffset);
1771: // </netbeans>
1772:
1773: return pn;
1774: }
1775:
1776: private Node bitAndExpr(boolean inForInit) throws IOException,
1777: ParserException {
1778: // <netbeans>
1779: int startOffset = getStartOffset();
1780: // </netbeans>
1781:
1782: Node pn = eqExpr(inForInit);
1783: while (matchToken(Token.BITAND)) {
1784: decompiler.addToken(Token.BITAND);
1785: pn = nf.createBinary(Token.BITAND, pn, eqExpr(inForInit));
1786: }
1787:
1788: // <netbeans>
1789: setSourceOffsets(pn, startOffset);
1790: // </netbeans>
1791:
1792: return pn;
1793: }
1794:
1795: private Node eqExpr(boolean inForInit) throws IOException,
1796: ParserException {
1797: // <netbeans>
1798: int startOffset = getStartOffset();
1799: // </netbeans>
1800:
1801: Node pn = relExpr(inForInit);
1802: for (;;) {
1803: int tt = peekToken();
1804: switch (tt) {
1805: case Token.EQ:
1806: case Token.NE:
1807: case Token.SHEQ:
1808: case Token.SHNE:
1809: consumeToken();
1810: int decompilerToken = tt;
1811: int parseToken = tt;
1812: if (compilerEnv.getLanguageVersion() == Context.VERSION_1_2) {
1813: // JavaScript 1.2 uses shallow equality for == and != .
1814: // In addition, convert === and !== for decompiler into
1815: // == and != since the decompiler is supposed to show
1816: // canonical source and in 1.2 ===, !== are allowed
1817: // only as an alias to ==, !=.
1818: switch (tt) {
1819: case Token.EQ:
1820: parseToken = Token.SHEQ;
1821: break;
1822: case Token.NE:
1823: parseToken = Token.SHNE;
1824: break;
1825: case Token.SHEQ:
1826: decompilerToken = Token.EQ;
1827: break;
1828: case Token.SHNE:
1829: decompilerToken = Token.NE;
1830: break;
1831: }
1832: }
1833: decompiler.addToken(decompilerToken);
1834: pn = nf
1835: .createBinary(parseToken, pn,
1836: relExpr(inForInit));
1837: continue;
1838: }
1839: break;
1840: }
1841:
1842: // <netbeans>
1843: setSourceOffsets(pn, startOffset);
1844: // </netbeans>
1845:
1846: return pn;
1847: }
1848:
1849: private Node relExpr(boolean inForInit) throws IOException,
1850: ParserException {
1851: // <netbeans>
1852: int startOffset = getStartOffset();
1853: // </netbeans>
1854:
1855: Node pn = shiftExpr();
1856: for (;;) {
1857: int tt = peekToken();
1858: switch (tt) {
1859: case Token.IN:
1860: if (inForInit)
1861: break;
1862: // fall through
1863: case Token.INSTANCEOF:
1864: case Token.LE:
1865: case Token.LT:
1866: case Token.GE:
1867: case Token.GT:
1868: consumeToken();
1869: decompiler.addToken(tt);
1870: pn = nf.createBinary(tt, pn, shiftExpr());
1871: continue;
1872: }
1873: break;
1874: }
1875:
1876: // <netbeans>
1877: setSourceOffsets(pn, startOffset);
1878: // </netbeans>
1879:
1880: return pn;
1881: }
1882:
1883: private Node shiftExpr() throws IOException, ParserException {
1884: // <netbeans>
1885: int startOffset = getStartOffset();
1886: // </netbeans>
1887:
1888: Node pn = addExpr();
1889: for (;;) {
1890: int tt = peekToken();
1891: switch (tt) {
1892: case Token.LSH:
1893: case Token.URSH:
1894: case Token.RSH:
1895: consumeToken();
1896: decompiler.addToken(tt);
1897: pn = nf.createBinary(tt, pn, addExpr());
1898: continue;
1899: }
1900: break;
1901: }
1902:
1903: // <netbeans>
1904: setSourceOffsets(pn, startOffset);
1905: // </netbeans>
1906:
1907: return pn;
1908: }
1909:
1910: private Node addExpr() throws IOException, ParserException {
1911: // <netbeans>
1912: int startOffset = getStartOffset();
1913: // </netbeans>
1914:
1915: Node pn = mulExpr();
1916: for (;;) {
1917: int tt = peekToken();
1918: if (tt == Token.ADD || tt == Token.SUB) {
1919: consumeToken();
1920: decompiler.addToken(tt);
1921: // flushNewLines
1922: pn = nf.createBinary(tt, pn, mulExpr());
1923: continue;
1924: }
1925: break;
1926: }
1927:
1928: // <netbeans>
1929: setSourceOffsets(pn, startOffset);
1930: // </netbeans>
1931:
1932: return pn;
1933: }
1934:
1935: private Node mulExpr() throws IOException, ParserException {
1936: // <netbeans>
1937: int startOffset = getStartOffset();
1938: // </netbeans>
1939:
1940: Node pn = unaryExpr();
1941: for (;;) {
1942: int tt = peekToken();
1943: switch (tt) {
1944: case Token.MUL:
1945: case Token.DIV:
1946: case Token.MOD:
1947: consumeToken();
1948: decompiler.addToken(tt);
1949: pn = nf.createBinary(tt, pn, unaryExpr());
1950: continue;
1951: }
1952: break;
1953: }
1954:
1955: // <netbeans>
1956: setSourceOffsets(pn, startOffset);
1957: // </netbeans>
1958:
1959: return pn;
1960: }
1961:
1962: private Node unaryExpr() throws IOException, ParserException {
1963: int tt;
1964:
1965: tt = peekToken();
1966:
1967: // <netbeans>
1968: int startOffset = getStartOffset();
1969: // </netbeans>
1970:
1971: switch (tt) {
1972: case Token.VOID:
1973: case Token.NOT:
1974: case Token.BITNOT:
1975: case Token.TYPEOF:
1976: consumeToken();
1977: decompiler.addToken(tt);
1978: // <netbeans>
1979: //return nf.createUnary(tt, unaryExpr());
1980: return setSourceOffsets(nf.createUnary(tt, unaryExpr()),
1981: startOffset);
1982: // </netbeans>
1983:
1984: case Token.ADD:
1985: consumeToken();
1986: // Convert to special POS token in decompiler and parse tree
1987: decompiler.addToken(Token.POS);
1988: // <netbeans>
1989: //return nf.createUnary(Token.POS, unaryExpr());
1990: return setSourceOffsets(nf.createUnary(Token.POS,
1991: unaryExpr()), startOffset);
1992: // </netbeans>
1993:
1994: case Token.SUB:
1995: consumeToken();
1996: // Convert to special NEG token in decompiler and parse tree
1997: decompiler.addToken(Token.NEG);
1998: // <netbeans>
1999: //return nf.createUnary(Token.NEG, unaryExpr());
2000: return setSourceOffsets(nf.createUnary(Token.NEG,
2001: unaryExpr()), startOffset);
2002: // </netbeans>
2003:
2004: case Token.INC:
2005: case Token.DEC:
2006: consumeToken();
2007: decompiler.addToken(tt);
2008: // <netbeans>
2009: //return nf.createIncDec(tt, false, memberExpr(true));
2010: return setSourceOffsets(nf.createIncDec(tt, false,
2011: memberExpr(true)), startOffset);
2012: // </netbeans>
2013:
2014: case Token.DELPROP:
2015: consumeToken();
2016: decompiler.addToken(Token.DELPROP);
2017: // <netbeans>
2018: //return nf.createUnary(Token.DELPROP, unaryExpr());
2019: return setSourceOffsets(nf.createUnary(Token.DELPROP,
2020: unaryExpr()), startOffset);
2021: // </netbeans>
2022:
2023: case Token.ERROR:
2024: consumeToken();
2025: break;
2026:
2027: // XML stream encountered in expression.
2028: case Token.LT:
2029: if (compilerEnv.isXmlAvailable()) {
2030: consumeToken();
2031: Node pn = xmlInitializer();
2032: // <netbeans>
2033: //return memberExprTail(true, pn);
2034: return setSourceOffsets(memberExprTail(true, pn),
2035: startOffset);
2036: // </netbeans>
2037: }
2038: // Fall thru to the default handling of RELOP
2039:
2040: default:
2041: Node pn = memberExpr(true);
2042:
2043: // Don't look across a newline boundary for a postfix incop.
2044: tt = peekTokenOrEOL();
2045: if (tt == Token.INC || tt == Token.DEC) {
2046: consumeToken();
2047: decompiler.addToken(tt);
2048: // <netbeans>
2049: //return nf.createIncDec(tt, true, pn);
2050: return setSourceOffsets(nf.createIncDec(tt, true, pn),
2051: startOffset);
2052: // </netbeans>
2053: }
2054:
2055: // <netbeans>
2056: setSourceOffsets(pn, startOffset);
2057: // </netbeans>
2058:
2059: return pn;
2060: }
2061: // <netbeans>
2062: return nf.createName("err"); // Only reached on error. Try to continue.
2063: // </netbeans>
2064:
2065: }
2066:
2067: // <netbeans>
2068: // TODO - rename to something like setSourceOffsets
2069: Node setSourceOffsets(Node n, int startOffset) {
2070: if (n.getSourceEnd() != 0) {
2071: return n;
2072: }
2073: int endOffset = matchedTokenEnd;
2074: n.setSourceBounds(startOffset, endOffset);
2075: // Return n such that expressions can be chained, e.g
2076: // return factory.createNumber(42)
2077: // can be written as
2078: // return factory.createNumber(42).setSourceOffsets(n, startOffset)
2079: return n;
2080: }
2081:
2082: int getStartOffset() {
2083: return matchedTokenStart;
2084: }
2085:
2086: int getEndOffset() {
2087: return matchedTokenEnd;
2088: }
2089:
2090: // </netbeans>
2091:
2092: private Node xmlInitializer() throws IOException {
2093: // <netbeans>
2094: int startOffset = getStartOffset();
2095: // </netbeans>
2096:
2097: int tt = ts.getFirstXMLToken();
2098: if (tt != Token.XML && tt != Token.XMLEND) {
2099: reportError("msg.syntax");
2100: return null;
2101: }
2102:
2103: /* Make a NEW node to append to. */
2104: Node pnXML = nf.createLeaf(Token.NEW);
2105:
2106: String xml = ts.getString();
2107: boolean fAnonymous = xml.trim().startsWith("<>");
2108:
2109: Node pn = nf.createName(fAnonymous ? "XMLList" : "XML");
2110: nf.addChildToBack(pnXML, pn);
2111:
2112: pn = null;
2113: Node expr;
2114: for (;; tt = ts.getNextXMLToken()) {
2115: switch (tt) {
2116: case Token.XML:
2117: xml = ts.getString();
2118: decompiler.addName(xml);
2119: mustMatchToken(Token.LC, "msg.syntax");
2120: decompiler.addToken(Token.LC);
2121: expr = (peekToken() == Token.RC) ? nf.createString("")
2122: : expr(false);
2123: mustMatchToken(Token.RC, "msg.syntax");
2124: decompiler.addToken(Token.RC);
2125: if (pn == null) {
2126: pn = nf.createString(xml);
2127: } else {
2128: pn = nf.createBinary(Token.ADD, pn, nf
2129: .createString(xml));
2130: }
2131: if (ts.isXMLAttribute()) {
2132: /* Need to put the result in double quotes */
2133: expr = nf.createUnary(Token.ESCXMLATTR, expr);
2134: Node prepend = nf.createBinary(Token.ADD, nf
2135: .createString("\""), expr);
2136: expr = nf.createBinary(Token.ADD, prepend, nf
2137: .createString("\""));
2138: } else {
2139: expr = nf.createUnary(Token.ESCXMLTEXT, expr);
2140: }
2141: pn = nf.createBinary(Token.ADD, pn, expr);
2142: break;
2143: case Token.XMLEND:
2144: xml = ts.getString();
2145: decompiler.addName(xml);
2146: if (pn == null) {
2147: pn = nf.createString(xml);
2148: } else {
2149: pn = nf.createBinary(Token.ADD, pn, nf
2150: .createString(xml));
2151: }
2152:
2153: nf.addChildToBack(pnXML, pn);
2154:
2155: // <netbeans>
2156: setSourceOffsets(pnXML, startOffset);
2157: // </netbeans>
2158:
2159: return pnXML;
2160: default:
2161: reportError("msg.syntax");
2162: return null;
2163: }
2164: }
2165: }
2166:
2167: private void argumentList(Node listNode) throws IOException,
2168: ParserException {
2169: // <netbeans>
2170: int startOffset = getStartOffset();
2171: // </netbeans>
2172:
2173: boolean matched;
2174: matched = matchToken(Token.RP);
2175: if (!matched) {
2176: boolean first = true;
2177: do {
2178: if (!first)
2179: decompiler.addToken(Token.COMMA);
2180: first = false;
2181: nf.addChildToBack(listNode, assignExpr(false));
2182: } while (matchToken(Token.COMMA));
2183:
2184: mustMatchToken(Token.RP, "msg.no.paren.arg");
2185: }
2186:
2187: // <netbeans>
2188: setSourceOffsets(listNode, startOffset);
2189: // </netbeans>
2190:
2191: decompiler.addToken(Token.RP);
2192: }
2193:
2194: private Node memberExpr(boolean allowCallSyntax)
2195: throws IOException, ParserException {
2196: int tt;
2197:
2198: Node pn;
2199:
2200: /* Check for new expressions. */
2201: tt = peekToken();
2202:
2203: // <netbeans>
2204: int startOffset = getStartOffset();
2205: // </netbeans>
2206:
2207: if (tt == Token.NEW) {
2208: /* Eat the NEW token. */
2209: consumeToken();
2210: decompiler.addToken(Token.NEW);
2211:
2212: /* Make a NEW node to append to. */
2213: pn = nf.createCallOrNew(Token.NEW, memberExpr(false));
2214:
2215: if (matchToken(Token.LP)) {
2216: decompiler.addToken(Token.LP);
2217: /* Add the arguments to pn, if any are supplied. */
2218: argumentList(pn);
2219: }
2220:
2221: /* XXX there's a check in the C source against
2222: * "too many constructor arguments" - how many
2223: * do we claim to support?
2224: */
2225:
2226: /* Experimental syntax: allow an object literal to follow a new expression,
2227: * which will mean a kind of anonymous class built with the JavaAdapter.
2228: * the object literal will be passed as an additional argument to the constructor.
2229: */
2230: tt = peekToken();
2231: if (tt == Token.LC) {
2232: nf.addChildToBack(pn, primaryExpr());
2233: }
2234: } else {
2235: pn = primaryExpr();
2236: }
2237:
2238: // <netbeans>
2239: setSourceOffsets(pn, startOffset);
2240: // </netbeans>
2241:
2242: return memberExprTail(allowCallSyntax, pn);
2243: }
2244:
2245: private Node memberExprTail(boolean allowCallSyntax, Node pn)
2246: throws IOException, ParserException {
2247: // <netbeans>
2248: //int startOffset = getStartOffset();
2249: assert pn.getSourceStart() <= getStartOffset() : pn
2250: .getSourceStart()
2251: + "," + getStartOffset();
2252: int startOffset = pn.getSourceStart();
2253: // </netbeans>
2254:
2255: tailLoop: for (;;) {
2256: int tt = peekToken();
2257: switch (tt) {
2258:
2259: case Token.DOT:
2260: case Token.DOTDOT: {
2261: int memberTypeFlags;
2262: String s;
2263:
2264: consumeToken();
2265: decompiler.addToken(tt);
2266: memberTypeFlags = 0;
2267: if (tt == Token.DOTDOT) {
2268: mustHaveXML();
2269: memberTypeFlags = Node.DESCENDANTS_FLAG;
2270: }
2271: if (!compilerEnv.isXmlAvailable()) {
2272: mustMatchToken(Token.NAME, "msg.no.name.after.dot");
2273: s = ts.getString();
2274: decompiler.addName(s);
2275: pn = nf.createPropertyGet(pn, null, s,
2276: memberTypeFlags);
2277: break;
2278: }
2279:
2280: tt = nextToken();
2281: switch (tt) {
2282: // handles: name, ns::name, ns::*, ns::[expr]
2283: case Token.NAME:
2284: s = ts.getString();
2285: decompiler.addName(s);
2286: pn = propertyName(pn, s, memberTypeFlags);
2287: // <netbeans>
2288: setSourceOffsets(pn.getLastChild(),
2289: getStartOffset());
2290: // </netbeans>
2291: break;
2292:
2293: // handles: *, *::name, *::*, *::[expr]
2294: case Token.MUL:
2295: decompiler.addName("*");
2296: pn = propertyName(pn, "*", memberTypeFlags);
2297: break;
2298:
2299: // handles: '@attr', '@ns::attr', '@ns::*', '@ns::*',
2300: // '@::attr', '@::*', '@*', '@*::attr', '@*::*'
2301: case Token.XMLATTR:
2302: decompiler.addToken(Token.XMLATTR);
2303: pn = attributeAccess(pn, memberTypeFlags);
2304: break;
2305:
2306: default:
2307: reportError("msg.no.name.after.dot");
2308: }
2309: }
2310: break;
2311:
2312: case Token.DOTQUERY:
2313: consumeToken();
2314: mustHaveXML();
2315: decompiler.addToken(Token.DOTQUERY);
2316: pn = nf.createDotQuery(pn, expr(false), ts.getLineno());
2317: mustMatchToken(Token.RP, "msg.no.paren");
2318: decompiler.addToken(Token.RP);
2319: break;
2320:
2321: case Token.LB:
2322: consumeToken();
2323: decompiler.addToken(Token.LB);
2324: pn = nf.createElementGet(pn, null, expr(false), 0);
2325: mustMatchToken(Token.RB, "msg.no.bracket.index");
2326: decompiler.addToken(Token.RB);
2327: break;
2328:
2329: case Token.LP:
2330: if (!allowCallSyntax) {
2331: break tailLoop;
2332: }
2333: consumeToken();
2334: decompiler.addToken(Token.LP);
2335: pn = nf.createCallOrNew(Token.CALL, pn);
2336: /* Add the arguments to pn, if any are supplied. */
2337: argumentList(pn);
2338: break;
2339:
2340: default:
2341: break tailLoop;
2342: }
2343: }
2344: // <netbeans>
2345: pn.setSourceBounds(startOffset, getEndOffset());
2346: // </netbeans>
2347:
2348: return pn;
2349: }
2350:
2351: /*
2352: * Xml attribute expression:
2353: * '@attr', '@ns::attr', '@ns::*', '@ns::*', '@*', '@*::attr', '@*::*'
2354: */
2355: private Node attributeAccess(Node pn, int memberTypeFlags)
2356: throws IOException {
2357: // <netbeans>
2358: int startOffset = getStartOffset();
2359: // </netbeans>
2360:
2361: memberTypeFlags |= Node.ATTRIBUTE_FLAG;
2362: int tt = nextToken();
2363:
2364: switch (tt) {
2365: // handles: @name, @ns::name, @ns::*, @ns::[expr]
2366: case Token.NAME: {
2367: String s = ts.getString();
2368: decompiler.addName(s);
2369: pn = propertyName(pn, s, memberTypeFlags);
2370: }
2371: break;
2372:
2373: // handles: @*, @*::name, @*::*, @*::[expr]
2374: case Token.MUL:
2375: decompiler.addName("*");
2376: pn = propertyName(pn, "*", memberTypeFlags);
2377: break;
2378:
2379: // handles @[expr]
2380: case Token.LB:
2381: decompiler.addToken(Token.LB);
2382: pn = nf.createElementGet(pn, null, expr(false),
2383: memberTypeFlags);
2384: mustMatchToken(Token.RB, "msg.no.bracket.index");
2385: decompiler.addToken(Token.RB);
2386: break;
2387:
2388: default:
2389: reportError("msg.no.name.after.xmlAttr");
2390: pn = nf.createPropertyGet(pn, null, "?", memberTypeFlags);
2391: break;
2392: }
2393:
2394: // <netbeans>
2395: setSourceOffsets(pn, startOffset);
2396: // </netbeans>
2397:
2398: return pn;
2399: }
2400:
2401: /**
2402: * Check if :: follows name in which case it becomes qualified name
2403: */
2404: private Node propertyName(Node pn, String name, int memberTypeFlags)
2405: throws IOException, ParserException {
2406: // <netbeans>
2407: //int startOffset = getStartOffset();
2408: int startOffset = matchedTokenStart;
2409: // </netbeans>
2410:
2411: String namespace = null;
2412: if (matchToken(Token.COLONCOLON)) {
2413: decompiler.addToken(Token.COLONCOLON);
2414: namespace = name;
2415:
2416: int tt = nextToken();
2417: switch (tt) {
2418: // handles name::name
2419: case Token.NAME:
2420: name = ts.getString();
2421: decompiler.addName(name);
2422: break;
2423:
2424: // handles name::*
2425: case Token.MUL:
2426: decompiler.addName("*");
2427: name = "*";
2428: break;
2429:
2430: // handles name::[expr]
2431: case Token.LB:
2432: decompiler.addToken(Token.LB);
2433: pn = nf.createElementGet(pn, namespace, expr(false),
2434: memberTypeFlags);
2435: mustMatchToken(Token.RB, "msg.no.bracket.index");
2436: decompiler.addToken(Token.RB);
2437:
2438: // <netbeans>
2439: setSourceOffsets(pn, startOffset);
2440: // </netbeans>
2441:
2442: return pn;
2443:
2444: default:
2445: reportError("msg.no.name.after.coloncolon");
2446: name = "?";
2447: }
2448: }
2449:
2450: pn = nf.createPropertyGet(pn, namespace, name, memberTypeFlags);
2451:
2452: // <netbeans>
2453: setSourceOffsets(pn, startOffset);
2454: // </netbeans>
2455:
2456: return pn;
2457: }
2458:
2459: private Node primaryExpr() throws IOException, ParserException {
2460: Node pn;
2461:
2462: int ttFlagged = nextFlaggedToken();
2463: int tt = ttFlagged & CLEAR_TI_MASK;
2464: // <netbeans>
2465: int startOffset = matchedTokenStart;
2466: // </netbeans>
2467:
2468: switch (tt) {
2469:
2470: case Token.FUNCTION: {
2471: // <netbeans>
2472: //return function(FunctionNode.FUNCTION_EXPRESSION);
2473: Node fn = function(FunctionNode.FUNCTION_EXPRESSION);
2474: if (jsonMode) {
2475: addError("msg.json.error", Token.fullName(tt), fn);
2476: }
2477: return fn;
2478: // </netbeans>
2479: }
2480:
2481: case Token.LB: {
2482: ObjArray elems = new ObjArray();
2483: int skipCount = 0;
2484: decompiler.addToken(Token.LB);
2485: boolean after_lb_or_comma = true;
2486: for (;;) {
2487: tt = peekToken();
2488:
2489: if (tt == Token.COMMA) {
2490: consumeToken();
2491: decompiler.addToken(Token.COMMA);
2492: if (!after_lb_or_comma) {
2493: after_lb_or_comma = true;
2494: } else {
2495: elems.add(null);
2496: ++skipCount;
2497: }
2498: } else if (tt == Token.RB) {
2499: consumeToken();
2500: decompiler.addToken(Token.RB);
2501: break;
2502: } else {
2503: if (!after_lb_or_comma) {
2504: reportError("msg.no.bracket.arg");
2505: }
2506: elems.add(assignExpr(false));
2507: after_lb_or_comma = false;
2508: }
2509: }
2510: // <netbeans>
2511: //return nf.createArrayLiteral(elems, skipCount);
2512: return setSourceOffsets(nf.createArrayLiteral(elems,
2513: skipCount), startOffset);
2514: // </netbeans>
2515: }
2516:
2517: case Token.LC: {
2518: ObjArray elems = new ObjArray();
2519: // <netbeans>
2520: List<Node> nameNodes = new ArrayList<Node>();
2521: // </netbeans>
2522: decompiler.addToken(Token.LC);
2523: if (!matchToken(Token.RC)) {
2524:
2525: boolean first = true;
2526: commaloop: do {
2527: Object property;
2528:
2529: if (!first)
2530: decompiler.addToken(Token.COMMA);
2531: else
2532: first = false;
2533:
2534: tt = peekToken();
2535: switch (tt) {
2536: case Token.NAME:
2537: // <netbeans>
2538: if (jsonMode) {
2539: addError("msg.json.error", Token
2540: .fullName(tt), null);
2541: }
2542: // </netbeans>
2543:
2544: case Token.STRING:
2545: consumeToken();
2546: // map NAMEs to STRINGs in object literal context
2547: // but tell the decompiler the proper type
2548: String s = ts.getString();
2549: if (tt == Token.NAME) {
2550: if (s.equals("get")
2551: && peekToken() == Token.NAME) {
2552: decompiler.addToken(Token.GET);
2553: consumeToken();
2554: s = ts.getString();
2555: decompiler.addName(s);
2556: property = ScriptRuntime
2557: .getIndexObject(s);
2558: if (!getterSetterProperty(elems,
2559: property, true))
2560: break commaloop;
2561: break;
2562: } else if (s.equals("set")
2563: && peekToken() == Token.NAME) {
2564: decompiler.addToken(Token.SET);
2565: consumeToken();
2566: s = ts.getString();
2567: decompiler.addName(s);
2568: property = ScriptRuntime
2569: .getIndexObject(s);
2570: if (!getterSetterProperty(elems,
2571: property, false))
2572: break commaloop;
2573: break;
2574: }
2575: decompiler.addName(s);
2576: } else {
2577: decompiler.addString(s);
2578: }
2579: // <netbeans>
2580: int nameStart = matchedTokenStart;
2581: // </netbeans>
2582: property = ScriptRuntime.getIndexObject(s);
2583: plainProperty(elems, property);
2584: // <netbeans>
2585: if (elems.size() > 0) {
2586: Node rhs = (Node) elems
2587: .get(elems.size() - 1);
2588: Node objLitName = new Node.LabelledNode(s,
2589: rhs);
2590: objLitName.setSourceBounds(nameStart,
2591: nameStart + s.length());
2592: nameNodes.add(objLitName);
2593: }
2594: // </netbeans>
2595: break;
2596:
2597: case Token.NUMBER:
2598: consumeToken();
2599: double n = ts.getNumber();
2600: decompiler.addNumber(n);
2601: property = ScriptRuntime.getIndexObject(n);
2602: plainProperty(elems, property);
2603: break;
2604:
2605: case Token.RC:
2606: // trailing comma is OK.
2607: break commaloop;
2608: default:
2609: reportError("msg.bad.prop");
2610: break commaloop;
2611: }
2612: } while (matchToken(Token.COMMA));
2613:
2614: mustMatchToken(Token.RC, "msg.no.brace.prop");
2615: }
2616: decompiler.addToken(Token.RC);
2617: // <netbeans>
2618: //return nf.createObjectLiteral(elems);
2619: Node literal = nf.createObjectLiteral(elems);
2620: literal.setSourceBounds(startOffset, getEndOffset());
2621: for (Node n : nameNodes) {
2622: literal.addChildToBack(n);
2623: }
2624: return literal;
2625: // </netbeans>
2626: }
2627:
2628: case Token.LP:
2629: // <netbeans>
2630: if (jsonMode) {
2631: addError("msg.json.error", Token.fullName(tt), null);
2632: }
2633: // </netbeans>
2634:
2635: /* Brendan's IR-jsparse.c makes a new node tagged with
2636: * TOK_LP here... I'm not sure I understand why. Isn't
2637: * the grouping already implicit in the structure of the
2638: * parse tree? also TOK_LP is already overloaded (I
2639: * think) in the C IR as 'function call.' */
2640: decompiler.addToken(Token.LP);
2641: pn = expr(false);
2642: pn.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE);
2643: decompiler.addToken(Token.RP);
2644: mustMatchToken(Token.RP, "msg.no.paren");
2645: // <netbeans>
2646: setSourceOffsets(pn, startOffset);
2647: // </netbeans>
2648: return pn;
2649:
2650: case Token.XMLATTR:
2651: mustHaveXML();
2652: decompiler.addToken(Token.XMLATTR);
2653: pn = attributeAccess(null, 0);
2654: // <netbeans>
2655: setSourceOffsets(pn, startOffset);
2656: // </netbeans>
2657: return pn;
2658:
2659: case Token.NAME: {
2660: // <netbeans>
2661: if (jsonMode) {
2662: addError("msg.json.error", Token.fullName(tt), null);
2663: }
2664: // </netbeans>
2665: String name = ts.getString();
2666: if ((ttFlagged & TI_CHECK_LABEL) != 0) {
2667: if (peekToken() == Token.COLON) {
2668: // Do not consume colon, it is used as unwind indicator
2669: // to return to statementHelper.
2670: // XXX Better way?
2671: // TODO - create position?
2672: return nf.createLabel(ts.getLineno());
2673: }
2674: }
2675:
2676: decompiler.addName(name);
2677: if (compilerEnv.isXmlAvailable()) {
2678: pn = propertyName(null, name, 0);
2679: } else {
2680: pn = nf.createName(name);
2681: }
2682: // <netbeans>
2683: if (pn.getType() == Token.NAME) {
2684: pn.setSourceBounds(startOffset, startOffset
2685: + name.length());
2686: } else {
2687: setSourceOffsets(pn, startOffset);
2688: }
2689: // </netbeans>
2690: return pn;
2691: }
2692:
2693: case Token.NUMBER: {
2694: double n = ts.getNumber();
2695: decompiler.addNumber(n);
2696: // <netbeans>
2697: //return nf.createNumber(n);
2698: return setSourceOffsets(nf.createNumber(n), startOffset);
2699: // </netbeans>
2700: }
2701:
2702: case Token.STRING: {
2703: String s = ts.getString();
2704: decompiler.addString(s);
2705: // <netbeans>
2706: //return nf.createString(s);
2707: return setSourceOffsets(nf.createString(s), startOffset);
2708: // </netbeans>
2709: }
2710:
2711: case Token.DIV:
2712: case Token.ASSIGN_DIV: {
2713: // Got / or /= which should be treated as regexp in fact
2714: ts.readRegExp(tt);
2715: String flags = ts.regExpFlags;
2716: ts.regExpFlags = null;
2717: String re = ts.getString();
2718: decompiler.addRegexp(re, flags);
2719: int index = currentScriptOrFn.addRegexp(re, flags);
2720: // <netbeans>
2721: //return nf.createRegExp(index);
2722: // Regexp node processing doesn't use the match token calls,
2723: // it's character based, so I need to do manual arithmetic to
2724: // get the right results here rather than my usual
2725: // setSourceOffsets(node, startOffset) call
2726: Node rn = nf.createRegExp(index);
2727: int endOffset = matchedTokenEnd + re.length()
2728: + flags.length() + 1; // +1: closing /
2729: rn.setSourceBounds(startOffset, endOffset);
2730: matchedTokenEnd = endOffset;
2731: return rn;
2732: // </netbeans>
2733: }
2734:
2735: case Token.NULL:
2736: case Token.THIS:
2737: case Token.FALSE:
2738: case Token.TRUE:
2739: decompiler.addToken(tt);
2740: // <netbeans>
2741: //return nf.createLeaf(tt);
2742: return setSourceOffsets(nf.createLeaf(tt), startOffset);
2743: // </netbeans>
2744:
2745: case Token.RESERVED:
2746: reportError("msg.reserved.id");
2747: break;
2748:
2749: case Token.ERROR:
2750: /* the scanner or one of its subroutines reported the error. */
2751: break;
2752:
2753: case Token.EOF:
2754: reportError("msg.unexpected.eof");
2755: break;
2756:
2757: default:
2758: reportError("msg.syntax");
2759: break;
2760: }
2761: return null; // should never reach here
2762: }
2763:
2764: private void plainProperty(ObjArray elems, Object property)
2765: throws IOException {
2766: mustMatchToken(Token.COLON, "msg.no.colon.prop");
2767:
2768: // OBJLIT is used as ':' in object literal for
2769: // decompilation to solve spacing ambiguity.
2770: decompiler.addToken(Token.OBJECTLIT);
2771: elems.add(property);
2772: elems.add(assignExpr(false));
2773: }
2774:
2775: private boolean getterSetterProperty(ObjArray elems,
2776: Object property, boolean isGetter) throws IOException {
2777: Node f = function(FunctionNode.FUNCTION_EXPRESSION);
2778: if (f.getType() != Token.FUNCTION) {
2779: reportError("msg.bad.prop");
2780: return false;
2781: }
2782: int fnIndex = f.getExistingIntProp(Node.FUNCTION_PROP);
2783: FunctionNode fn = currentScriptOrFn.getFunctionNode(fnIndex);
2784: if (fn.getFunctionName().length() != 0) {
2785: reportError("msg.bad.prop");
2786: return false;
2787: }
2788: elems.add(property);
2789: if (isGetter) {
2790: elems.add(nf.createUnary(Token.GET, f));
2791: } else {
2792: elems.add(nf.createUnary(Token.SET, f));
2793: }
2794: return true;
2795: }
2796:
2797: // <netbeans>
2798: public TokenStream getTokenStream() {
2799: return ts;
2800: }
2801:
2802: public void setTokenStream(TokenStream ts) {
2803: this .ts = ts;
2804: }
2805:
2806: public ScriptOrFnNode parseJson(String sourceString,
2807: String sourceURI, int lineno) {
2808: this .sourceURI = sourceURI;
2809: this .ts = new TokenStream(this , null, sourceString, lineno);
2810: try {
2811: setJsonMode(true);
2812: return parseJson();
2813: } catch (IOException ex) {
2814: // Should never happen
2815: throw new IllegalStateException();
2816: }
2817: }
2818:
2819: private ScriptOrFnNode parseJson() throws IOException {
2820: assert jsonMode;
2821: this .decompiler = createDecompiler(compilerEnv);
2822: this .nf = new IRFactory(this );
2823: currentScriptOrFn = nf.createScript();
2824: int sourceStartOffset = decompiler.getCurrentOffset();
2825: // <netbeans>
2826: int realSourceStartOffset = ts.getBufferOffset();
2827: // </netbeans>
2828: this .encodedSource = null;
2829: decompiler.addToken(Token.SCRIPT);
2830:
2831: this .currentFlaggedToken = Token.EOF;
2832: this .syntaxErrorCount = 0;
2833:
2834: int baseLineno = ts.getLineno(); // line number where source starts
2835:
2836: /* so we have something to add nodes to until
2837: * we've collected all the source */
2838: Node pn = nf.createLeaf(Token.BLOCK);
2839:
2840: try {
2841: mustMatchToken(Token.LC, "msg.json.expectedlc");
2842: int startOffset = getStartOffset();
2843: ObjArray elems = new ObjArray();
2844: // <netbeans>
2845: List<Node> nameNodes = new ArrayList<Node>();
2846: // </netbeans>
2847: decompiler.addToken(Token.LC);
2848: if (!matchToken(Token.RC)) {
2849:
2850: boolean first = true;
2851: commaloop: do {
2852: Object property;
2853:
2854: if (!first)
2855: decompiler.addToken(Token.COMMA);
2856: else
2857: first = false;
2858:
2859: int tt = peekToken();
2860: switch (tt) {
2861: case Token.NAME:
2862: case Token.STRING:
2863: consumeToken();
2864: // map NAMEs to STRINGs in object literal context
2865: // but tell the decompiler the proper type
2866: String s = ts.getString();
2867: if (tt == Token.NAME) {
2868: if (s.equals("get")
2869: && peekToken() == Token.NAME) {
2870: decompiler.addToken(Token.GET);
2871: consumeToken();
2872: s = ts.getString();
2873: decompiler.addName(s);
2874: property = ScriptRuntime
2875: .getIndexObject(s);
2876: if (!getterSetterProperty(elems,
2877: property, true))
2878: break commaloop;
2879: break;
2880: } else if (s.equals("set")
2881: && peekToken() == Token.NAME) {
2882: decompiler.addToken(Token.SET);
2883: consumeToken();
2884: s = ts.getString();
2885: decompiler.addName(s);
2886: property = ScriptRuntime
2887: .getIndexObject(s);
2888: if (!getterSetterProperty(elems,
2889: property, false))
2890: break commaloop;
2891: break;
2892: }
2893: decompiler.addName(s);
2894: } else {
2895: decompiler.addString(s);
2896: }
2897: // <netbeans>
2898: int nameStart = matchedTokenStart;
2899: // </netbeans>
2900: property = ScriptRuntime.getIndexObject(s);
2901: plainProperty(elems, property);
2902: // <netbeans>
2903: if (elems.size() > 0) {
2904: Node rhs = (Node) elems
2905: .get(elems.size() - 1);
2906: Node objLitName = new Node.LabelledNode(s,
2907: rhs);
2908: objLitName.setSourceBounds(nameStart,
2909: nameStart + s.length());
2910: nameNodes.add(objLitName);
2911: }
2912: // </netbeans>
2913: break;
2914:
2915: case Token.NUMBER:
2916: consumeToken();
2917: double n = ts.getNumber();
2918: decompiler.addNumber(n);
2919: property = ScriptRuntime.getIndexObject(n);
2920: plainProperty(elems, property);
2921: break;
2922:
2923: case Token.RC:
2924: // trailing comma is OK.
2925: break commaloop;
2926: default:
2927: reportError("msg.bad.prop");
2928: break commaloop;
2929: }
2930: } while (matchToken(Token.COMMA));
2931:
2932: mustMatchToken(Token.RC, "msg.no.brace.prop");
2933: }
2934: decompiler.addToken(Token.RC);
2935: // <netbeans>
2936: //return nf.createObjectLiteral(elems);
2937: Node literal = nf.createObjectLiteral(elems);
2938: literal.setSourceBounds(startOffset, getEndOffset());
2939: for (Node n : nameNodes) {
2940: literal.addChildToBack(n);
2941: }
2942: pn.addChildToBack(literal);
2943: } catch (StackOverflowError ex) {
2944: String msg = ScriptRuntime
2945: .getMessage0("msg.too.deep.parser.recursion");
2946: throw Context.reportRuntimeError(msg, sourceURI, ts
2947: .getLineno(), null, 0);
2948: }
2949:
2950: if (this .syntaxErrorCount != 0) {
2951: String msg = String.valueOf(this .syntaxErrorCount);
2952: msg = ScriptRuntime.getMessage1("msg.got.syntax.errors",
2953: msg);
2954: // <netbeans>
2955: //throw errorReporter.runtimeError(msg, sourceURI, baseLineno,
2956: // null, 0);
2957: // Don't show an error for this at all!
2958: //EvaluatorException exc = errorReporter.runtimeError(msg, sourceURI, baseLineno,
2959: // null, 0);
2960: //if (exc != null) {
2961: // throw exc;
2962: //} else {
2963: // currentScriptOrFn.setSourceName(sourceURI);
2964: // currentScriptOrFn.setBaseLineno(baseLineno);
2965: // currentScriptOrFn.setEndLineno(ts.getLineno());
2966: //
2967: // return currentScriptOrFn;
2968: return null;
2969: //}
2970: // </netbeans>
2971: }
2972:
2973: currentScriptOrFn.setSourceName(sourceURI);
2974: currentScriptOrFn.setBaseLineno(baseLineno);
2975: currentScriptOrFn.setEndLineno(ts.getLineno());
2976:
2977: int sourceEndOffset = decompiler.getCurrentOffset();
2978: currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset,
2979: sourceEndOffset);
2980: // <netbeans>
2981: int realSourceEndOffset = getEndOffset();
2982: currentScriptOrFn.setSourceBounds(realSourceStartOffset,
2983: realSourceEndOffset);
2984: // </netbeans>
2985:
2986: nf.initScript(currentScriptOrFn, pn);
2987:
2988: if (compilerEnv.isGeneratingSource()) {
2989: encodedSource = decompiler.getEncodedSource();
2990: }
2991: this .decompiler = null; // It helps GC
2992:
2993: return currentScriptOrFn;
2994: }
2995: // </netbeans>
2996: }
|