📄 parser.java
字号:
break; } } else { n = statement(); } nf.addChildToBack(pn, n); } } catch (StackOverflowError ex) { String msg = ScriptRuntime.getMessage0( "msg.too.deep.parser.recursion"); throw Context.reportRuntimeError(msg, sourceURI, ts.getLineno(), null, 0); } if (this.syntaxErrorCount != 0) { String msg = String.valueOf(this.syntaxErrorCount); msg = ScriptRuntime.getMessage1("msg.got.syntax.errors", msg); throw errorReporter.runtimeError(msg, sourceURI, baseLineno, null, 0); } currentScriptOrFn.setSourceName(sourceURI); currentScriptOrFn.setBaseLineno(baseLineno); currentScriptOrFn.setEndLineno(ts.getLineno()); int sourceEndOffset = decompiler.getCurrentOffset(); currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset, sourceEndOffset); nf.initScript(currentScriptOrFn, pn); if (compilerEnv.isGeneratingSource()) { encodedSource = decompiler.getEncodedSource(); } this.decompiler = null; // It helps GC return currentScriptOrFn; } /* * The C version of this function takes an argument list, * which doesn't seem to be needed for tree generation... * it'd only be useful for checking argument hiding, which * I'm not doing anyway... */ private Node parseFunctionBody() throws IOException { ++nestingOfFunction; Node pn = nf.createBlock(ts.getLineno()); try { bodyLoop: for (;;) { Node n; int tt = peekToken(); switch (tt) { case Token.ERROR: case Token.EOF: case Token.RC: break bodyLoop; case Token.FUNCTION: consumeToken(); n = function(FunctionNode.FUNCTION_STATEMENT); break; default: n = statement(); break; } nf.addChildToBack(pn, n); } } catch (ParserException e) { // Ignore it } finally { --nestingOfFunction; } return pn; } private Node function(int functionType) throws IOException, ParserException { int syntheticType = functionType; int baseLineno = ts.getLineno(); // line number where source starts int functionSourceStart = decompiler.markFunctionStart(functionType); String name; Node memberExprNode = null; if (matchToken(Token.NAME)) { name = ts.getString(); decompiler.addName(name); if (!matchToken(Token.LP)) { if (compilerEnv.isAllowMemberExprAsFunctionName()) { // Extension to ECMA: if 'function <name>' does not follow // by '(', assume <name> starts memberExpr Node memberExprHead = nf.createName(name); name = ""; memberExprNode = memberExprTail(false, memberExprHead); } mustMatchToken(Token.LP, "msg.no.paren.parms"); } } else if (matchToken(Token.LP)) { // Anonymous function name = ""; } else { name = ""; if (compilerEnv.isAllowMemberExprAsFunctionName()) { // Note that memberExpr can not start with '(' like // in function (1+2).toString(), because 'function (' already // processed as anonymous function memberExprNode = memberExpr(false); } mustMatchToken(Token.LP, "msg.no.paren.parms"); } if (memberExprNode != null) { syntheticType = FunctionNode.FUNCTION_EXPRESSION; } if (syntheticType != FunctionNode.FUNCTION_EXPRESSION && name.length() > 0) { // Function statements define a symbol in the enclosing scope defineSymbol(Token.FUNCTION, name); } boolean nested = insideFunction(); FunctionNode fnNode = nf.createFunction(name); if (nested || nestingOfWith > 0) { // 1. Nested functions are not affected by the dynamic scope flag // as dynamic scope is already a parent of their scope. // 2. Functions defined under the with statement also immune to // this setup, in which case dynamic scope is ignored in favor // of with object. fnNode.itsIgnoreDynamicScope = true; } int functionIndex = currentScriptOrFn.addFunction(fnNode); int functionSourceEnd; ScriptOrFnNode savedScriptOrFn = currentScriptOrFn; currentScriptOrFn = fnNode; Node.Scope savedCurrentScope = currentScope; currentScope = fnNode; int savedNestingOfWith = nestingOfWith; nestingOfWith = 0; Hashtable savedLabelSet = labelSet; labelSet = null; ObjArray savedLoopSet = loopSet; loopSet = null; ObjArray savedLoopAndSwitchSet = loopAndSwitchSet; loopAndSwitchSet = null; boolean savedHasReturnValue = hasReturnValue; int savedFunctionEndFlags = endFlags; Node destructuring = null; Node body; try { decompiler.addToken(Token.LP); if (!matchToken(Token.RP)) { boolean first = true; do { if (!first) decompiler.addToken(Token.COMMA); first = false; int tt = peekToken(); if (tt == Token.LB || tt == Token.LC) { // Destructuring assignment for parameters: add a // dummy parameter name, and add a statement to the // body to initialize variables from the destructuring // assignment if (destructuring == null) { destructuring = new Node(Token.COMMA); } String parmName = currentScriptOrFn.getNextTempName(); defineSymbol(Token.LP, parmName); destructuring.addChildToBack( nf.createDestructuringAssignment(Token.VAR, primaryExpr(), nf.createName(parmName))); } else { mustMatchToken(Token.NAME, "msg.no.parm"); String s = ts.getString(); defineSymbol(Token.LP, s); decompiler.addName(s); } } while (matchToken(Token.COMMA)); mustMatchToken(Token.RP, "msg.no.paren.after.parms"); } decompiler.addToken(Token.RP); mustMatchToken(Token.LC, "msg.no.brace.body"); decompiler.addEOL(Token.LC); body = parseFunctionBody(); if (destructuring != null) { body.addChildToFront( new Node(Token.EXPR_VOID, destructuring, ts.getLineno())); } mustMatchToken(Token.RC, "msg.no.brace.after.body"); if (compilerEnv.isStrictMode() && !body.hasConsistentReturnUsage()) { String msg = name.length() > 0 ? "msg.no.return.value" : "msg.anon.no.return.value"; addStrictWarning(msg, name); } if (syntheticType == FunctionNode.FUNCTION_EXPRESSION && name.length() > 0 && currentScope.getSymbol(name) == null) { // Function expressions define a name only in the body of the // function, and only if not hidden by a parameter name defineSymbol(Token.FUNCTION, name); } decompiler.addToken(Token.RC); functionSourceEnd = decompiler.markFunctionEnd(functionSourceStart); if (functionType != FunctionNode.FUNCTION_EXPRESSION) { // Add EOL only if function is not part of expression // since it gets SEMI + EOL from Statement in that case decompiler.addToken(Token.EOL); } } finally { hasReturnValue = savedHasReturnValue; endFlags = savedFunctionEndFlags; loopAndSwitchSet = savedLoopAndSwitchSet; loopSet = savedLoopSet; labelSet = savedLabelSet; nestingOfWith = savedNestingOfWith; currentScriptOrFn = savedScriptOrFn; currentScope = savedCurrentScope; } fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd); fnNode.setSourceName(sourceURI); fnNode.setBaseLineno(baseLineno); fnNode.setEndLineno(ts.getLineno()); Node pn = nf.initFunction(fnNode, functionIndex, body, syntheticType); if (memberExprNode != null) { pn = nf.createAssignment(Token.ASSIGN, memberExprNode, pn); if (functionType != FunctionNode.FUNCTION_EXPRESSION) { // XXX check JScript behavior: should it be createExprStatement? pn = nf.createExprStatementNoReturn(pn, baseLineno); } } return pn; } private Node statements(Node scope) throws IOException { Node pn = scope != null ? scope : nf.createBlock(ts.getLineno()); int tt; while ((tt = peekToken()) > Token.EOF && tt != Token.RC) { nf.addChildToBack(pn, statement()); } return pn; } private Node condition() throws IOException, ParserException { mustMatchToken(Token.LP, "msg.no.paren.cond"); decompiler.addToken(Token.LP); Node pn = expr(false); mustMatchToken(Token.RP, "msg.no.paren.after.cond"); decompiler.addToken(Token.RP); // Report strict warning on code like "if (a = 7) ...". Suppress the // warning if the condition is parenthesized, like "if ((a = 7)) ...". if (pn.getProp(Node.PARENTHESIZED_PROP) == null && (pn.getType() == Token.SETNAME || pn.getType() == Token.SETPROP || pn.getType() == Token.SETELEM)) { addStrictWarning("msg.equal.as.assign", ""); } return pn; } // match a NAME; return null if no match. private Node matchJumpLabelName() throws IOException, ParserException { Node label = null; int tt = peekTokenOrEOL(); if (tt == Token.NAME) { consumeToken(); String name = ts.getString(); decompiler.addName(name); if (labelSet != null) { label = (Node)labelSet.get(name); } if (label == null) { reportError("msg.undef.label"); } } return label; } private Node statement() throws IOException { try { Node pn = statementHelper(null); if (pn != null) { if (compilerEnv.isStrictMode() && !pn.hasSideEffects()) addStrictWarning("msg.no.side.effects", ""); return pn; } } catch (ParserException e) { } // skip to end of statement int lineno = ts.getLineno(); guessingStatementEnd: for (;;) { int tt = peekTokenOrEOL(); consumeToken(); switch (tt) { case Token.ERROR: case Token.EOF: case Token.EOL: case Token.SEMI: break guessingStatementEnd; } } return nf.createExprStatement(nf.createName("error"), lineno); } private Node statementHelper(Node statementLabel) throws IOException, ParserException { Node pn = null; int tt = peekToken(); switch (tt) { case Token.IF: { consumeToken(); decompiler.addToken(Token.IF); int lineno = ts.getLineno(); Node cond = condition(); decompiler.addEOL(Token.LC); Node ifTrue = statement(); Node ifFalse = null; if (matchToken(Token.ELSE)) { decompiler.addToken(Token.RC); decompiler.addToken(Token.ELSE); decompiler.addEOL(Token.LC); ifFalse = statement(); } decompiler.addEOL(Token.RC); pn = nf.createIf(cond, ifTrue, ifFalse, lineno); return pn; } case Token.SWITCH: { consumeToken(); decompiler.addToken(Token.SWITCH); int lineno = ts.getLineno(); mustMatchToken(Token.LP, "msg.no.paren.switch"); decompiler.addToken(Token.LP); pn = enterSwitch(expr(false), lineno); try { mustMatchToken(Token.RP, "msg.no.paren.after.switch"); decompiler.addToken(Token.RP); mustMatchToken(Token.LC, "msg.no.brace.switch"); decompiler.addEOL(Token.LC); boolean hasDefault = false; switchLoop: for (;;) { tt = nextToken(); Node caseExpression; switch (tt) { case Token.RC: break switchLoop; case Token.CASE: decompiler.addToken(Token.CASE); caseExpression = expr(false); mustMatchToken(Token.COLON, "msg.no.colon.case"); decompiler.addEOL(Token.COLON); break; case Token.DEFAULT: if (hasDefault) { reportError("msg.double.switch.default"); } decompiler.addToken(Token.DEFAULT); hasDefault = true; caseExpression = null;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -